[Android7.1][RK3399] 系統默認給予App權限的各種情況及對應測試方法

title: [Android7.1][RK3399] 系統默認給予App權限的各種情況及對應測試方法
date: 2020-5-12 21:00:00
tags: Android


Platform: RK3399
OS: Android 7.1
Kernel: v4.4.126

需求描述

有這樣幾種場景:
App 是 系統 App 或者是 第三方需要內置的 App;
權限 是 危險權限 或者是 特殊權限。
所以排列組合有四種場景。這裏分別討論。

  1. 系統 App(比如作爲用來替代原生Launcher的系統應用)需要默認給予所有的權限。
    包括危險權限(身體傳感器,日曆,攝像頭,通訊錄,地理位置,麥克風,電話,短信,存儲空間)和特殊權限(懸浮窗、系統修改權限、訪問使用記錄權限)。
    危險權限可以通過修改 DefaultPermissionGrantPolicy.java 實現;
    系統權限可以通過系統簽名實現。

  2. 系統需要內置的第三方App(比如騰訊視頻,驀然認知,喜馬拉雅這種)需要默認給它 危險權限和特殊權限。

給系統應用權限

framework 中的修改 DefaultPermissionGrantPolicy.java 給系統應用危險權限

services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -607,6 +607,25 @@ final class DefaultPermissionGrantPolicy {
                 grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId);
             }
 
+            PackageParser.Package YounixPackage = getPackageLPr("com.younix.packagename");
+            Log.d(TAG, "YounixPackage >> ");
+            if (YounixPackage != null) {
+                Log.d(TAG, "YounixPackage >> not null");
+                grantRuntimePermissionsLPw(YounixPackage, PHONE_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, CONTACTS_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, LOCATION_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, CALENDAR_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, SMS_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, MICROPHONE_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, CAMERA_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, SENSORS_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(YounixPackage, STORAGE_PERMISSIONS, userId);
+            }else{
+                Log.d(TAG, "YounixPackage >> null");
+            }
+
             // Watches
             if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
                 // Home application on watches

如上修改便給予了 com.younix.packagename 這個系統 App 所有的普通權限。

給系統應用特殊權限

特殊權限包括 懸浮窗、修改系統 設置等。
直接簽名即可。
根據 google 的文檔:https://developer.android.google.cn/reference/android/R.attr#protectionLevel

被 signature 標記標記的權限類型,當 app 被系統簽名的時候,這種類型的權限會直接賦予給 app
signature :Base permission type: a permission that the system is to grant only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user’s explicit approval.

驗證方法

  1. 通過開機後在 設置-應用 中查看對應 APK 的權限是否有給到。
  2. 或者通過 dumpsys package 來看:
$ adb shell dumpsys package [Package_Name]

給第三方應用權限

給第三方內置應用危險權限

網上方法有很多,但是大部分都沒寫自己的系統環境,很是頭疼。
我搜集並逐一嘗試,有的有效有的無效,最終採用的方法五,趕時間的可以直接跳過去看。

方法一:framework 中修改 PackageManagerService.java
grantPermisisons 返回 true //測試有效 ,但是對於特殊權限無效

services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1447,8 +1447,13 @@ public class PackageManagerService extends IPackageManager.Stub {
                         InstallArgs args = data.args;
                         PackageInstalledInfo parentRes = data.res;  
 
+          /*
                         final boolean grantPermisisons = (args.installFlags
                                 & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+          */
+          final boolean grantPermissions = true;
+          //modified by Younix @2020.05.12,第三方應用默認給予權限
+
                         final boolean killApp = (args.installFlags
                                 & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                         final String[] grantedPermissions = args.installGrantPermissions;

方法二:修改 DatabaseHelper.java。//未測試,待驗證。
參考的 https://blog.csdn.net/wangjicong_215/article/details/71601494
記錄如下。
frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java

--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2351,6 +2351,65 @@ class DatabaseHelper extends SQLiteOpenHelper {
         if (mUserHandle == UserHandle.USER_SYSTEM) {
             loadGlobalSettings(db);
         }
+
+       //added by Younix @2020.05.18
+       loadAppOpsPermission(); 
+    }
+
+    private void loadAppOpsPermission(){
+       AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+       PackageManager pm = mContext.getPackageManager();
+
+       //String[] apkString = {"net.imoran.main.launcher"};
+
+       final String []itemString = mContext.getResources()
+                                       .getStringArray(com.android.internal.R.array.system_alert_window_permission_disable_custom_packagename);//net.imoran.main.launcher
+       for (int i = 0; i < itemString.length; i++) {
+               try {
+                       PackageInfo packageInfo = pm.getPackageInfo(itemString[i],
+                       PackageManager.GET_DISABLED_COMPONENTS |
+                       PackageManager.GET_UNINSTALLED_PACKAGES |
+                       PackageManager.GET_SIGNATURES);
+                       
+                       appOpsManager.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                                       packageInfo.applicationInfo.uid, itemString[i], AppOpsManager.MODE_ERRORED);
+               } catch (Exception e) {
+                        Log.e(TAG, "Exception when retrieving package:", e);
+               }
+       }
+
+       final String []itemStringExt = mContext.getResources()
+                     .getStringArray(com.android.internal.R.array.system_alert_window_permission_custom_packagename);
+        for (int i = 0; i < itemStringExt.length; i++) {
+            try {
+                 PackageInfo packageInfo = pm.getPackageInfo(itemStringExt[i],
+                     PackageManager.GET_DISABLED_COMPONENTS |
+                     PackageManager.GET_UNINSTALLED_PACKAGES |
+                     PackageManager.GET_SIGNATURES);
+
+                    appOpsManager.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                            packageInfo.applicationInfo.uid, itemStringExt[i], AppOpsManager.MODE_ALLOWED);                     
+            } catch (Exception e) {
+                Log.e(TAG, "Exception when retrieving package:", e);
+            }    
+        }
+
+       final String []itemStringExt1 = mContext.getResources()
+                                       .getStringArray(com.android.internal.R.array.write_settings_permission_custom_packagename);
+
+       for (int i = 0; i < itemStringExt1.length; i++) {
+           try {
+               PackageInfo packageInfo = pm.getPackageInfo(itemStringExt1[i],
+               PackageManager.GET_DISABLED_COMPONENTS |
+               PackageManager.GET_UNINSTALLED_PACKAGES |
+               PackageManager.GET_SIGNATURES);
+
+                appOpsManager.setMode(AppOpsManager.OP_WRITE_SETTINGS,
+                        packageInfo.applicationInfo.uid, itemStringExt1[i], AppOpsManager.MODE_ALLOWED);
+            } catch (Exception e) {
+               Log.e(TAG, "Exception when retrieving package:", e);
+           }    
+       }
     }

write_settings_permission_custom_packagename 需要去 xml 裏面定義一下。

方法三:RK 的補丁。修改的工程較大。
核心思想是,增加了一個方法

method public abstract boolean deleteOtherPermissions(int, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;

在這個方法裏針對指定的 package,刪掉所有權限,再增加指定權限(grantDefaultOtherAllPermissions)。
其實本質還是grantRuntimePermissionsLPw

方法四:修改 framework 中各個權限的 protectionLevel。不推薦。 測試有效,但會引起很多Bug,比如點擊 設置 裏面的某些內容的時候會閃退。
參考:
https://developer.android.google.cn/guide/topics/manifest/permission-element
https://developer.android.google.cn/reference/android/R.attr#protectionLevel
因爲保護級別包含基本權限類型以及零個或者多個標記。
“dangerous”保護級別沒有標記。

我們以 PACKAGE_USAGE_STATS 爲例。比如在core/res/AndroidManifest.xml 中看到如下信息:

2667     <!-- @SystemApi Allows an application to collect component usage
2668         ¦statistics
2669         ¦<p>Declaring the permission implies intention to use the API and the user of the
2670         ¦device can grant permission through the Settings application. -->
2671     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
2672         android:protectionLevel="signature|privileged|development|appop" />
2673     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />

關注 protectionLevel:

signature :Base permission type: a permission that the system is to grant only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user’s explicit approval.
privileged:Additional flag from base permission type: this permission can also be granted to any applications installed as privileged apps on the system image. Please avoid using this option, as the signature protection level should be sufficient for most needs and works regardless of exactly where applications are installed. This permission flag is used for certain special situations where multiple vendors have applications built in to a system image which need to share specific features explicitly because they are being built together.
development:Additional flag from base permission type: this permission can also (optionally) be granted to development applications.

所以將特殊權限修改爲危險權限後,配合方法一使用即可。

方法五:使用 grantRuntimePermissionsLPw 授予特殊權限。
根據方法三中 RK 的補丁。grantRuntimePermissionsLPw 是可以給予特殊權限的。
所以進行如下操作

--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -87,6 +87,13 @@ final class DefaultPermissionGrantPolicy {
     private static final String ATTR_NAME = "name";
     private static final String ATTR_FIXED = "fixed";
 
+    private static final Set<String> YOUNIX_PERMISSIONS = new ArraySet<>();
+    static {
+        YOUNIX_PERMISSIONS.add(Manifest.permission.PACKAGE_USAGE_STATS);
+        YOUNIX_PERMISSIONS.add(Manifest.permission.SYSTEM_ALERT_WINDOW);
+        YOUNIX_PERMISSIONS.add(Manifest.permission.WRITE_SETTINGS);
+    }
+
     private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
     static {
         PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
@@ -663,6 +670,7 @@ final class DefaultPermissionGrantPolicy {
                 grantRuntimePermissionsLPw(YounixPackage, CAMERA_PERMISSIONS, userId);
                 grantRuntimePermissionsLPw(YounixPackage, SENSORS_PERMISSIONS, userId);
                 grantRuntimePermissionsLPw(YounixPackage, STORAGE_PERMISSIONS, userId);
+       grantRuntimePermissionsLPw(YounixPackage, YOUNIX_PERMISSIONS, userId);
             }else{
                 Log.d(TAG, "YounixPackage >> null");
             }

第三方應用危險權限申請 PERMISSIONS_STORAGE

原理

 674     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
 675         android:permissionGroup="android.permission-group.STORAGE"
 676         android:label="@string/permlab_sdcardRead"
 677         android:description="@string/permdesc_sdcardRead"
 678         android:protectionLevel="dangerous" />

關注 protectionLevel:dangerous

Base permission type: a higher-risk permission that would give a requesting application access to private user data or control over the device that can negatively impact the user. Because this type of permission introduces potential risk, the system may not automatically grant it to the requesting application. For example, any dangerous permissions requested by an application may be displayed to the user and require confirmation before proceeding, or some other approach may be taken to avoid the user automatically allowing the use of such facilities.

測試APKdemo

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};
			
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestDangerousPermission();
        //requestOverlayPermission();
        //requestWriteSettings();
    }
	
	    private void requestDangerousPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
            }
        }
    }
	
	    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (int i = 0; i < permissions.length; i++) {
                Log.i("MainActivity", "申請的權限爲:" + permissions[i] + ",申請結果:" + grantResults[i]);
            }
        }

    }

第三方應用特殊權限(懸浮窗)申請 SYSTEM_ALERT_WINDOW

原理

1726     <!-- Allows an app to create windows using the type
1727         ¦{@link android.view.WindowManager.LayoutParams#TYPE_SYSTEM_ALERT},
1728         ¦shown on top of all other apps.  Very few apps
1729         ¦should use this permission; these windows are intended for
1730         ¦system-level interaction with the user.
1731 
1732         ¦<p class="note"><strong>Note:</strong> If the app
1733         ¦targets API level 23 or higher, the app user must explicitly grant
1734         ¦this permission to the app through a permission management screen. The app requests
1735         ¦the user's approval by sending an intent with action
1736         ¦{@link android.provider.Settings#ACTION_MANAGE_OVERLAY_PERMISSION}.
1737         ¦The app can check whether it has this authorization by calling
1738         ¦{@link android.provider.Settings#canDrawOverlays
1739         ¦Settings.canDrawOverlays()}.
1740         ¦<p>Protection level: signature -->
1741     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
1742         android:label="@string/permlab_systemAlertWindow"
1743         android:description="@string/permdesc_systemAlertWindow"
1744         android:protectionLevel="signature|preinstalled|appop|pre23|development" />

關注 protectionLevel:signature|preinstalled|appop|pre23|development
signature:簽名後可以自動給於此權限
preinstalled:這個權限可以給系統中預安裝的應用程序
appop:此權限與用於控制訪問權限的應用操作緊密相關
pre23:如果是 Build.VERSION_CODES.M 以下的 SDK,可以自動授予
development:這個權限可以給予開發中的應用程序

測試APKdemo

參考https://blog.csdn.net/zhangyong7112/article/details/55097257

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //myRequetPermission();
        requestOverlayPermission();
        //requestWriteSettings();
    }
	
	    private void requestOverlayPermission() {
        //Settings.canDrawOverlays(this) 檢查是否有懸浮窗權限
        if(!Settings.canDrawOverlays(this)){
            //沒有懸浮窗權限,跳轉申請
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            startActivity(intent);
        }
    }

可以看到,不會彈出懸浮窗了。權限被直接給予。

第三方應用特殊權限(修改系統設置)申請 WRITE_SETTINGS

原理

略,各種標誌前面都寫了

測試 APK demo

這個權限比較特殊,App 默認是會跳轉到設置的系統界面中去,需要用戶手動打開開關進行設置。
代碼參考 https://www.jianshu.com/p/c3908cb3554d

    /**
     * 申請權限
     */
    private void requestWriteSettings()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            //大於等於23 請求權限
            if ( !Settings.System.canWrite(getApplicationContext()))
            {//沒有權限,進行申請
                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
                intent.setData(Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS );
            } else {//有了權限,具體的動作(比如調整系統亮度)
                        Settings.System.putInt(getContentResolver(),Settings.System.SCREEN_BRIGHTNESS, progress);
			}
        }else{
            //小於23直接設置
        }
    }
	
	    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_WRITE_SETTINGS)
        {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
            {
                  //Settings.System.canWrite方法檢測授權結果
                if (Settings.System.canWrite(getApplicationContext()))
                {
                    T.show("獲取了權限");
                }else{
                    T.show("您拒絕了權限");
                }
            }
        }

    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章