android探索之UID u0_axxx的由来
通过PackageManager的学习,我们知道,android的UID和linux的UID根本是两回事,Linux的UID是用于针对多用户操作系统中用于区分用户的。而Android中的UID是用于系统进行权限管理的,相信大家在shell环境中进行ps命令查询的时候,屏幕都会输出如下的信息,那么,对于输出信息中的USER一栏中具体的system,radio,u0_a1(CanlendarProvider),u0_a27(deskClock)等等这就是我们今天的主人公UID,奇怪的就是之前我们理解的uid都是有正整数来表示,为毛这里是字串的形式,uid是整数这点毋庸置疑,会出现字串的情况应该是有一个一一对应的关系。
为了探索这个对应关系,今天我们就以此为例,探索下这些UID的具体由来。
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a42 1971 597 1443692 35452 SyS_epoll_ 7f7dca9ba4 S com.android.printspooler
u0_a24 2003 597 1440292 33136 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qti.accesscache
u0_a50 2110 597 1440316 32912 SyS_epoll_ 7f7dca9ba4 S com.android.smspush
system 2127 597 1470876 37476 SyS_epoll_ 7f7dca9ba4 S com.android.settings
radio 2140 597 1442476 43824 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qcrilmsgtunnel
system 2212 597 1444100 35500 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.telephony
system 2286 597 1442632 34892 SyS_epoll_ 7f7dca9ba4 S com.qti.diagservices
system 2301 597 1440236 34528 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qti.qs
u0_a1 2318 597 1443108 39640 SyS_epoll_ 7f7dca9ba4 S com.android.providers.calendar
u0_a8 2335 597 1442188 34216 SyS_epoll_ 7f7dca9ba4 S com.android.managedprovisioning
u0_a9 2351 597 1440216 33492 SyS_epoll_ 7f7dca9ba4 S com.android.onetimeinitializer
u0_a20 2368 597 1440176 32664 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qti.calendarlocalaccount
u0_a26 2381 597 1440680 33512 SyS_epoll_ 7f7dca9ba4 S com.qti.csk
u0_a27 2394 597 1448988 40792 SyS_epoll_ 7f7dca9ba4 S com.android.deskclock
首先,通过对于android系统的了解,由于android进程是由zygote进程孵化而来,因此通过zygote的fork流程,我们可以断定,这个字符串并非在这里生成的。如下简要列出zygote孵化的重要部分:
最终在fork的子进程中通过系统调用setresgid和setresuid对当前的进程uid和gid进行了设置,但是这里仍然是数字。无法确认整数和字符的对应关系。所以并非是zygote对其进行了映射转换。
接着我们看第二个方向,由于这些信息终是由ps命令而输出,而这里的ps命令又与原生linux中的ps命令不同,android中源码中,具体的实现代码在/system/core/toolbox/ps.c中,其对应的函数为ps_line方法。
static int ps_line(int pid, int tid, char *namefilter)
{// 略去无关代码pw = getpwuid(stats.st_uid);if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {sprintf(user,"%d",(int)stats.st_uid);} else {strcpy(user,pw->pw_name);}// 略去无关代码
}
这个方法体很长,我们只关注重点部分,getpwuid即是我们要获取UID的方法了。这里需要注意,这个方法是在libc(android实现的轻量级c库boinic)中,路径bionic/libc/bionic/stubs.c
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.passwd_state_t* state = g_passwd_tls_buffer.get();if (state == NULL) {return NULL;}passwd* pw = android_id_to_passwd(state, uid);if (pw != NULL) {return pw;}return app_id_to_passwd(uid, state);
}
这里首先通过传入的uid通过android_id_to_passwd方法去查找,如果有查到,便直接返回了。这里我插一下,这个uid啊,是由userid+appid得来的, 而userid即为我们android的用户id,appid即PKMS在apk安装的时候给每个应用分配的,想要了解PKMS是怎样给安装的应用程序分配uid的同学请戳如下文章深入了解:
Android M PackageManagerService 启动过程分析
Android M PackageManager对于应用程序apk的安装流程分析
我们跟进android_id_to_passwd方法。
static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {for (size_t n = 0; n < android_id_count; ++n) {if (android_ids[n].aid == id) {return android_iinfo_to_passwd(state, android_ids + n);}}return NULL;
}
android_id_passwd的情况是通过查询一个android_ids的数组,其中定义了各个特殊uid和字符串的对应关系,如system root shell等系统级别的,定义在文件/system/core/include/private/android_filesystem_config.h当中的,看一下,是不是似曾相识?
#define AID_ROOT 0 /* traditional unix root user */#define AID_SYSTEM 1000 /* system server */#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources *//* The range 2900-2999 is reserved for OEM, and must never be* used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999/* The 3000 series are intended for use as supplemental group id's only.* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
#define AID_QCOM_DIAG 3009 /* can read/write /dev/diag */#define AID_SENSORS 3011 /* access to /dev/socket/sensor_ctl_socket & QCCI/QCSI */#define AID_RFS 3012 /* Remote Filesystem for peripheral processors */
#define AID_RFS_SHARED 3013 /* Shared files for Remote Filesystem for peripheral processors */#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999#define AID_APP 10000 /* first app user */#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */#define AID_USER 100000 /* offset for uid ranges for each user */#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */static const struct android_id_info android_ids[] = {{ "root", AID_ROOT, },{ "system", AID_SYSTEM, },{ "radio", AID_RADIO, },{ "bluetooth", AID_BLUETOOTH, },{ "graphics", AID_GRAPHICS, },{ "input", AID_INPUT, },{ "audio", AID_AUDIO, },{ "camera", AID_CAMERA, },{ "log", AID_LOG, },{ "compass", AID_COMPASS, },{ "mount", AID_MOUNT, },{ "wifi", AID_WIFI, },{ "adb", AID_ADB, },{ "install", AID_INSTALL, },{ "media", AID_MEDIA, },{ "dhcp", AID_DHCP, },{ "sdcard_rw", AID_SDCARD_RW, },{ "vpn", AID_VPN, },{ "keystore", AID_KEYSTORE, },{ "usb", AID_USB, },{ "drm", AID_DRM, },{ "mdnsr", AID_MDNSR, },{ "gps", AID_GPS, },// AID_UNUSED1{ "media_rw", AID_MEDIA_RW, },{ "mtp", AID_MTP, },// AID_UNUSED2{ "drmrpc", AID_DRMRPC, },{ "nfc", AID_NFC, },{ "sdcard_r", AID_SDCARD_R, },{ "clat", AID_CLAT, },{ "loop_radio", AID_LOOP_RADIO, },{ "mediadrm", AID_MEDIA_DRM, },{ "package_info", AID_PACKAGE_INFO, },{ "shared_relro", AID_SHARED_RELRO, },{ "shell", AID_SHELL, },{ "cache", AID_CACHE, },{ "diag", AID_DIAG, },{ "qcom_diag", AID_QCOM_DIAG, },{ "net_bt_admin", AID_NET_BT_ADMIN, },{ "net_bt", AID_NET_BT, },{ "inet", AID_INET, },{ "net_raw", AID_NET_RAW, },{ "net_admin", AID_NET_ADMIN, },{ "net_bw_stats", AID_NET_BW_STATS, },{ "net_bw_acct", AID_NET_BW_ACCT, },{ "net_bt_stack", AID_NET_BT_STACK, },{ "sensors", AID_SENSORS, },{ "rfs", AID_RFS, },{ "rfs_shared", AID_RFS_SHARED, },{ "everybody", AID_EVERYBODY, },{ "misc", AID_MISC, },{ "nobody", AID_NOBODY, },
};
这里就很清楚了,那些系统级别的uid对应的字符串都是在这里定义的,比如我们开篇提到的system,radio等等,而普通的应用呢则不是在这里匹配得到,方法自然会返回null,那么就会进入后面的流程 app_id_to_passwd。
#define AID_USER 100000 /* offset for uid ranges for each user */
#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_APP 10000 // Translate a uid into the corresponding name.
// 0 to AID_APP-1 -> "system", "radio", etc.
// AID_APP to AID_ISOLATED_START-1 -> u0_a1234
// AID_ISOLATED_START to AID_USER-1 -> u0_i1234
// AID_USER+ -> u1_radio, u1_a1234, u2_i1234, etc.
// returns a passwd structure (sets errno to ENOENT on failure).
static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {if (uid < AID_APP) {errno = ENOENT;return NULL;}print_app_name_from_uid(uid, state->name_buffer_, sizeof(state->name_buffer_));const uid_t appid = uid % AID_USER;if (appid < AID_APP) {snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");} else {snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");}snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");passwd* pw = &state->passwd_;pw->pw_name = state->name_buffer_;pw->pw_dir = state->dir_buffer_;pw->pw_shell = state->sh_buffer_;pw->pw_uid = uid;pw->pw_gid = uid;return pw;
}static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) {const uid_t appid = uid % AID_USER;const uid_t userid = uid / AID_USER;if (appid >= AID_ISOLATED_START) {snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);} else if (appid < AID_APP) {for (size_t n = 0; n < android_id_count; n++) {if (android_ids[n].aid == appid) {snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);return;}}} else {snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);}
}
看到这个方法后,我们不禁恍然大悟啊,通过上面的宏定义以及计算方法,我们不难得出:
- app的uid/100000的结果为userid,填到ux的x处。
- app的uid减去10000为appid,填到axx的xx处。
- 例如某个app的uid是10022,经过计算,userid为10022/100000=0,appid为10022-10000=22,则那么最终通过ps打印得到uid字串就是u0_a22
那么这个useid在系统中哪里可以查到呢?当然是在pkms中啦 ,比如在packages.list中就会有哦。
com.gd.mobicore.pa 10047 0 /data/data/com.gd.mobicore.pa platform 3003
com.qualcomm.qti.auth.sampleextauthservice 10049 0 /data/data/com.qualcomm.qti.auth.sampleextauthservice platform none
com.cootek.smartinputv5.language.indonesian 10062 0 /data/data/com.cootek.smartinputv5.language.indonesian default none
com.qrd.omadownload 10036 0 /data/data/com.qrd.omadownload platform 3003
com.cootek.smartinputv5.language.vietnam 10072 0 /data/data/com.cootek.smartinputv5.language.vietnam default none
com.android.providers.telephony 1001 0 /data/data/com.android.providers.telephony platform 2001,1005,3002,1023,1015,3003,3001,3009,3006
com.cootek.smartinputv5.language.cangjie 10059 0 /data/data/com.cootek.smartinputv5.language.cangjie default none
com.android.providers.calendar 10001 0 /data/data/com.android.providers.calendar default 3003
com.android.providers.media 10006 0 /data/data/com.android.providers.media default 2001,1023,1015,3003,1024,3007
com.qti.service.colorservice 1000 0 /data/data/com.qti.service.colorservice platform 2001,3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,3009,1010
com.qualcomm.shutdownlistner 10053 0 /data/data/com.qualcomm.shutdownlistner platform none
com.android.wallpapercropper 10016 0 /data/data/com.android.wallpapercropper platform none
com.quicinc.cne.CNEService 1000 0 /data/data/com.quicinc.cne.CNEService platform 2001,3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,3009,1010
com.android.protips 10043 0 /data/data/com.android.protips default none
com.qualcomm.qti.phonefeature 1001 0 /data/data/com.qualcomm.qti.phonefeature platform 2001,1005,3002,1023,1015,3003,3001,3009,3006
com.cootek.smartinputv5.language.marathi 10063 0 /data/data/com.cootek.smartinputv5.language.marathi default none
org.simalliance.openmobileapi.service 1000 0 /data/data/org.simalliance.openmobileapi.service platform 2001,3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,3009,1010
com.android.documentsui 10028 0 /data/data/com.android.documentsui platform none
com.android.externalstorage 10007 0 /data/data/com.android.externalstorage platform 1023,1015
com.cootek.smartinputv5.language.spanishlatin 10066 0 /data/data/com.cootek.smartinputv5.language.spanishlatin default none
com.qualcomm.uimremoteclient 1001 0 /data/data/com.qualcomm.uimremoteclient platform 2001,1005,3002,1023,1015,3003,3001,3009,3006
com.android.htmlviewer 10030 0 /data/data/com.android.htmlviewer default none
com.qualcomm.ftm 10029 0 /data/data/com.qualcomm.ftm platform none
com.qualcomm.sta 1000 0 /data/data/com.qualcomm.sta platform 2001,3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,3009,1010
com.qualcomm.svi 1000 0 /data/data/com.qualcomm.svi platform 2001,3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,3009,1010
com.android.deskclock 10027 0 /data/data/com.android.deskclock platform none
上面的第二列即是每个app对应的uid了,我们可以看到,canlendarprovider的uid为10001,而deskclock的是10027,那么经过计算,我们得到的USER分别为u0_a1, u0_a27。
可能有些人会问:博主,看你打印都是u0_axx,那有些u10_axx中是u10是怎么回事,我看到过的哦。
/*** @hide Range of uids allocated for a user.*/public static final int PER_USER_RANGE = 100000;public static final int getUid(int userId, int appId) {if (MU_ENABLED) {return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);} else {return appId;}}
很简单,u10_axx就是多用户下的进程了,我们打开多用户开关,切换到访客模式或者通过新建user的方式,完成后进行ps一下,输出如下:
// ps输出 访客模式
u0_a34 13056 597 1440200 32780 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qti.lunarinfo
system 13069 597 1440288 33880 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.timeservice
u10_a42 32319 597 1443772 35444 SyS_epoll_ 7f7dca9ba4 S com.android.printspooler
u10_a8 32341 597 1442188 33064 SyS_epoll_ 7f7dca9ba4 S com.android.managedprovisioning
u10_system 32355 597 1470876 36316 SyS_epoll_ 7f7dca9ba4 S com.android.settings
u10_radio 32388 597 1440252 32800 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.qcrilmsgtunnel
u10_a44 32406 597 1440248 35280 SyS_epoll_ 7f7dca9ba4 S com.android.provision
u10_a14 32419 597 1453712 44656 SyS_epoll_ 7f7dca9ba4 S com.android.systemui
u10_system 32434 597 1448136 37004 SyS_epoll_ 7f7dca9ba4 S com.qualcomm.location.XT
system 32492 1 14332 3832 hrtimer_na 7f964c9594 S /system/bin/ATFWD-daemon// 新建user 11
u11_system 3022 591 1440164 33184 SyS_epoll_ 7f96147ba4 S com.qualcomm.qti.notificationservice
u11_a37 3035 591 1447512 35676 SyS_epoll_ 7f96147ba4 S com.oma.drm
u11_radio 3050 591 1451772 39164 SyS_epoll_ 7f96147ba4 S com.android.phone
u11_a45 3063 594 878888 36016 SyS_epoll_ 00f7427c64 S com.qti.smq.qualcommFeedback
u11_system 3077 591 1441432 34276 SyS_epoll_ 7f96147ba4 S com.qualcomm.qti.GBAHttpAuthentication.auth
u11_a46 3096 591 1440756 33672 SyS_epoll_ 7f96147ba4 S com.qualcomm.qti.telephonyservice
u11_system 3114 591 1441200 34632 SyS_epoll_ 7f96147ba4 S com.qualcomm.qualcommsettings
u11_radio 3128 591 1442344 34000 SyS_epoll_ 7f96147ba4 S com.qualcomm.qti.rcsbootstraputil
u11_system 3143 591 1441420 34084 SyS_epoll_ 7f96147ba4 S com.qualcomm.telephony
是不是很神奇?
android探索之UID u0_axxx的由来相关推荐
- Android探索之旅 | 面向对象和Java基础
-- 作者 谢恩铭 转载请注明出处 上一篇 Android探索之旅 | Android简介 中说到: "Android的默认开发语言是Java,入门简单.而且,你的Java水平不需要多好就可 ...
- 【Android探索】基于OpenCV的微液滴粒径分析APP
前言:这个App是之前<数字图像处理>课程的一次课程设计中的产物,现在整理一下记录下来,里面涉及到了比较多的控件以及拓展包,功能不是很丰富但是也比较算齐全,其中使用的技术原理包括在安卓上使 ...
- Android系统中UID
Android系统中修改了Linux的UID的含义.由于Android是单用户系统,不需要支持多用户登陆,因此传统的UID系统就失去了原来的意义.Android的开发者巧妙地修改了UID的含义:每个A ...
- Android探索之旅 | AIDL原理和实例讲解
前言 为使应用程序之间能够彼此通信,Android提供了IPC (Inter Process Communication,进程间通信)的一种独特实现: AIDL (Android Interface ...
- Android探索之旅 | 为应用添加角标(Badge)
-- 作者 谢恩铭 转载请注明出处 内容简介 需求简介 Android角标起源 不错的Github项目 清除角标 小问题纠错 总结 1.需求简介 角标是什么意思呢? 看下图即可明了: 可以看到图中的乐 ...
- android 无法添加帐户,android - Android SecurityException:uid xxxxx无法显式添加帐户 - 堆栈内存溢出...
我收到错误消息 java.lang.SecurityException: uid 10178 cannot explicitly add accounts of type: net.roughdesi ...
- android NFC读取UID
1.在清单文件中添加所需要的权限 <uses-sdk android:minSdkVersion="8" /> <uses-permission android: ...
- android探索宇宙app,AR研学星系探索app
AR研学星系探索app是一款为喜欢探索宇宙的用户们提供的关于八大行星学习的软件:通过VR虚拟的形式让用户可以更加直观地了解到我们的地球和我们的浩瀚的宇宙,来启发用户对宇宙的探索和好奇.这款软件会为用户 ...
- 【Android探索】基于Android Studio平台的蓝牙遥控APP
前言:好久没更新这博客了,接下来有时间记录下前阵子做的东西,当作是复习之余的回顾往事和时间消遣,哈哈.首先是这个蓝牙遥控APP,这个APP是之前做一个小比赛的时候尝试做来玩玩的,主要内容是使用这个AP ...
- Android 探索增量升级
一.介绍 Android 的增量升级,不同热修复和热更新,它只是通过和老的 apk 对比,识别出与新 apk 之间的二进制差异,从而生成的补丁包(差量包): 这样的好处在于,不用全部下载所有的文件,比 ...
最新文章
- Python之父:Python 4.0可能不会来了
- 基于深度法向约束的稀疏雷达数据深度补全(商汤科技和香港大学联合提出)
- 华人小哥控诉机器学习「四大Boring」,CS博士:深有同感,正打算退学
- 一个.net的系统的AOP设计思路二——页面控件校验映射
- booloader编写
- BellmanFord
- BZOJ 1877 拆点费用流
- 计算区域中有t 个点的 区域有多少个+计算几何 + 叉乘+sort+ 二分 + map poj 2398 Toy Storage...
- SIP学习之网络链接
- Java静态变量,常量,成员变量,局部变量
- 机器学习之数据预处理——降噪
- 对_stdcall 的理解 (转)
- VS2017生成可执行程序,执行提示“不是有效的win32应用程序”
- C语言#define宏中省略号的含义?
- 3w 字长文爆肝 Java 基础面试题!太顶了!!!
- java程序报stream has already been operated upon or closed异常错误解决方案
- 计算机开机选择用户界面,Windows10每次开机都会出现选择操作系统界面的解决方法...
- 程序化交易策略系统的构成
- 大家在人生低谷时有多惨,怎么熬过来的(二)
- Android中layout-sw600dp、layout-w600dp和layout-h600dp的区别
热门文章
- 杭州电子科技大学计算机网络考研,2017杭州电子科技大学计算机网络考研大纲...
- 深入分析AIL语言及init.rc文件
- canvas 填充圆内正方形
- 使用C语言编写craps骰子游戏,Python实现国外赌场热门游戏Craps(双骰子)
- Linux C语言实现SYN包泛洪攻击
- Powershell————2、Powershell交互式
- 做webgl遇到的两个坑
- 简述autocad在测绘工程中的应用_AutoCAD在工程测绘制图中的应用
- 天秀,Excel居然还可以制作二维码
- 微信隐藏功能系列:微信朋友圈三天可见怎么设置?