Android 11 Google针对权限系统又加了更多的限制,比如1.权限的单次授权;2.某个app长时间不使用,权限会被自动更新/重置!
关于app的权限重置
Android Framework权限篇四之AppOps机制
Settings里面关于app权限重置的switch 流程
./packages/apps/Settings/src/com/android/settings/applications/appinfo/AppPermissionPreferenceController.java
...
Intent.ACTION_AUTO_REVOKE_PERMISSIONS, INVALID_SESSION_ID
...
./packages/apps/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
private void addAutoRevokePreferences(PreferenceScreen screen) {
Context context = screen.getPreferenceManager().getContext();
PreferenceCategory autoRevokeCategory = new PreferenceCategory(context);
autoRevokeCategory.setKey(AUTO_REVOKE_CATEGORY_KEY);
screen.addPreference(autoRevokeCategory);
SwitchPreference autoRevokeSwitch = new SwitchPreference(context);
autoRevokeSwitch.setOnPreferenceClickListener((preference) -> {
mViewModel.setAutoRevoke(autoRevokeSwitch.isChecked());
return true;
});
...
./packages/apps/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt
fun setAutoRevoke(enabled: Boolean) {
GlobalScope.launch(IPC) {
val aom = app.getSystemService(AppOpsManager::class.java)!!
val uid = LightPackageInfoLiveData[packageName, user].getInitializedValue()?.uid
if (uid != null) {
Log.i(LOG_TAG, "sessionId $sessionId setting auto revoke enabled to $enabled for" +
"$packageName $user")
val tag = if (enabled) {
APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_ENABLED
} else {
APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION__ACTION__SWITCH_DISABLED
}
PermissionControllerStatsLog.write(
APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION, sessionId, uid, packageName,
tag)
val mode = if (enabled) {
MODE_ALLOWED
} else {
MODE_IGNORED
}
aom.setUidMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, uid, mode)
}
}
}
./frameworks/base/core/java/android/app/AppOpsManager.java
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(int code, int uid, @Mode int mode) {
try {
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//或者
/** @hide */
@UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//关于 op code 都是大写OP为首
/** @hide Auto-revoke app permissions if app is unused for an extended period */
public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
AppProtoEnums.APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED;
//adb 语法
AppOps service (appops) commands:
help
Print this help text.
start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> <OP>
Starts a given operation for a particular application.
stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> <OP>
Stops a given operation for a particular application.
set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>
Set the mode for a particular application and operation.
get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> [<OP>]
Return the mode for a particular application and optional operation.
query-op [--user <USER_ID>] <OP> [<MODE>]
Print all packages that currently have the given op in the given mode.
reset [--user <USER_ID>] [<PACKAGE>]
Reset the given application or all applications to default modes.
write-settings
Immediately write pending changes to storage.
read-settings
Read the last written settings, replacing current state in RAM.
options:
<PACKAGE> an Android package name or its UID if prefixed by --uid
<OP> an AppOps operation.
<MODE> one of allow, ignore, deny, or default
<USER_ID> the user id under which the package is installed. If --user is
not specified, the current user is assumed.
//给予安装位置来源apk权限
adb shell appops set com.android.settings REQUEST_INSTALL_PACKAGES allow
不过只能给Manifest关联的权限, AppOpsManager的sOpPerms[]数组
./frameworks/base/core/java/android/app/AppOpsManager.java
关于权限的几种修改方案,都是套路:
最先是要找到你需要操作的权限是啥,可以在AppOpsManager的数组里面查询!
方案一:源头操作
./frameworks/base/core/java/android/app/AppOpsManager.java
/**
* This specifies the default mode for each operation.
*/
private static int[] sOpDefaultMode = new int[] {
AppOpsManager.MODE_ALLOWED, // COARSE_LOCATION
AppOpsManager.MODE_ALLOWED, // FINE_LOCATION
AppOpsManager.MODE_ALLOWED, // GPS
...
- AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+ AppOpsManager.MODE_IGNORED, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
...
方案二:系统服务拦截
./frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java
private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
Op op = ops.get(code);
if (op == null) {
if (!edit) {
return null;
}
op = new Op(ops.uidState, ops.packageName, code, uid);
ops.put(code, op);
}
//add text
if(ops.packageName.equals("com.xxx")){
Op op1 = new Op(ops.uidState, ops.packageName, AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,uid);
op1.mode = AppOpsManager.MODE_IGNORED;//MODE_ALLOWED
ops.put(op1.op, op1);
}
//add text
if (edit) {
scheduleWriteLocked();
}
return op;
}
方案三:参考
private void setSomeAppPermission(){
int uid = 0;
//大部分系统app才能读到
/*PackageManager packageManager = mContext.getPackageManager();
try {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo("com.xxx",0);
uid = applicationInfo.uid;
}catch (Exception e){
}*/
AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
appOpsManager.setUidMode(AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, 10136, AppOpsManager.MODE_IGNORED);
/*appOpsManager.setMode(AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
10136, "com.xxx", AppOpsManager.MODE_IGNORED);*/
}