Android9.0/8.1/6.0 默认给系统 app 授予所有权限

简介: Android9.0/8.1/6.0 默认给系统 app 授予所有权限

前言


最近和 PackageManagerService(PMS) 杠上了,3W 多行代码,着实精妙。网上有很多分析流程的文章,这里我就不再复述了,就来看下 PMS 的衍生修改实战吧。之前写过一篇 Android8.1 默认给第三方 app 授予所有权限,其实也能给系统 app 授权,原理大概为收到开机广播后去检查指定包名权限是否已经赋予,未授权则授权。但开机广播有时效性,有些场景不能满足要求,况且总需要去修改源码,不方便。


修改


大致思路如下,参考 MTK 的系统 app 可卸载配置方案,在

vendor\mediatek\proprietary\frameworks\base\data\etc\pms_sysapp_removable_system_list.txt

中增加可卸载系统 app 包名,在编译时拷贝至 out system/etc/permissions 路径下, 在 PmsExtImpl.java 中读取该文件,PMS 在扫描时判断包名是否在 pms_sysapp_removable_system_list 列表中,确定是否可卸载。


一、新建 pms_sysapp_grant_permission_list.txt


vendor\mediatek\proprietary\frameworks\base\data\etc\pms_sysapp_grant_permission_list.txt


com.android.dialer
com.android.soundrecorder
com.android.browser
com.mediatek.filemanager
com.android.calendar
com.android.email

二、拷贝 pms_sysapp_grant_permission_list.txt 至 out 目录下


device/mediatek/common/device.mk

 ifneq ($(strip $(MTK_BASIC_PACKAGE)), yes)
+  PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_grant_permission_list.txt:system/etc/permissions/pms_sysapp_grant_permission_list.txt)
   PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_removable_system_list.txt:system/etc/permissions/pms_sysapp_removable_system_list.txt)
   PRODUCT_COPY_FILES += $(call add-to-product-copy-files-if-exists,vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_removable_vendor_list.txt:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/pms_sysapp_removable_vendor_list.txt)
 endif

三、PMS 中系统启动完成读取 pms_sysapp_grant_permission_list.txt,给 app 授权


frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

@Override
    public void systemReady() {
        enforceSystemOrRoot("Only the system can claim the system is ready");
    //cczheng add for system app grant permission S
        if (mFirstBoot) {
            MTKPackageManagerUtil.slientGrantRuntimePermission(mContext);
        }
    //cczheng add for system app grant permission E
        mSystemReady = true;
        final ContentResolver resolver = mContext.getContentResolver();
        ContentObserver co = new ContentObserver(mHandler) {
            @Override
            public void onChange(boolean selfChange) {
                mEphemeralAppsDisabled =
                        (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
                                (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
            }
        };
        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                        .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
                false, co, UserHandle.USER_SYSTEM);
        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                        .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
        co.onChange(true);


新增 MTKPackageManagerUtil 类

1、读取 pms_sysapp_grant_permission_list.txt 中包名

2、遍历包名集合获取需要申请的权限集合

3、根据权限名称判断当前包名是否已经授权,未授权则授权

此处有几个坑说一下,

坑一、根据包名获取到的权限集合中有很多不在BasePermission中, 系统不能正常授权,会抛异常,导致后续的权限不能正常授权,需要剔除这部分。

2019-01-01 08:23:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.grantRuntimePermission(PackageManagerService.java:5732)
2019-01-01 08:23:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.grantRuntimePermission(PackageManagerService.java:5703)
2019-01-01 08:23:51.605 656-656/system_process W/System.err:     at android.app.ApplicationPackageManager.grantRuntimePermission(ApplicationPackageManager.java:627)
2019-01-01 08:23:51.605 656-656/system_process W/System.err:     at com.android.server.pm.MTKPackageManagerUtil.slientGrantRuntimePermission(MTKPackageManagerUtil.java:90)
2019-01-01 08:23:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.systemReady(PackageManagerService.java:22551)
2019-01-01 08:23:51.605 656-656/system_process D/MTKPackageManagerUtil: Unknown permission: com.qualcomm.permission.USE_PHONE_SERVICE

坑二、用户自己声明的权限和非运行时权限,需要剔除这部分。

2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(PackageManagerService.java:5696)
2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.grantRuntimePermission(PackageManagerService.java:5740)
2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.grantRuntimePermission(PackageManagerService.java:5703)
2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at android.app.ApplicationPackageManager.grantRuntimePermission(ApplicationPackageManager.java:627)
2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at com.android.server.pm.MTKPackageManagerUtil.slientGrantRuntimePermission(MTKPackageManagerUtil.java:90)
2019-01-01 08:43:51.605 656-656/system_process W/System.err:     at com.android.server.pm.PackageManagerService.systemReady(PackageManagerService.java:22551)
2019-01-01 08:43:51.605 656-656/system_process D/MTKPackageManagerUtil: Permission android.permission.ACCESS_BLUETOOTH_SHARE is not a changeable permission type

frameworks\base\services\core\java\com\android\server\pm\MTKPackageManagerUtil.java

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.pm;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.content.pm.IPackageManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.Manifest;
import com.android.internal.util.ArrayUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
public class MTKPackageManagerUtil{
    private static String TAG = "KEPackageManagerUtil";
    //copy from vendor\mediatek\proprietary\frameworks\base\services\core\java\com\mediatek\server\pm\PmsExtImpl.java
    private static final File GRANT_SYS_APP_LIST_SYSTEM = Environment
            .buildPath(Environment.getRootDirectory(), "etc", "permissions",
                    "pms_sysapp_grant_permission_list.txt");
    private static HashSet<String> sGrantSystemAppSet = new HashSet<String>();
    private static HashSet<String> sGrantPermissionSet = new HashSet<String>();
    private static  IPackageManager mIpm;
    private static  AppOpsManager mAppOpsManager;
    public static void slientGrantRuntimePermission(Context mContext, Settings mSettings){
        sGetGrantSystemAppFromFile(sGrantSystemAppSet, GRANT_SYS_APP_LIST_SYSTEM);
        PackageManager mPackageManager = mContext.getPackageManager();
        mIpm = AppGlobals.getPackageManager();
        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        Iterator<String> it = sGrantSystemAppSet.iterator();
        Log.d(TAG, "sGrantSystemAppSet:");
        while (it.hasNext()) {
            sGrantPermissionSet.clear();
            String pkgName = it.next();
            Log.d(TAG, "pkgName="+pkgName);
            try {
                PackageInfo mPackageInfo =   mPackageManager.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS);
                 for (String permission : mPackageInfo.requestedPermissions){
                     int status = mPackageManager.checkPermission(permission, pkgName);
                     final BasePermission bp = mSettings.mPermissions.get(permission);
                     if (status != PackageManager.PERMISSION_GRANTED && bp != null) {
                        if (!bp.isRuntime() && !bp.isDevelopment()) {
                            Log.d(TAG, "Permission " + bp.name + " is not a changeable permission type");
                            continue;
                        }
                        sGrantPermissionSet.add(permission);
                     }
                 }
                 Log.d(TAG, " need grantRuntimePermission size:"+sGrantPermissionSet.size());
                 for (String permission : sGrantPermissionSet) {
                    mPackageManager.grantRuntimePermission(pkgName,
                            permission, Process.myUserHandle());
                 }
                 if (checkInstallPackagesPermission(pkgName, mPackageInfo)) {
                     Log.e(TAG, pkgName + " need grant INSTALL_PACKAGES permission");
                     mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
                        mPackageInfo.applicationInfo.uid, pkgName, AppOpsManager.MODE_ALLOWED);
                     Log.e(TAG, "grant INSTALL_PACKAGES permission done");
                 }
            } catch (Exception e) {
                //e.printStackTrace();
                Log.d(TAG, e.getMessage());
            }
        }
    }
    private static boolean checkInstallPackagesPermission(String packageName, PackageInfo mPackageInfo){
        int uid = mPackageInfo.applicationInfo.uid;
        //boolean permissionGranted = hasPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, uid);
        boolean permissionRequested = hasRequestedAppOpPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, packageName);
        int appOpMode = getAppOpMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, uid, packageName);
        return appOpMode != AppOpsManager.MODE_DEFAULT || permissionRequested;
    }
    private static int getAppOpMode(int appOpCode, int uid, String packageName) {
        return mAppOpsManager.checkOpNoThrow(appOpCode, uid, packageName);
    }
    private static boolean hasRequestedAppOpPermission(String permission, String packageName) {
        try {
            String[] packages = mIpm.getAppOpPermissionPackages(permission);
            return ArrayUtils.contains(packages, packageName);
        } catch (Exception exc) {
            Log.e(TAG, "PackageManager dead. Cannot get permission info");
            return false;
        }
    }
    private static boolean hasPermission(String permission, int uid) {
        try {
            int result = mIpm.checkUidPermission(permission, uid);
            return result == PackageManager.PERMISSION_GRANTED;
        } catch (Exception e) {
            Log.e(TAG, "PackageManager dead. Cannot get permission info");
            return false;
        }
    }
    /**
     * Get removable system app list from config file
     *
     * @param resultSet
     *            Returned result list
     * @param file
     *            The config file
     */
    private static void sGetGrantSystemAppFromFile(
            HashSet<String> resultSet, File file) {
        resultSet.clear();
        FileReader fr = null;
        BufferedReader br = null;
        try {
            if (file.exists()) {
                fr = new FileReader(file);
            } else {
                Log.d(TAG, "file in " + file + " does not exist!");
                return;
            }
            br = new BufferedReader(fr);
            String line;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (!TextUtils.isEmpty(line)) {
                    Log.d(TAG, "read line " + line);
                    resultSet.add(line);
                }
            }
            Log.e(TAG,"GRANT_SYS_APP_LIST_SYSTEM size="+resultSet.size());
        } catch (Exception io) {
            Log.d(TAG, io.getMessage());
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException io) {
                Log.d(TAG, io.getMessage());
            }
        }
    }
}


目录
相关文章
|
9天前
|
安全 定位技术 API
婚恋交友系统匹配功能 婚恋相亲软件实现定位 语音社交app红娘系统集成高德地图SDK
在婚恋交友系统中集成高德地图,可实现用户定位、导航及基于地理位置的匹配推荐等功能。具体步骤如下: 1. **注册账号**:访问高德开放平台,注册并创建应用。 2. **获取API Key**:记录API Key以备开发使用。 3. **集成SDK**:根据开发平台下载并集成高德地图SDK。 4. **配置功能**:实现定位、导航及基于位置的匹配推荐。 5. **注意事项**:保护用户隐私,确保API Key安全,定期更新地图数据,添加错误处理机制。 6. **测试优化**:完成集成后进行全面测试,并根据反馈优化功能。 通过以上步骤,提升用户体验,提供更便捷的服务。
|
10天前
|
运维 小程序 前端开发
结合圈层营销策略,打造稳定可靠的圈子app系统,圈子小程序!
圈子系统是一种社交平台,用户可按兴趣、职业等创建或加入“圈子”,进行内容发布、讨论和资源共享。开发时需考虑需求分析、技术选型(如PHP、MySQL)、页面设计、功能实现(注册、登录、发布、评论等)、测试优化及运维管理。圈层营销则通过精准化、高端化的方式传递品牌信息,增强客户归属感。圈子小程序基于微信等平台,具备跨平台、便捷性和社交性,开发过程中需明确需求、选择技术框架、设计页面并确保稳定性和流畅性。
|
3天前
年轻人如果运用圈子系统进行扩列,社交圈子论坛app扩列的好处,兴趣行业圈子提升社交技能
年轻人通过圈子系统扩列,在数字化时代积极扩展社交网络、增进人际交往。圈子系统是社交媒体中的虚拟社区,提供内容发布、互动等功能。扩列能拓宽社交圈、增进交流、获取信息资源、提升社交技能并发现商业机会。策略包括明确目标、筛选适合的圈子、积极参与和保持诚信。同时需注意保护隐私、警惕不良信息及合理规划时间。
|
3天前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
|
7天前
|
前端开发 算法 安全
一站式搭建相亲交友APP丨交友系统源码丨语音视频聊天社交软件平台系统丨开发流程步骤
本文详细介绍了一站式搭建相亲交友APP的开发流程,涵盖需求分析、技术选型、系统设计、编码实现、测试、部署上线及后期维护等环节。通过市场调研明确平台定位与功能需求,选择适合的技术栈(如React、Node.js、MySQL等),设计系统架构和数据库结构,开发核心功能如用户注册、匹配算法、音视频聊天等,并进行严格的测试和优化,确保系统的稳定性和安全性。最终,通过云服务部署上线,并持续维护和迭代,提供一个功能完善、安全可靠的社交平台。
66 6
|
9天前
|
前端开发 数据库 UED
uniapp开发,前后端分离的陪玩系统优势,陪玩app功能特点,线上聊天线下陪玩,只要4800
前后端分离的陪玩系统将前端(用户界面)和后端(服务器逻辑)分开开发,前者负责页面渲染与用户交互,后者处理数据并提供接口。该架构提高开发效率、优化用户体验、增强可扩展性和稳定性,降低维护成本,提升安全性。玩家可发布陪玩需求,陪玩人员发布服务信息,支持在线聊天、预约及线下陪玩功能,满足多样化需求。[演示链接](https://www.51duoke.cn/games/?id=7)
|
11天前
|
移动开发 小程序 前端开发
使用php开发圈子系统特点,如何获取圈子系统源码,社交圈子运营以及圈子系统的功能特点,圈子系统,允许二开,免费源码,APP 小程序 H5
开发一个圈子系统(也称为社交网络或社群系统)可以是一个复杂但非常有趣的项目。以下是一些关键特点和步骤,帮助你理解如何开发、获取源码以及运营一个圈子系统。
77 3
|
8天前
|
安全 算法 机器人
双重防护!红娘相亲app搭建开发,婚恋交友系统登录方式,密码+验证码的优势
在婚恋交友系统中,密码和验证码是两种重要的安全措施。密码用于验证用户身份,应设置为复杂组合以防止未经授权的访问;验证码则通过图形或字符识别,防止自动化攻击如暴力破解和注册机器人。两者同时开启可显著提高安全性,防止暴力破解和自动化注册,提升用户信任感。建议要求强密码、定期更新验证码样式,并在可疑登录时增加验证码复杂性。这样既能保障用户信息安全,又兼顾了用户体验。 ![交友11111.jpg](https://ucc.alicdn.com/pic/developer-ecology/hy2p6wcvgk4oe_c9eb8d6eb8144866b0cd1d96ffb0c907.jpg)
|
8天前
|
前端开发 搜索推荐 PHP
大开眼界!uniapp秀操作,陪玩系统新功能,陪玩app源码,可实时互动随心优化!
多客游戏陪玩系统采用前端uniapp与PHP语言,实现全开源、易改造,RTC传输协议确保低延迟语音连麦,分布式部署应对高并发。功能创新包括游戏约单、多人语音聊天室、动态广场、私信聊天等,提供高端社交和个性化服务,满足各类需求,让玩家畅享游戏乐趣。