本人从事开发已经5年了,即做过android应用的开发,也搞过Framework层的开发,虽不敢说精通,但只要用到的基本也能说个大概。和同行业的人比也不知道自己处在一个什么样的水平。
随着移动互联网行业创业的寒冬和Android的热度消退,Android程序员的待遇也大不如前。在经过几次找工作面试的不如意,渐渐的产生转方向的想法。在面试过程中,主要得到几个启发.
1.之前的工作中接触的方向太广,在某些方面没有很深入的研究,这主要取决现在的公司太小,什么事都的做也杂,没有在一些领域过深的研究过。这直接导致自己的知识系统只在广的方面有所增长却没深度。
2.从2007年android出现以来到现在也近10个年头了,从事android的程序员从开始的巨大缺口到今日的严重饱和,也直接导致android开发岗位的工资大不如前。而且企业对android工程师的要求也大大提高,需要工程师在某些领域有更深的研究来开发性能更优,体验更好的产品,这也正是android程序员需求的一个从量来质的变化,而我却没有实现这个变化,导致自己的竞争力落后
3.在一个小公司待了4年之久,没有知名企业的工作经历也是很致命的。中小型公司在同等条件下总是希望招聘的员工有打大公司的工作经历
这是我从事android开发的最后一天,也是写关于android知识相关博客的最后一篇,也是我在待了4年公司的最后一天,下一份工作,我将改行从事java ee的开发,对这个选择我不知道是否正确,也不知道将来到底是android 和java ee哪个前景更好,毕竟路是自己选的,也没理由后悔。
说了这么多,回归主题。
大家都知道Android的内核是就是linux的内核,熟悉linux的人都知道,linux的文件属性是 9位 表示 ,前3位表示文件所属用户,中间3位表示文件所属组,后3位表示其他用户,例如 rwxr_x_ _ _ 表示750 的权限,表示所有者可读可写可执行,所属组可读不可写可执行,其他用户不可读不可写不可执行。文件属性的权限就介绍到这里。
而Permission权限是Android系统定义的一套权限机制,用 于控制APP访问某个硬件设备或某个android系统的组件。
举两个例子
1.如果你的App想要使用GPS地位,你需要在你的AndroidManifest文件中使用对应的权限定义用于向系统请求权限
2.你可以给你的Activity组件加个访问权限,这样任何想启动该Activity的程序必须在它的AndroidManifest中进行权限的请求
那么文件属性的权限和Permission到底是怎么联系起来的呢?为什么你在AndroidManifest文件请求权限你就可以使用GPS定位呢?下面我们来具体来讲。
我们都知道在linux中一切都是文件,所有的设备也同样是文件,既然是文件自然就是文件的属性,在Android中一些重要的设备文件和目录都在一个文件中定义了文件的属性
system/core/include/private/android_filesystem_config.h
在这个头文件中定义了android系统的一些用户,包含root用户,system用户,shell用户所对应的值等等。
#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 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_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 */
也定义了结构体的数组来映射数值所对应的字符串
struct android_id_info {
const char *name;
unsigned aid;
};
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, },
{ "sdcard_pics", AID_SDCARD_PICS, },
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_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, },
{ "misc", AID_MISC, },
{ "nvram", AID_NVRAM,},
{ "nobody", AID_NOBODY, },
{ "ccci", AID_CCCI, },
};
所以你通过adb 工具去查看某些文件的时候都是看到类似 root ,system sdcard_r等用户。
定义完用户名和数值后就该定义目录和文件的所属用户,所属用户组,和其他用户了。
struct fs_path_config {
unsigned mode;
unsigned uid;
unsigned gid;
uint64_t capabilities;
const char *prefix;
};
/* Rules for directories.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root.
*/
static const struct fs_path_config android_dirs[] = {
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/dalvik-cache" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" },
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local" },
{ 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" },
{ 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
};
/* Rules for files.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root. Prefixes ending in * denotes wildcard
** and will allow partial matches.
*/
static const struct fs_path_config android_files[] = {
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" },
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.trout.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.testmenu" },
{ 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00550, AID_DHCP, AID_SHELL, 0, "system/etc/wide-dhcpv6/dhcp6c.script" },
{ 00444, AID_RADIO, AID_AUDIO, 0, "system/etc/AudioPara4.csv" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/bin/ping" },
/* the following file is INTENTIONALLY set-gid and not set-uid.
* Do not change. */
{ 02750, AID_ROOT, AID_INET, 0, "system/bin/netcfg" },
/* the following five files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/su" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/xbin/tcpdump" },
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "charger*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
这也弄明白了为什么我们经常通过adb工具去查看data目录提示无权限。因为adb在没root的情况下默认是shell用户,而data目录定义的文件属性是
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
用户和用户组都是system用户才拥有读写的权限,而其他用户无读写的权限。
接下来我们来讲讲Permission,在讲Permission之前我们要讲一个非常重要的系统服务PMS。frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
这个服务在SystemServer进程中实例化,具体SysetmServer是什么,他的重要性我在这就不细讲了,不是我们今天的主题。PackageManagerService.java我就简称PMS了,PMS在启动后做的一件很重要的事就是扫描所有已经安装好的应用程序,然后加载和解析他们的Androidmanifest文件,这样就得到应用程序所有的配置信息,其中就包括Permission,之后PMS会将各个Permission加入到一个集合中去,但是在之前PMS会做一个权限拦截的工作。
frameworks/base/core/res/AndroidManifest.xml
在这个文件中定义了Permission拦截规则
<permission android:name="android.permission.CARRIER_FILTER_SMS"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="signature|system" />
<permission android:name="android.permission.RECEIVE_MMS"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="dangerous"
android:label="@string/permlab_receiveMms"
android:description="@string/permdesc_receiveMms" />
上面举了两个例子,这里重点看android:protectionLevel=”dangerous” 和android:protectionLevel=”signature|system” ,这是什么意思呢?
protectionLevel共有5个选项值分别为signature,system,dangerous,normal,development。
简单介绍下这5个值
signature: 表示如果想获取该权限必须为系统平台签名
system: 表示如果想获取该权限必须为系统应用
剩下3个普通应用程序都能获取该权限
例如:你在你的app中请求了一个权限而这个权限定义的拦截规则是signature|system 这个级别的,如果此时你的app没有作为系统应用和用系统平台签名工具签名的话,PMS会将你所请求的该Permission从集合中移除,也就说明你的app实际是不存在该Permission的,也就无法得到其权限了
接下来是该文的重点,文件属性的权限是怎么和Permission联系起来的。
同样有一个关键文件的定义:
frameworks/base/data/etc/platform.xml
这个文件定义了Permission所能加入的组,即gid。
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
<permission name="android.permission.ACCESS_MTK_MMHW" >
<group gid="media" />
<group gid="camera" />
</permission>
<permission name="android.permission.READ_LOGS" >
<group gid="log" />
</permission>
<permission name="android.permission.READ_EXTERNAL_STORAGE" >
<group gid="sdcard_r" />
</permission>
发现没有,就是博客开头的头文件所定义的用户名。
我们再回到PMS,PMS在解析每个Permission是会根据这个文件将Permission所能联系的gid 加入到一个gid的数组中去,换句话说,如果你的应用程序请求了某个Permission的话,系统在该app启动时 ,将app的进程加入到gid数组所对应的组中。从而硬件设备所对应的设备文件就能被该应用程序访问
在ActivityManagerService.java简称AMS,在AMS中的方法startProcessLocked开启一个新的进程
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
参数列表的gids就是app所请求Permission关联的文件所属组
下面我们再举个例子来贯穿下整个流程 ,我们在写sdcard的时候会在app中加入
<permission name="android.permission.READ_EXTERNAL_STORAGE" >
而该Permission所关联的gid是sdcard_r,这样的app进程就加入的sdcard_r组,
adb工具查看sdcard目录下的文件属性
drwxrwx--- root sdcard_r
只有root用户和sdcard_r组才有读写执行的权限。由此可以证明在app中加入相应的Permission确实获取了对应组的权限,也证实了Android文件属性的权限和Permission的联系
本博客只是本人对android权限的理解,如果有哪里讲解不正确,还望读到本博客的大神指出,定会虚心改正 !!!!!!