android 11安装apk自动获取权限

由于android 11以上版本对于读写权限的进一步限制,安装的apk获取权限的流程又加了一步,对于客户来说多半步也算复杂,Android 保存/读取本地SD卡文件(兼容Android 13)

一、打开全部权限

根据之前的经验,在安装流程后打开全部权限即可。

Index: frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
===================================================================
--- frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java	(版本 2518)
+++ frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java	(工作副本)
@@ -221,6 +221,8 @@
 import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
 // @}
 
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+
 final class InstallPackageHelper {
 
@@ -281,6 +283,7 @@
     private final ViewCompiler mViewCompiler;
     private final SharedLibrariesImpl mSharedLibraries;
     private final PackageManagerServiceInjector mInjector;
+    private final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
 
     // TODO(b/198166813): remove PMS dependency
     InstallPackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
@@ -310,6 +313,7 @@
         mAlwaysAllowInstallApks = mContext.getResources().getStringArray(
                 com.android.internal.R.array.config_always_allowed_install_apks);
+        mDefaultPermissionPolicy =  new DefaultPermissionGrantPolicy(mContext);
     }
 
     InstallPackageHelper(PackageManagerService pm) {
@@ -388,6 +392,19 @@
                 // Attempt the transparent shared UID migration
                 mPm.mSettings.convertSharedUserSettingsLPw(sharedUserSetting);
             }
+        } else {
+            final Object obj = mPm.mSettings.getSettingLPr(pkgSetting.getAppId());
+            if (obj instanceof SharedUserSetting) {
+                try {
+                    synchronized (mPm.mLock) {
+                        mPm.mSettings.registerAppIdLPw(pkgSetting, true);
+                        Slog.d(TAG, "The AppId of " + pkgSetting.getName() + " changes from "
+                            + ((SharedUserSetting)obj).getAppId() + " to " + pkgSetting.getAppId());
+                    }
+                } catch (PackageManagerException e) {
+                    Slog.e(TAG, "register new app id for " + pkgSetting + " error:", e);
+                }
+            }
         }
         if (reconciledPkg.mInstallArgs != null
                 && reconciledPkg.mInstallArgs.mForceQueryableOverride) {
@@ -2386,9 +2403,25 @@
                     // The caller explicitly specified INSTALL_ALL_USERS flag.
                     // Thus, updating the settings to install the app for all users.
                     for (int currentUserId : allUsers) {
-                        ps.setInstalled(true, currentUserId);
-                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
+                        // If the app is already installed for the currentUser,
+                        // keep it as installed as we might be updating the app at this place.
+                        // If not currently installed, check if the currentUser is restricted by
+                        // DISALLOW_INSTALL_APPS or DISALLOW_DEBUGGING_FEATURES device policy.
+                        // Install / update the app if the user isn't restricted. Skip otherwise.
+                        final boolean installedForCurrentUser = ArrayUtils.contains(
+                                installedForUsers, currentUserId);
+                        final boolean restrictedByPolicy =
+                                mPm.isUserRestricted(currentUserId,
+                                        UserManager.DISALLOW_INSTALL_APPS)
+                                || mPm.isUserRestricted(currentUserId,
+                                        UserManager.DISALLOW_DEBUGGING_FEATURES);
+                        if (installedForCurrentUser || !restrictedByPolicy) {
+                            ps.setInstalled(true, currentUserId);
+                            ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
                                 installerPackageName);
+                        } else {
+                            ps.setInstalled(false, currentUserId);
+                        }
                     }
                 }
 
@@ -2505,6 +2538,18 @@
         }
     }
 
+    private void enableManageExternalStorage(String pkgName, int appId) {
+        final AppOpsManager appOpsManager = mPm.mContext.getSystemService(AppOpsManager.class);
+        final int[] allUsersList = mPm.mUserManager.getUserIds();
+        for (int userId : allUsersList) {
+            final int uid = UserHandle.getUid(userId, appId);
+            appOpsManager.setMode(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE,
+                    uid,
+                    pkgName,
+                    AppOpsManager.MODE_ALLOWED);
+        }
+    }
+
     /**
      * On successful install, executes remaining steps after commit completes and the package lock
      * is released. These are typically more expensive or require calls to installd, which often
@@ -2938,6 +2983,11 @@
         final boolean removedBeforeUpdate = (pkgSetting == null)
                 || (pkgSetting.isSystem() && !pkgSetting.getPath().getPath().equals(
                 res.mPkg.getPath()));
+        mDefaultPermissionPolicy.grantAppRuntimePermissions(packageName);
+        int resAppId = UserHandle.getAppId(res.mUid);
+        enableManageExternalStorage(packageName, resAppId);
         if (succeeded && removedBeforeUpdate) {
             Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
                     + "could be executed");
Index: frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
===================================================================
--- frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java	(版本 2518)
+++ frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java	(工作副本)
@@ -287,6 +287,8 @@
 import com.android.server.pm.pkg.component.ParsedUsesPermission;
 // @}
 
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+
 /**
  * Keep track of all those APKs everywhere.
  * <p>
@@ -864,7 +866,7 @@
 
     // Internal interface for permission manager
     final PermissionManagerServiceInternal mPermissionManager;
-
+    final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
     @Watched
     final ComponentResolver mComponentResolver;
 
@@ -1649,6 +1651,7 @@
         mLock = injector.getLock();
         mPackageStateWriteLock = mLock;
         mPermissionManager = injector.getPermissionManagerServiceInternal();
+        mDefaultPermissionPolicy =  new DefaultPermissionGrantPolicy(mContext);
         mSettings = injector.getSettings();
         mUserManager = injector.getUserManagerService();
         mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
@@ -1780,6 +1783,7 @@
         mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
         mComponentResolver = injector.getComponentResolver();
         mPermissionManager = injector.getPermissionManagerServiceInternal();
+        mDefaultPermissionPolicy =  new DefaultPermissionGrantPolicy(mContext);
         mSettings = injector.getSettings();
         mIncrementalManager = mInjector.getIncrementalManager();
         mDefaultAppProvider = mInjector.getDefaultAppProvider();
@@ -4485,6 +4489,10 @@
         final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token,
                 didLaunch ? 1 : 0);
         mHandler.sendMessage(msg);
+        PostInstallData data = mRunningInstalls.get(msg.arg1);
+        InstallArgs args = data.args;
+        String packageName = args.mInstallSource.installerPackageName;
+        mDefaultPermissionPolicy.grantAppRuntimePermissions(packageName);
     }
 
     void checkPackageStartable(@NonNull Computer snapshot, @NonNull String packageName,
Index: frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
===================================================================
--- frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java	(版本 2518)
+++ frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java	(工作副本)
@@ -87,6 +87,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import android.os.Binder;
 
 // CTA Feature: add permission @{
 import android.cta.CtaPermFactory;
@@ -104,7 +105,7 @@
  * to have an interface defined in the package manager but have the impl next to other
  * policy stuff like PhoneWindowManager
  */
-final class DefaultPermissionGrantPolicy {
+final public class DefaultPermissionGrantPolicy {
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
@@ -336,7 +337,7 @@
         }
     };
 
-    DefaultPermissionGrantPolicy(@NonNull Context context) {
+    public DefaultPermissionGrantPolicy(@NonNull Context context) {
         mContext = context;
         HandlerThread handlerThread = new ServiceThread(TAG,
                 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
@@ -437,6 +438,43 @@
         grantRuntimePermissionsForSystemPackage(pm, userId, pkg, null);
     }
 
+    private void grantRuntimePermissionsForPackage(int userId, PackageInfo pkg) {
+        Set<String> permissions = new ArraySet<>();
+        DelayingPackageManagerCache pm = new DelayingPackageManagerCache();
+        String [] pkgPermissions = pkg.requestedPermissions;
+        if(pkgPermissions== null || pkgPermissions.length==0)return;
+        for (String permission :  pkgPermissions) {
+            final PermissionInfo perm = pm.getPermissionInfo(permission);
+            if (perm == null) {
+                continue;
+            }
+            if (perm.isRuntime()) {
+                Log.i(TAG, "Granting run permission="+permission);
+                permissions.add(permission);
+            }
+        }
+        if (!permissions.isEmpty()) {
+            grantRuntimePermissions(pm,pkg, permissions, true, userId);
+        }
+        pm.apply();
+    }
+
+    public void grantAppRuntimePermissions(String pkgName) {
+        Log.i(TAG, "grantAppRuntimePermissions--pkgName:"+pkgName);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            final PackageInfo pkg = NO_PM_CACHE.getPackageInfo(pkgName);
+            Log.i(TAG, "pkg=" + pkg);
+            if (pkg != null) {
+                grantRuntimePermissionsForPackage(UserHandle.USER_SYSTEM, pkg);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void grantRuntimePermissionsForSystemPackage(PackageManagerWrapper pm,
             int userId, PackageInfo pkg, Set<String> filterPermissions) {
         if (ArrayUtils.isEmpty(pkg.requestedPermissions)) {
@@ -497,13 +535,13 @@
             pm.addPackageInfo(pkg.packageName, pkg);
 
-            if (!pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
-                    || !doesPackageSupportRuntimePermissions(pkg)
-                    || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
+            if (/*!pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
+                    || !doesPackageSupportRuntimePermissions(pkg)
+                    || */ArrayUtils.isEmpty(pkg.requestedPermissions)) {
                 continue;
             }
             

验证结果显示:
mDefaultPermissionPolicy.grantAppRuntimePermissions(packageName);为获取除android.permission.MANAGE_EXTERNAL_STORAGE外的所有权限
为了解决android.permission.MANAGE_EXTERNAL_STORAGE,需要额外添加enableManageExternalStorage(packageName, resAppId);

二、针对性打开

仅打开MANAGE_EXTERNAL_STORAGE权限

Index: frameworks/base/core/java/android/app/AppOpsManager.java
===================================================================
--- frameworks/base/core/java/android/app/AppOpsManager.java	(版本 2390)
+++ frameworks/base/core/java/android/app/AppOpsManager.java	(工作副本)
@@ -2856,7 +2856,7 @@
             AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
             AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION
             AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
-            AppOpsManager.MODE_DEFAULT, // MANAGE_EXTERNAL_STORAGE
+            AppOpsManager.MODE_ALLOWED, // MANAGE_EXTERNAL_STORAGE
             AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
             AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
             AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS

三、验证DEMO

MainActivity.java

package com.basewin.permissiontest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static final String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    private boolean havePermission = false;
    private AlertDialog dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkPermission();
    }

    private void checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (!Environment.isExternalStorageManager()) {
                if (dialog != null) {
                    dialog.dismiss();
                    dialog = null;
                }
                dialog = new AlertDialog.Builder(this)
                        .setTitle("HINT")
                        .setMessage("Please open permission!")
                        .setNegativeButton("cancel", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        })
                        .setPositiveButton("confirm", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                                intent.setData(Uri.parse("package:"+MainActivity.this.getPackageName()));
                                startActivity(intent);
                            }
                        }).create();
                dialog.show();
            } else {
                havePermission = true;
            }
        } else {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    if (dialog != null) {
                        dialog.dismiss();
                        dialog = null;
                    }
                    dialog = new AlertDialog.Builder(this)
                            .setTitle("HINT")
                            .setMessage("Please open permission!")
                            .setPositiveButton("confirm", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                    ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                                }
                            }).create();
                    dialog.show();
                } else {
                    havePermission = true;
                }
            } else {
                havePermission = true;
            }
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    havePermission = true;
                } else {
                    havePermission = false;
                }
                return;
        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.basewin.permissiontest">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.PermissionTest"
        android:requestLegacyExternalStorage="true"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值