柚子快報(bào)邀請(qǐng)碼778899分享:Android 通知訪問(wèn)權(quán)限
柚子快報(bào)邀請(qǐng)碼778899分享:Android 通知訪問(wèn)權(quán)限
問(wèn)題背景
客戶反饋手機(jī)掃描三方運(yùn)動(dòng)手表,下載app安裝后,通知訪問(wèn)權(quán)限打不開。 點(diǎn)擊提示“受限設(shè)置” “出于安全考慮,此設(shè)置目前不可用”。
問(wèn)題分析
1、setting界面搜“授予通知訪問(wèn)權(quán)限”,此按鈕灰色不可點(diǎn)擊,點(diǎn)擊提示“受限設(shè)置” “出于安全考慮,此設(shè)置目前不可用”。 2、“授予通知訪問(wèn)權(quán)限”界面在setting中的notification_access_permission_details.xml 按鈕類型: RestrictedSwitchPreference 對(duì)應(yīng)controller: ApprovalPreferenceController updateState中跟蹤按鈕狀態(tài)
public void updateState(
@NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
if (mAppOpsManager == null) {
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
}
final int mode = mAppOpsManager.noteOpNoThrow(
AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
uid, packageName);
final boolean ecmEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
if (!isEnableAllowed && !isEnabled) {
setEnabled(false);
} else if (isEnabled) {
setEnabled(true);
} else if (appOpsAllowed && isDisabledByAppOps()) {
setEnabled(true);
} else if (!appOpsAllowed){
setDisabledByAppOps(true);
}
}
config_enhancedConfirmationModeEnabled這個(gè)值是framework寫死的值。 mode = mAppOpsManager.noteOpNoThrow這個(gè)是根據(jù)apk動(dòng)態(tài)變化的。跟蹤這個(gè)值異常的原因。
3、AppOpsManager.java noteOpNoThrow AppOpsService.java noteOperation --> noteOperationUnchecked 打開log開關(guān),單編services。
AppOps system_server D noteOperation: package 000 com.huawei.health
AppOps system_server D noteOperation: package 222 com.huawei.health
AppOps system_server D noteOperationUnchecked: package com.huawei.health
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName com.huawei.health op: 119 userId: 0
//默認(rèn)值是0
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 222 com.huawei.health AppOpsManager.opToDefaultMode(op): 0
//實(shí)際拿到是2
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 444 com.huawei.health opModes.get(op, AppOpsManager.opToDefaultMode(op): 2
AppOps system_server D noteOperationUnchecked: ops 2
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName com.huawei.health op: 119 userId: 0
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 222 com.huawei.health AppOpsManager.opToDefaultMode(op): 0
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 444 com.huawei.health opModes.get(op, AppOpsManager.opToDefaultMode(op): 2
AppOps system_server D noteOperationUnchecked: op 2
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName com.huawei.health op: 119 userId: 0
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 222 com.huawei.health AppOpsManager.opToDefaultMode(op): 0
LegacyAppOpsServiceInterfaceImpl system_server W getPackageMode packageName 444 com.huawei.health opModes.get(op, AppOpsManager.opToDefaultMode(op): 2
//reject #2 權(quán)限被拒絕
AppOps system_server D noteOperation: reject #2 for code 119 (119) uid 10243 package com.huawei.health flags: s
AppOps system_server D noteOperationUnchecked: package 555 com.huawei.health
4、AppOpsManager.opToDefaultMode
public static @Mode int opToDefaultMode(int op) {
return sAppOpInfos[op].defaultMode;
}
//sAppOpInfos是個(gè)內(nèi)部數(shù)組,存的好多權(quán)限的默認(rèn)值
//119 OP_ACCESS_RESTRICTED_SETTINGS 默認(rèn)0 MODE_ALLOWED
new AppOpInfo.Builder(OP_ACCESS_RESTRICTED_SETTINGS, OPSTR_ACCESS_RESTRICTED_SETTINGS,
"ACCESS_RESTRICTED_SETTINGS").setDefaultMode(AppOpsManager.MODE_ALLOWED)
.setDisableReset(true).setRestrictRead(true).build()
5、opModes.get(op, AppOpsManager.opToDefaultMode(op): 2 設(shè)置2的地方:
setMode packageName com.huawei.health op: 119 userId: 10243 # java.lang.Throwable
at com.android.server.appop.AppOpsService$Op.setMode(AppOpsService.java:637)
at com.android.server.appop.AppOpsService.setMode(AppOpsService.java:2006)
at com.android.server.appop.AppOpsService.setMode(AppOpsService.java:1973)
at android.app.AppOpsManager.setMode(AppOpsManager.java:7609)
at com.android.server.pm.InstallPackageHelper.enableRestrictedSettings(InstallPackageHelper.java:2514)
at com.android.server.pm.InstallPackageHelper.updateSettingsInternalLI(InstallPackageHelper.java:2493)
at com.android.server.pm.InstallPackageHelper.updateSettingsLI(InstallPackageHelper.java:2277)
at com.android.server.pm.InstallPackageHelper.commitPackagesLocked(InstallPackageHelper.java:2246)
at com.android.server.pm.InstallPackageHelper.installPackagesLI(InstallPackageHelper.java:1120)
at com.android.server.pm.InstallPackageHelper.installPackagesTraced(InstallPackageHelper.java:987)
at com.android.server.pm.InstallingSession.processApkInstallRequests(InstallingSession.java:547)
at com.android.server.pm.InstallingSession.processInstallRequests(InstallingSession.java:536)
at com.android.server.pm.InstallingSession.lambda$processPendingInstall$0(InstallingSession.java:295)
at com.android.server.pm.InstallingSession.$r8$lambda$tqRjKCgCJYNNnnY7Qw5M5BHLup8(InstallingSession.java:0)
at com.android.server.pm.InstallingSession$$ExternalSyntheticLambda2.run(R8$$SyntheticClass:0)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:243)
at android.os.Looper.loop(Looper.java:338)
at android.os.HandlerThread.run(HandlerThread.java:67)
at com.android.server.ServiceThread.run(ServiceThread.java:46)
setPackageMode packageName com.huawei.health op: 119 mode: 2
setPackageMode packageModes.put packageName com.huawei.health op: 119 mode: 2
6、安裝應(yīng)用時(shí)就設(shè)置了限制: InstallPackageHelper.enableRestrictedSettings
private void enableRestrictedSettings(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_ACCESS_RESTRICTED_SETTINGS,
uid,
pkgName,
AppOpsManager.MODE_ERRORED);
}
}
//調(diào)用的地方
// Apply restricted settings on potentially dangerous packages.
if (installRequest.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
|| installRequest.getPackageSource()
== PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
enableRestrictedSettings(pkgName, pkg.getUid());
}
...
//PackageInstaller中
/**
* Code indicating that the package being installed comes from a local file on the device. A
* file manager that is facilitating the installation of an APK file would use this.
*/
public static final int PACKAGE_SOURCE_LOCAL_FILE = 3;
/**
* Code indicating that the package being installed comes from a file that was downloaded to
* the device by the user. For use in place of {@link #PACKAGE_SOURCE_LOCAL_FILE} when the
* installer knows the package was downloaded.
*/
public static final int PACKAGE_SOURCE_DOWNLOADED_FILE = 4;
可以看出,只有當(dāng)是本地apk文件安裝時(shí),才會(huì)設(shè)置此限制。
解決方案
此彈框主要是為了防止未知來(lái)源的apk文件請(qǐng)求權(quán)限,正規(guī)途徑安裝不受影響。 用戶也可以在應(yīng)用信息中手動(dòng)解除限制。 1、打開受限設(shè)置 setting—app management—app list—“ xxx Health”—“…”—“allow restricted settings” 這里其實(shí)也是調(diào)用的setMode MODE_ALLOWED 2、通過(guò)play store安裝。(或者adb 繞過(guò)上面的if就可以)
如何讓自己的應(yīng)用顯示在這里
注冊(cè)action android:name=“android.service.notification.NotificationListenerService” setting會(huì)自動(dòng)加載進(jìn)去。
android:name=".NotificationListener" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" android:enabled="true" android:exported="true"> android:name="android.service.notification.NotificationListenerService" />
柚子快報(bào)邀請(qǐng)碼778899分享:Android 通知訪問(wèn)權(quán)限
好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。