Android系统编译之系统权限

1.引言

android system/etc 中有很多配置文件,例如白名单,例如system-private 权限区别,还例如 如何配置aapp的内存。这些都是懵逼的。抱着好奇心态,决定深入进去看看一般是怎么设置的。参考链接:https://blog.csdn.net/superkris/article/details/7709504/

2.Android的权限规则

2.1 基于UserID的进程级别的安全机制

进程有独立的地址空间,进程与进程间默认是不能互相访问的,Android通过为每一个apk分配唯一的linux userID来实现,名称为"app_"加一个数字,比如app_43不同的UserID,运行在不同的进程,所以apk之间默认便不能相互访问。

Android提供了如下的一种机制,可以使两个apk打破前面讲的这种壁垒。 在AndroidManifest.xml中利用sharedUserId属性给不同的package分配相同的userID,通过这样做,两个package可以被当做同一个程序, 系统会分配给两个程序相同的UserID。当然,基于安全考虑,两个apk需要相同的签名,否则没有验证也就没有意义了

2.2 默认apk生成的数据对外是不可见的

实现方法是:Android会为程序存储的数据分配该程序的UserID。借助于Linux严格的文件系统访问权限,便实现了apk之间不能相互访问似有数据的机制。 例:我的应用创建的一个文件,默认权限如下,可以看到只有UserID为app_21的程序才能读写该文件

2.3 root权限和system权限

  • root权限

    拥有root权限的用户,其uid=0. 拥有系统约定的最高权限。可以访问绝大部分文件

  • system 权限
    1. system/app 下面的apk

    2. system/priv-app 下面的apk。

    俩者的区别在于:俩者虽然都是系统app,但是system/priv-app 中所具有的权限,要大于system/app

  • 特权权限

    特权应用程序是位于/system/priv-app目录下的系统应用程序 。过去,设备制造商几乎无法控制可对特权应用授予哪些签名|特许权限。从 Android 8.0 开始,制造商必须在 /etc/permissions 目录下的系统配置 XML 文件中明确授予特许权限。从 Android 9 开始,实现人员必须明确授予或拒绝授予所有特许权限,否则设备将无法启动。

frameworks\base\core\res\AndroidManifest.xml 定义了各种广播,普通权限,危险权限,特权权限:

<!-- Allows notifications to be colorized
     <p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
            android:protectionLevel="signature|setup" /> //setting 具备的

<!-- Allows access to keyguard secure storage.  Only allowed for system processes.
    @hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
    android:protectionLevel="signature" />  //系统签名

<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
    android:protectionLevel="signature|privileged" />  //系统签名且还需要在system/priv-app 下

<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
    android:protectionLevel="signatureorsystem " />  //系统签名且还得是系统app(system/priv-app 或system/app)

Android 权限分成四类:

  • 普通权限(normal permission):也叫正常权限,即使拥有了该类权限,用户的隐私数据被泄露篡改的风险也很小。例如,设置时区的权限就是正常权限。如果应用声明其需要正常权限,系统会自动向应用授予该权限。

  • 敏感权限(dangerous permission):也叫危险权限,运行时权限,跟普通权限相反,一旦某个应该获取了该类权限,用户的隐私数据就面临被泄露篡改的风险。比如 READ_CONTACTS 权限就属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。

  • 签名权限(signature permission):该类权限只对拥有相同签名的应用开放,比如手机QQ 自定义了一个permission 且在权限标签中加入 android:protectionLevel=”signature”,而访问它的某个数据时,必须要拥有该权限。然后微信和 QQ 发布时采用相同的签名,微信就可以申请访问 QQ 中的此权限,并使用对应权限控制的数据。其他程序即使知道了这个开放数据的接口,也在 Manifest 注册了权限,但由于应用签名不同,还是无法访问的对应的数据。

  • 系统签名权限(signatureOrSystem permission):与 signature permission类似,但它不光要求签名相同,还要求是同类的系统级应用,一般手机厂商开发的预制应用,才会用到该类权限

应用场景1:
前提:app 系统签过名且放置于system/app/下
操作: 调用 Settings.System.putInt
现象:
Caused by: java.lang.IllegalArgumentException: You cannot keep your settings in the secure settings.
解决方案: 将app 防止于system/priv-app下
问题: 为什么放置于system/priv-app就解决了问题呢?

源码分析:putInt方法最终会调用: enforceRestrictedSystemSettingsMutationForCallingPackage 方法

1858    private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
1859            String name, int userId) {
1860        // System/root/shell can mutate whatever secure settings they want.
1861        final int callingUid = Binder.getCallingUid();
1862        final int appId = UserHandle.getAppId(callingUid);
1863        if (appId == android.os.Process.SYSTEM_UID
1864                || appId == Process.SHELL_UID
1865                || appId == Process.ROOT_UID) {
1866            return;
1867        }
1868
1869        switch (operation) {
1870            case MUTATION_OPERATION_INSERT:
1871                // Insert updates.
1872            case MUTATION_OPERATION_UPDATE: {
1873                if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
1874                    return;
1875                }
1876
1877                // The calling package is already verified.
1878                PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
1879
1880                // Privileged apps can do whatever they want. 只要是特权应用,就可以直接插入数据
1881                if ((packageInfo.applicationInfo.privateFlags
1882                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1883                    return;
1884                }
1885                // 检查是否具备插入数据的资格,没得就会抛出异常
1886                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1887                        packageInfo.applicationInfo.targetSdkVersion, name);
1888            } break;
18
1910    }
应用场景2:
前提:国内 app 采用系统签名,放在/system/priv-app/下,但是没有添加 android:sharedUserId="android.uid.system
操作:app本身是一个service,需要有读写权限
现象:app中直接进行创建/删除文件,报错,提示没得读写权限
解决方案:

Y:\aosp\device\google\marlin\default-permissions.xml:

<exceptions>
    <exception package="com.verizon.mips.services">
        <permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
        <permission name="android.permission.READ_PHONE_STATE" fixed="false"/>
        <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
    </exception>
</exceptions>

default-permissions 配置文件会在第一次开机的时候加载。所以假如直接更改开发版中的default-permissions。需要格式化开发板,恢复出厂模式

应用场景3:
前提:国内 app 采用系统签名,放在/system/priv-app/下,但是没有添加 android:sharedUserId="android.uid.system且android:persistent="false"
操作: 代码中直接使用startService启动服务
现象:
Not allowed to start service Intent { flg=0x1000000 cmp=packagename/.servicename (has extras) }: app is in background uid UidRecord{52db80 u2357s1000 TRNB bg:+2m42s199ms idle procs:3 seq(0,0,0)}
问题: app系统签名且置于/system/app/下 但是为啥startService 还报错呢?且为什么加上android:persistent="true"就ok了呢
解答:

startService 启动服务流程中,有一个方法appServicesRestrictedInBackgroundLocked

 int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
    // Persistent app?
        if (mPackageManagerInt.isPackagePersistent(packageName)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " is persistent; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // Non-persistent but background whitelisted?
        if (uidOnBackgroundWhitelist(uid)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on background whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // Is this app on the battery whitelist?
        if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on idle whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // None of the service-policy criteria apply, so we apply the common criteria
        return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
    }
应用场景4:
前提:AndroidManifest 中添加android:sharedUserId="android.uid.system"
操作:代码中调用安装apk的代码
现象:弹出如下所示的dialog
问题:为什么会弹出这个框?如何解决这个问题
第一个问题解答:ActivityManagerService#checkGrantUriPermissionLocked
        if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) { 
9715            if ("com.android.settings.files".equals(grantUri.uri.getAuthority())
9716                    || SystemConfig.getInstance().getAuthoriesInPreloadedApks().contains(
9717                    grantUri.uri.getAuthority())) {
9718                // Exempted authority for
9719                // 1. cropping user photos and sharing a generated license html
9720                //    file in Settings app
9721                // 2. sharing a generated license html file in TvSettings app
9722            } else {
9723                Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
9724                        + " grant to " + grantUri + "; use startActivityAsCaller() instead");
9725                return -1;
9726            }
9727        }

callUid为SYSTEM_UID,且不满足俩个if 则return -1 ,于是就出现上述的安装失败情况。

解决方式有俩种:

  • 去掉android:sharedUserId
  • 更改SystemConfig.java
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容