[Framework] 全方位理解Android权限之底层实现概览

栏目: IOS · Android · 发布时间: 5年前

内容简介:这个阶段搞了很多和Android文件权限相关的问题,虽然一知半解,但也算是对Android权限机制有一些自己的理解。遂将这些内容整理出来。因为权限这部分涉及到的内容很多,故将知识分为几块内容分别去整理。目前能想到的概要如下:这是第一篇。2,3,4已经有一些草稿了,但离发出来还有一些时间。5,6,7还在规划中。可以关注新弄的公众号softard,后面比较完善的文章都会在这个号上及时更新。这里再推荐一本书

这个阶段搞了很多和Android文件权限相关的问题,虽然一知半解,但也算是对Android权限机制有一些自己的理解。遂将这些内容整理出来。因为权限这部分涉及到的内容很多,故将知识分为几块内容分别去整理。目前能想到的概要如下:

  1. Android 权限底层实现原理概述
  2. Android uid,gid的生成与权限机制的联系
  3. Android packageManagerService与权限的千丝万缕(源码解析)
  4. Android 从recovery模式下的OTA升级理解权限
  5. Android ROOT 原理
  6. Android 签名
  7. Android 权限大杀器 — Selinux的策略

这是第一篇。2,3,4已经有一些草稿了,但离发出来还有一些时间。5,6,7还在规划中。可以关注新弄的公众号softard,后面比较完善的文章都会在这个号上及时更新。

这里再推荐一本书 ,这也是查资料找到的一本宝贝,非常牛逼。

0001 Overview

Linux File Permission

众所周知,Android的内核是 linux 的内核。对于linux来说,系统的一切都是文件。同时,linux为文件系统设计了一套完善的权限机制。下面简单提一下linux文件权限的核心:

比如在Android手机adb shell下查看一个目录

# ls -ld data/data/
drwxrwx--x 113 system system 4096 1970-01-01 15:08 data/data/

其中, drwxrwx--x 这10位代表文件权限,第一位文件类型可以忽略(这里类型是文件夹),后面每三位代表文件拥有的权限,包括rwx(可读,可写,可执行)。 system system 表示文件属于system用户和属于system组。

翻译过来是,system用户对该文件拥有读写执行权限,system组对该文件拥有读写执行权限,其他用户对该文件拥有执行权限。简单来说就是771权限。

Android Permission

Permission权限是Android系统定义的一套权限机制,用于控制APP访问某个硬件设备或某个Android系统的组件。

举两个常见的例子:

  1. 如果你的App想要访问存储卡,你需要在你的AndroidManifest文件中使用对应的permission用于向系统请求权限 。
  2. 你可以给你的Activity组件加个自定义的访问权限,这样任何想启动该Activity的程序必须在它的AndroidManifest中进行权限的请求。见 Android自定义权限

那么为什么你在AndroidManifest文件请求storage权限你就可以访问设备文件?linux文件属性的权限和Permission到底是怎么联系起来的呢?下面我们来具体来讲。

0010 packages.list & packages.xml

Android开机阶段会扫描所有App,从Manifest文件中把App信息和权限存到 packages.xmlpackages.list 文件中,具体的处理过程会在后面第三篇去分析。

因为文件包含所有已安装应用的信息,所以我们尝试安装一个App(com.softard.test),并且查看其信息:

packages.list

com.softard.test 10052 1 /data/user/0/com.softard.test default none

这里10052是uid,至于其怎么生成的后面第二篇再详谈。

packages.xml

<package name="com.softard.test" codePath="/data/app/com.softard.test-1" nativeLibraryPath="/data/app/com.softard.test-1/lib" publicFlags="944291654" privateFlags="0" ft="8bbd70" it="89023c" ut="8bc04d" version="1" userId="10052">
        <sigs count="1">
            <cert index="10" key="308..../>
        </sigs>
        <proper-signing-keyset identifier="11" />
    </package>

然后对App做个修改,将其改成系统App并签名放到 system/app/Test 下,再看这两个文件:

com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007

看到uid变成了1000,selinux从default变成platform,权限组从none变成3009,3002,1023,1015,3003,3001,1021,1000,2002,2950,1010,1007。而且应用一下子增加了一堆权限:

<package name="com.softard.test" codePath="/system/app/Test" nativeLibraryPath="/system/app/Test/lib" primaryCpuAbi="armeabi-v7a" publicFlags="944291397" privateFlags="0" ft="1683b80c790" it="1683b80c790" ut="1683b80c790" version="1" sharedUserId="1000" isOrphaned="true">
       <sigs count="1">
           <cert index="0" />
       </sigs>
       <perms>
           <item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />
           <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.CONFIGURE_WIFI_DISPLAY" granted="true" flags="0" />
           <item name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" granted="true" flags="0" />
           <item name="android.permission.ACCESS_WIMAX_STATE" granted="true" flags="0" />
           <item name="android.permission.RECOVERY" granted="true" flags="0" />
           <item name="com.qualcomm.permission.READPROC" granted="true" flags="0" />
           <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
           <item name="android.permission.MODIFY_AUDIO_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.ACCESS_CHECKIN_PROPERTIES" granted="true" flags="0" />
           <item name="com.zqautomotive.oris.wechat.provider.WRITE" granted="true" flags="0" />
           <item name="android.permission.INSTALL_LOCATION_PROVIDER" granted="true" flags="0" />
           <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
           <item name="android.permission.SYSTEM_ALERT_WINDOW" granted="true" flags="0" />
           <item name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION" granted="true" flags="0" />
           <item name="android.permission.CONTROL_LOCATION_UPDATES" granted="true" flags="0" />
           <item name="android.permission.CLEAR_APP_USER_DATA" granted="true" flags="0" />
           <item name="com.zqautomotive.oris.wechat.provider.READ" granted="true" flags="0" />
           <item name="android.permission.BROADCAST_CALLLOG_INFO" granted="true" flags="0" />
           <item name="android.permission.NFC" granted="true" flags="0" />
           <item name="android.permission.CALL_PRIVILEGED" granted="true" flags="0" />
           <item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
           <item name="android.permission.MASTER_CLEAR" granted="true" flags="0" />
           <item name="android.permission.WRITE_SYNC_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
           <item name="android.permission.PEERS_MAC_ADDRESS" granted="true" flags="0" />
           <item name="android.permission.DEVICE_POWER" granted="true" flags="0" />
           <item name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" granted="true" flags="0" />
           <item name="android.permission.READ_PROFILE" granted="true" flags="0" />
           <item name="android.permission.BLUETOOTH" granted="true" flags="0" />
           <item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />
           <item name="android.permission.WRITE_BLOCKED_NUMBERS" granted="true" flags="0" />
           <item name="com.qualcomm.permission.USE_QCRIL_MSG_TUNNEL" granted="true" flags="0" />
           <item name="android.permission.ACCESS_SURFACE_FLINGER" granted="true" flags="0" />
           <item name="com.zqautomotive.voice_controller.GET_SPEECH_RESULT" granted="true" flags="0" />
           <item name="android.permission.AUTHENTICATE_ACCOUNTS" granted="true" flags="0" />
           <item name="android.permission.INTERNET" granted="true" flags="0" />
           <item name="android.permission.REORDER_TASKS" granted="true" flags="0" />
           <item name="zq.permissio.CONNECTION_MQTT_SERVICE" granted="true" flags="0" />
           <item name="android.permission.BLUETOOTH_ADMIN" granted="true" flags="0" />
           <item name="android.permission.CONTROL_VPN" granted="true" flags="0" />
           <item name="android.permission.UPDATE_DEVICE_STATS" granted="true" flags="0" />
           <item name="android.permission.MANAGE_FINGERPRINT" granted="true" flags="0" />
           <item name="com.qualcomm.permission.IZAT" granted="true" flags="0" />
           <item name="android.permission.BIND_CONNECTION_SERVICE" granted="true" flags="0" />
           <item name="android.permission.MANAGE_USB" granted="true" flags="0" />
           <item name="android.permission.INTERACT_ACROSS_USERS_FULL" granted="true" flags="0" />
           <item name="android.permission.STOP_APP_SWITCHES" granted="true" flags="0" />
           <item name="android.permission.BATTERY_STATS" granted="true" flags="0" />
           <item name="android.permission.PACKAGE_USAGE_STATS" granted="true" flags="0" />
           <item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" granted="true" flags="0" />
           <item name="android.permission.TETHER_PRIVILEGED" granted="true" flags="0" />
           <item name="android.permission.WRITE_SECURE_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.MOVE_PACKAGE" granted="true" flags="0" />
           <item name="android.permission.READ_BLOCKED_NUMBERS" granted="true" flags="0" />
           <item name="com.qualcomm.permission.wfd.QC_WFD" granted="true" flags="0" />
           <item name="android.permission.READ_SEARCH_INDEXABLES" granted="true" flags="0" />
           <item name="android.permission.ACCESS_IMS_CALL_SERVICE" granted="true" flags="0" />
           <item name="android.permission.BLUETOOTH_PRIVILEGED" granted="true" flags="0" />
           <item name="android.permission.HARDWARE_TEST" granted="true" flags="0" />
           <item name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE" granted="true" flags="0" />
           <item name="android.permission.BIND_JOB_SERVICE" granted="true" flags="0" />
           <item name="android.permission.CONFIRM_FULL_BACKUP" granted="true" flags="0" />
           <item name="android.permission.SET_TIME" granted="true" flags="0" />
           <item name="android.permission.WRITE_APN_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" />
           <item name="android.permission.MANAGE_USERS" granted="true" flags="0" />
           <item name="android.permission.SET_PREFERRED_APPLICATIONS" granted="true" flags="0" />
           <item name="android.permission.DELETE_CACHE_FILES" granted="true" flags="0" />
           <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
           <item name="zq.permissio.CONNECTION_ACTIVATION_SERVICE" granted="true" flags="0" />
           <item name="android.permission.DISABLE_KEYGUARD" granted="true" flags="0" />
           <item name="android.permission.BACKUP" granted="true" flags="0" />
           <item name="android.permission.CHANGE_CONFIGURATION" granted="true" flags="0" />
           <item name="android.permission.USER_ACTIVITY" granted="true" flags="0" />
           <item name="android.permission.READ_LOGS" granted="true" flags="0" />
           <item name="android.permission.COPY_PROTECTED_DATA" granted="true" flags="0" />
           <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
           <item name="android.permission.SET_KEYBOARD_LAYOUT" granted="true" flags="0" />
           <item name="android.permission.USE_FINGERPRINT" granted="true" flags="0" />
           <item name="android.permission.WRITE_USER_DICTIONARY" granted="true" flags="0" />
           <item name="android.permission.READ_SYNC_STATS" granted="true" flags="0" />
           <item name="android.permission.REBOOT" granted="true" flags="0" />
           <item name="android.permission.OEM_UNLOCK_STATE" granted="true" flags="0" />
           <item name="android.permission.MANAGE_DEVICE_ADMINS" granted="true" flags="0" />
           <item name="android.permission.CHANGE_APP_IDLE_STATE" granted="true" flags="0" />
           <item name="android.permission.SET_POINTER_SPEED" granted="true" flags="0" />
           <item name="android.permission.MANAGE_NOTIFICATIONS" granted="true" flags="0" />
           <item name="android.permission.READ_SYNC_SETTINGS" granted="true" flags="0" />
           <item name="android.permission.OVERRIDE_WIFI_CONFIG" granted="true" flags="0" />
           <item name="android.permission.FORCE_STOP_PACKAGES" granted="true" flags="0" />
           <item name="android.permission.ACCESS_NOTIFICATIONS" granted="true" flags="0" />
           <item name="android.permission.VIBRATE" granted="true" flags="0" />
           <item name="com.android.certinstaller.INSTALL_AS_USER" granted="true" flags="0" />
           <item name="android.permission.READ_USER_DICTIONARY" granted="true" flags="0" />
           <item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
           <item name="android.permission.CHANGE_WIMAX_STATE" granted="true" flags="0" />
           <item name="android.permission.MODIFY_PHONE_STATE" granted="true" flags="0" />
           <item name="android.permission.STATUS_BAR" granted="true" flags="0" />
           <item name="android.permission.READ_FRAME_BUFFER" granted="true" flags="0" />
           <item name="android.permission.LOCATION_HARDWARE" granted="true" flags="0" />
           <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
           <item name="android.permission.INJECT_EVENTS" granted="true" flags="0" />
           <item name="android.permission.DELETE_PACKAGES" granted="true" flags="0" />
       </perms>
       <proper-signing-keyset identifier="1" />
   </package>

所以问题来了,改成系统应用后uid为什么变成1000?后面代表权限组的一串数字又都是什么?

0011 Android File Permission

android_filesystem_config.h

在Android中,所有权限的定义都在: system/core/include/private/android_filesystem_config.h

在这个头文件中定义了Android系统的一些用户,包含root用户,system用户,shell用户所对应的值等等。

/* This is the master Users and Groups config for the platform.
 * DO NOT EVER RENUMBER
 */

#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_DBUS          1038  /* dbus-daemon IPC broker process */
#define AID_TLSDATE       1039  /* tlsdate unprivileged user */
#define AID_MEDIA_EX      1040  /* mediaextractor process */
#define AID_AUDIOSERVER   1041  /* audioserver process */
#define AID_METRICS_COLL  1042  /* metrics_collector process */
#define AID_METRICSD      1043  /* metricsd process */
#define AID_WEBSERV       1044  /* webservd process */
#define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
#define AID_MEDIA_CODEC   1046  /* mediacodec process */
#define AID_CAMERASERVER  1047  /* cameraserver process */
#define AID_FIREWALL      1048  /* firewalld process */
#define AID_TRUNKS        1049  /* trunksd process (TPM daemon) */
#define AID_NVRAM         1050  /* Access-controlled NVRAM */
#define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
/* Changes to this file must be made in AOSP, *not* in internal branches. */

#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_READPROC      3009  /* Allow /proc read access */
#define AID_WAKELOCK      3010  /* Allow system wakelock read/write access */

/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
#define AID_OEM_RESERVED_2_END   5999

#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, },
    { "sdcard_pics",   AID_SDCARD_PICS, },
    { "sdcard_av",     AID_SDCARD_AV, },
    { "sdcard_all",    AID_SDCARD_ALL, },
    { "logd",          AID_LOGD, },
    { "shared_relro",  AID_SHARED_RELRO, },
    { "dbus",          AID_DBUS, },
    { "tlsdate",       AID_TLSDATE, },
    { "mediaex",       AID_MEDIA_EX, },
    { "audioserver",   AID_AUDIOSERVER, },
    { "metrics_coll",  AID_METRICS_COLL },
    { "metricsd",      AID_METRICSD },
    { "webserv",       AID_WEBSERV },
    { "debuggerd",     AID_DEBUGGERD, },
    { "mediacodec",    AID_MEDIA_CODEC, },
    { "cameraserver",  AID_CAMERASERVER, },
    { "firewall",      AID_FIREWALL, },
    { "trunks",        AID_TRUNKS, },
    { "nvram",         AID_NVRAM, },
    { "dns",           AID_DNS, },
    { "dns_tether",    AID_DNS_TETHER, },

    { "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, },
    { "readproc",      AID_READPROC, },
    { "wakelock",      AID_WAKELOCK, },

    { "everybody",     AID_EVERYBODY, },
    { "misc",          AID_MISC, },
    { "nobody",        AID_NOBODY, },
};

好了,了解这个文件我们再来看我们应用的信息:

com.softard.test 1000 0 /data/user/0/com.softard.test platform 3009,3002,1023,1015,3003,3001,1021,1000,2002,1010,1007

我们把数字对应的信息截取下来:

#define AID_SYSTEM        1000  "system"	/* system server */		
#define AID_LOG           1007  "log"		/* log devices */		
#define AID_WIFI          1010  "wifi"		/* wifi subsystem */	
#define AID_SDCARD_RW     1015  "sdcard_rw"	/* external storage write access */
#define AID_GPS           1021  "gps"		/* GPS daemon */
#define AID_MEDIA_RW      1023  "media_rw"	/* internal media storage write access */
#define AID_DIAG          2002  "diag"		/* access to diagnostic resources */
#define AID_NET_BT_ADMIN  3001  "net_bt_admin"/* bluetooth: create any socket */
#define AID_NET_BT        3002  "net_bt"	/* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET          3003  "inet"		/* can create AF_INET and AF_INET6 sockets */
#define AID_READPROC      3009  "readproc"	/* Allow /proc read access */

所以,当我指定应用为系统应用时,就将uid指定为了1000。并且拥有了各种属于系统的权限组。

那么,指定系统应用后是怎么获得这一系列的gid呢?这一块源码流程很多,放到后面集中分析。

好了,现在我们了解 system/core/include/private/android_filesystem_config.h 文件定义以后,其实就前进了一大步。注意一下代码所在源码位置,位于 system/core 下,其实它已经是Android内核部分了,所以后面涉及到权限内容,都会导入这个头文件。

现在来看一段源码再来熟悉一下这部分内容:

FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);

这是位于 frameworks/base/services/core/java/com/android/server/pm/Settings.java 的一段代码,功能就是创建 packages.list 文件。从函数名称和参数可以知道,它是给文件添加权限的,通过这段代码可以推测出:它给packages.list文件赋予了0640的权限,权限隶属于system,权限组为package_info。

然后我们进入系统看一看是不是这样:

/data/system # ls -l packages.list
-rw-r----- 1 system package_info 13627 1970-01-01 11:27 packages.list

有没有发现原来Android底层权限其实也不是很难理解嘛?

这时,又有一个问题了,创建文件你可以这样设定权限,但系统文件/文件夹的默认权限又是从哪来的?这就要引入另外一个文件了。

fs_config.c

写过Android App的你肯定知道,App的一些数据都放在 /data/data 目录下。正常情况下这个目录是不可以访问的:

/data/data $ ls
ls: .: Permission denied

我们看一下这个目录的权限:

/data/data $ ls -ld
drwxrwx--x 310 system system 12288 2019-01-11 09:51 .

我们作为 shell 用户,只有一个x权限, 当然访问不了。那如果我要给shell赋予访问权限改怎么改呢?

这就需要了解一下 system/core/libcutils/fs_config.c 文件了。系统目录和文件的用户组以及权限都是在这个文件里定义的:

/* 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" },
    { 00500, AID_ROOT,   AID_ROOT,   0, "config" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
    { 00771, AID_ROOT,   AID_ROOT,   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" },
    { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
    { 00775, AID_ROOT,   AID_ROOT,   0, "data/preloads" },
    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
    { 00755, AID_ROOT,   AID_SYSTEM, 0, "mnt" },
    { 00755, AID_ROOT,   AID_ROOT,   0, "root" },
    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
    { 00751, AID_ROOT,   AID_SDCARD_R, 0, "storage" },
    { 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 char conf_dir[] = "/system/etc/fs_config_dirs";
static const char conf_file[] = "/system/etc/fs_config_files";

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" },
    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
    { 00440, AID_ROOT,      AID_ROOT,      0, "system/etc/recovery.img" },
    { 00444, AID_ROOT,      AID_ROOT,      0, conf_dir + 1 },
    { 00444, AID_ROOT,      AID_ROOT,      0, conf_file + 1 },
    { 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_SYSTEM,    AID_SYSTEM,    0, "data/app-ephemeral/*" },
    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },

    /* the following two files are INTENTIONALLY set-uid, but they
     * are NOT included on user builds. */
    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },

    /* the following files have enhanced capabilities and ARE included in user builds. */
    { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
    { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },

    /* Support FIFO scheduling mode in SurfaceFlinger. */
    { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },

    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/xbin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
    { 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, "sbin/fs_mgr" },
    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
};

感觉也不用多说, android_dirs[] 负责文件夹的权限配置, android_files[] 负责文件的权限配置。

从里面定义找找刚提到的 /data/data 目录

{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },

你看,就是这么回事儿而已。如果要改成shell权限的话,只需要这样改就可以了:

{ 00771, AID_SYSTEM, AID_SHELL, 0, "data/data" },

当然,如果系统里还要添加其他目录、文件需要指定权限,只需要在这个文件里添加一行即可。

0100 Android App Permission

讲到这里,还遗留一个开头提出的问题:

为什么你在AndroidManifest文件请求storage权限你就可以访问设备文件?

0010里提到过,PackageManagerService在启动后会扫描所有已经安装的App,然后加载和解析他们的Androidmanifest文件,生成 packages.listpackages.xml 等文件。解析过程就包括了permission的解析与拦截。

frameworks/base/core/res/AndroidManifest.xml 这个文件中定义了Permission拦截规则,下面列举几个:

<!-- Allows an application to read from external storage.
     <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
     granted this permission.</p>
     <p>This permission is enforced starting in API level 19.  Before API level 19, this
     permission is not enforced and all apps still have access to read from external storage.
     You can test your app with the permission enforced by enabling <em>Protect USB
     storage</em> under Developer options in the Settings app on a device running Android 4.1 or
     higher.</p>
     <p>Also starting in API level 19, this permission is <em>not</em> required to
     read/write files in your application-specific directories returned by
     {@link android.content.Context#getExternalFilesDir} and
     {@link android.content.Context#getExternalCacheDir}.
     <p class="note"><strong>Note:</strong> If <em>both</em> your <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
     minSdkVersion}</a> and <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
     targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
     grants your app this permission. If you don't need this permission, be sure your <a
     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
     targetSdkVersion}</a> is 4 or higher.
     <p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"
            android:permissionGroup="android.permission-group.STORAGE"
            android:label="@string/permlab_sdcardRead"
            android:description="@string/permdesc_sdcardRead"
            android:protectionLevel="dangerous" />

<!-- Allows applications to access information about Wi-Fi networks.
         <p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_WIFI_STATE"
            android:description="@string/permdesc_accessWifiState"
            android:label="@string/permlab_accessWifiState"
            android:protectionLevel="normal" />

<!-- @SystemApi Allows applications to set the system time.
    <p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
            android:protectionLevel="signature|privileged" />

这里看一下 protectionLevel ,normal是一般权限,即不需要动态申请,直接在Manifest里注册即可获得的权限。dangerous是敏感权限,需要动态申请告知用户才能获取的权限。signature|privileged一般是系统priv-app才拥有的权限,也就是拥有系统签名的系统应用。

他的拦截规则大概是,如果App申请了signature|privileged权限,但他是普通开发者的三方App,PMS就会将其从申请权限的列表里将该权限删除。这样你的App实际上就没有获得对应的权限了。

那么,文件属性的权限是怎么和Permission联系起来的?不出意外,系统也有一个关联文件的定义 frameworks/base/data/etc/platform.xml

<!-- This file is used to define the mappings between lower-level system
     user and group IDs and the higher-level permission names managed
     by the platform.

     Be VERY careful when editing this file!  Mistakes made here can open
     big security holes.
-->
<permissions>

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are associating low-level group IDs with
         permission names.  By specifying such a mapping, you are saying
         that any application process granted the given permission will
         also be running with the given group ID attached to its process,
         so it can perform any filesystem (read, write, execute) operations
         allowed for that group. -->

    <permission name="android.permission.BLUETOOTH_ADMIN" >
        <group gid="net_bt_admin" />
    </permission>

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    </permission>

    <permission name="android.permission.BLUETOOTH_STACK" >
        <group gid="net_bt_stack" />
        <group gid="wakelock" />
    </permission>

    <permission name="android.permission.NET_TUNNELING" >
        <group gid="vpn" />
    </permission>

    <permission name="android.permission.INTERNET" >
        <group gid="inet" />
    </permission>

    <permission name="android.permission.READ_LOGS" >
        <group gid="log" />
    </permission>

    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
        <group gid="media_rw" />
        <group gid="sdcard_rw" />
    </permission>

    <permission name="android.permission.ACCESS_MTP" >
        <group gid="mtp" />
    </permission>

    <permission name="android.permission.NET_ADMIN" >
        <group gid="net_admin" />
    </permission>

    <!-- The group that /cache belongs to, linked to the permission
         set on the applications that can access /cache -->
    <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
        <group gid="cache" />
    </permission>

    <!-- RW permissions to any system resources owned by group 'diag'.
         This is for carrier and manufacture diagnostics tools that must be
         installable from the framework. Be careful. -->
    <permission name="android.permission.DIAGNOSTIC" >
        <group gid="input" />
        <group gid="diag" />
    </permission>

    <!-- Group that can read detailed network usage statistics -->
    <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
        <group gid="net_bw_stats" />
    </permission>

    <!-- Group that can modify how network statistics are accounted -->
    <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
        <group gid="net_bw_acct" />
    </permission>

    <permission name="android.permission.LOOP_RADIO" >
        <group gid="loop_radio" />
    </permission>

    <!-- Hotword training apps sometimes need a GID to talk with low-level
         hardware; give them audio for now until full HAL support is added. -->
    <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
        <group gid="audio" />
    </permission>

    <permission name="android.permission.ACCESS_FM_RADIO" >
        <!-- /dev/fm is gid media, not audio -->
        <group gid="media" />
    </permission>

    <!-- These are permissions that were mapped to gids but we need
         to keep them here until an upgrade from L to the current
         version is to be supported. These permissions are built-in
         and in L were not stored in packages.xml as a result if they
         are not defined here while parsing packages.xml we would
         ignore these permissions being granted to apps and not
         propagate the granted state. From N we are storing the
         built-in permissions in packages.xml as the saved storage
         is negligible (one tag with the permission) compared to
         the fragility as one can remove a built-in permission which
         no longer needs to be mapped to gids and break grant propagation. -->
    <permission name="android.permission.READ_EXTERNAL_STORAGE" />
    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- ================================================================== -->
    <!-- ================================================================== -->
    <!-- ================================================================== -->

    <!-- The following tags are assigning high-level permissions to specific
         user IDs.  These are used to allow specific core system users to
         perform the given operations with the higher-level framework.  For
         example, we give a wide variety of permissions to the shell user
         since that is the user the adb shell runs under and developers and
         others should have a fairly open environment in which to
         interact with the system. -->

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
    <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />

    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
    <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />

    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

    <!-- This is a list of all the libraries available for application
         code to link against. -->

    <library name="android.test.runner"
            file="/system/framework/android.test.runner.jar" />
    <library name="javax.obex"
            file="/system/framework/javax.obex.jar" />
    <library name="org.apache.http.legacy"
            file="/system/framework/org.apache.http.legacy.jar" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in power save mode, even if they aren't in the foreground. -->
    <allow-in-power-save package="com.android.providers.downloads" />

    <!-- These are the standard packages that are white-listed to always have internet
         access while in data mode, even if they aren't in the foreground. -->
    <allow-in-data-usage-save package="com.android.providers.downloads" />

    <!-- These are the packages that are white-listed to be able to run as system user -->
    <system-user-whitelisted-app package="com.android.settings" />

    <!-- These are the packages that shouldn't run as system user -->
    <system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
</permissions>

这个文件定义了所有权限所属的gid。从里面找一下 READ_EXTERNAL_STORAGE 权限,emmmm,什么都没做。这是因为6.0之后存储权限变成动态,需要用户确认才可以获取权限,所以这里不作处理。动态权限这部分代码先不分析了,来看一下老版本的文件:

<permission name="android.permission.READ_EXTERNAL_STORAGE" >
    <group gid="sdcard_r" />
</permission>

那明确了, READ_EXTERNAL_STORAGE 权限获取的gid是 sdcard_r ,然后查看上面的文件定义,对应 AID_SDCARD_R ,数值是1028。实际上在7.0上得到的是 sdcard_rw ,即1015。

PMS在解析每个Permission时会根据这个文件将Permission关联的gid 加入到一个gid的数组中去,从而硬件设备所对应的设备文件就能被该应用程序访问。这块具体代码流程放到下一篇去分析。想自己跟代码的话可以从该函数看起:

private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
                                              String[] grantedPermissions) {
    for (int userId : userIds) {
        grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
    }

    // We could have touched GID membership, so flush out packages.list
    synchronized (mPackages) {
        mSettings.writePackageListLPr();
    }
}

回到存储权限,既然系统会根据permission给App添加合适的gid,那么我们在看下内置存储的权限为

/sdcard # ls -ld
drwxrwx--x 27 root sdcard_rw 4096 1970-01-01 18:30 .

所以获得 sdcard_rw 权限组的应用才可以访问内置存储。

到此Android权限的底层实现原理简单介绍完了,不过目前这里还留有一个坑,那就是我在测试App里添加STORAGE权限后,安装到设备里,通过查看进程属性,发现:

# ps | grep softard
u0_a53    3530  638   969076 30720 binder_thr b07244fc S com.softard.test
# cat /proc/3530/status
Name:	com.softard.test
State:	S (sleeping)
Tgid:	3530
Pid:	3530
PPid:	638
TracerPid:	0
Uid:	10053	10053	10053	10053
Gid:	10053	10053	10053	10053
Ngid:	0
FDSize:	256
Groups:	9997 50053

Groups没有对应的gid,但是程序的确可以访问 /sdcard

然后我又给App系统签名,作为系统应用放进去再看,

# ps | grep soft
system    3560  629   985352 49184 SyS_epoll_ abea53b8 S com.softard.test
# cat /proc/3560/status
Name:	com.softard.test
State:	S (sleeping)
Tgid:	3560
Pid:	3560
PPid:	629
TracerPid:	0
Uid:	1000	1000	1000	1000
Gid:	1000	1000	1000	1000
Ngid:	0
FDSize:	256
Groups:	1000 1007 1010 1015 1021 1023 2002 2950 3001 3002 3003 3009 9997 41000

这时候Groups有sdcard_rw权限了。然后从设置里手动关掉存储权限,App无法读取文件,再次检查gid发现这个1015依旧存在。

WTF,7.0的表现跟5.0完全不一样?又是一个坑…后面抽空再填吧…

行吧,这篇概览就这样了,后面就开始从眼花缭乱的源码角度去看这一切的实现。


以上所述就是小编给大家介绍的《[Framework] 全方位理解Android权限之底层实现概览》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

精通Android游戏开发

精通Android游戏开发

[美] Vladimir Silva / 王恒、苏金国 等 / 人民邮电出版社 / 2011-2 / 45.00元

作为引领移动技术潮流的软件平台,Android发布了NDK以支持Java和C的混合开发,使PC游戏可以在Android平台上焕发更多魅力。 本书是为那些在Android游戏开发工作中寻求突破的人准备的。书中不仅通过Space Blaster和Asteroids这两个炫酷 的街机游戏深入介绍了如何从头构建纯Java游戏,更详细展示了如何将PC上的3D经典游戏Doom和Wolfenstein 3......一起来看看 《精通Android游戏开发》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具