編輯:關於Android編程
一、權限控制組:
Permission Group
Permissions
CALENDAR
· READ_CALENDAR
· WRITE_CALENDAR
CAMERA
· CAMERA
CONTACTS
· READ_CONTACTS
· WRITE_CONTACTS
· GET_ACCOUNTS
LOCATION
· ACCESS_FINE_LOCATION
· ACCESS_COARSE_LOCATION
MICROPHONE
· RECORD_AUDIO
PHONE
· READ_PHONE_STATE
· CALL_PHONE
· READ_CALL_LOG
· WRITE_CALL_LOG
· ADD_VOICEMAIL
· USE_SIP
· PROCESS_OUTGOING_CALLS
SENSORS
· BODY_SENSORS
SMS
· SEND_SMS
· RECEIVE_SMS
· READ_SMS
· RECEIVE_WAP_PUSH
· RECEIVE_MMS
STORAGE
· READ_EXTERNAL_STORAGE
· WRITE_EXTERNAL_STORAGE
來看看checkUidPermission方法做了一些什麼:
@Override public int checkUidPermission(String permName, int uid){ //多用戶檢測 final int userId = UserHandle.getUserId(uid); if (!sUserManager.exists(userId)) { returnPackageManager.PERMISSION_DENIED; } synchronized (mPackages) { Object obj =mSettings.getUserIdLPr(UserHandle.getAppId(uid)); if (obj != null) { final SettingBase ps =(SettingBase) obj; final PermissionsStatepermissionsState = ps.getPermissionsState(); if (permissionsState.hasPermission(permName,userId)) { returnPackageManager.PERMISSION_GRANTED; } // Special case:ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION if(Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) &&permissionsState .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION,userId)) { returnPackageManager.PERMISSION_GRANTED; } } else { ArraySet perms =mSystemPermissions.get(uid); if (perms != null) { if(perms.contains(permName)) { returnPackageManager.PERMISSION_GRANTED; } if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName)&& perms .contains(Manifest.permission.ACCESS_FINE_LOCATION)) { returnPackageManager.PERMISSION_GRANTED; } } } } returnPackageManager.PERMISSION_DENIED; }
一眼掃過去,關鍵中關鍵在於mSettings裡面保存的這個SettingBase對象,它記錄了PermissionsState也就是權限的授予情況。先不直接分析,我們從另外一邊來看,看看是如何授權的。
授權有兩個地方,一個是設置裡面的入口,還有一個是申請權限彈框界面的入口,代碼都在PackageInstaller裡面,分別是ManagePermissionsActivity和GrantPermissionsActivity。就不仔細分析了最終授權和撤銷都是在AppPermissionGroup這裡實現的,grantRuntimePermissions和revokeRuntimePermissions兩個方法。最終生效的代碼還是在PackageManagerService裡面。
@Override public void grantRuntimePermission(String packageName, String name,final int userId) { if (!sUserManager.exists(userId)) { Log.e(TAG, "No such user:" + userId); return; } //授予權限是需要GRANT_RUNTIME_PERMISSIONS權限的 mContext.enforceCallingOrSelfPermission( android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, "grantRuntimePermission"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "grantRuntimePermission"); final int uid; final SettingBase sb; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { throw newIllegalArgumentException("Unknown package: " + packageName); } final BasePermission bp = mSettings.mPermissions.get(name); if (bp == null) { throw newIllegalArgumentException("Unknown permission: " + name); } enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp); uid = UserHandle.getUid(userId, pkg.applicationInfo.uid); sb = (SettingBase) pkg.mExtras; if (sb == null) { throw newIllegalArgumentException("Unknown package: " + packageName); } final PermissionsState permissionsState = sb.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(name, userId); //fix的權限是不能修改的 if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { throw newSecurityException("Cannot grant system fixed permission: " + name + " forpackage: " + packageName); } if (bp.isDevelopment()) { // Development permissions mustbe handled specially, since they are not // normal runtimepermissions. For now they apply to allusers. if(permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { scheduleWriteSettingsLocked(); } return; } final int result = permissionsState.grantRuntimePermission(bp,userId); switch (result) { casePermissionsState.PERMISSION_OPERATION_FAILURE: { return; } casePermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { final int appId =UserHandle.getAppId(pkg.applicationInfo.uid); mHandler.post(newRunnable() { @Override public void run() { killUid(appId,userId, KILL_APP_REASON_GIDS_CHANGED); } }); } break; } mOnPermissionChangeListeners.onPermissionsChanged(uid); // Not critical if that is lost - app has to request again. mSettings.writeRuntimePermissionsForUserLPr(userId,false); } // Only need to do this if user is initialized. Otherwise it's a newuser // and there are no processes running as the user yet and there's noneed // to make an expensive call to remount processes for the changedpermissions. if (READ_EXTERNAL_STORAGE.equals(name) ||WRITE_EXTERNAL_STORAGE.equals(name)) { final long token = Binder.clearCallingIdentity(); try { if(sUserManager.isInitialized(userId)) { MountServiceInternalmountServiceInternal = LocalServices.getService( MountServiceInternal.class); mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName); } } finally { Binder.restoreCallingIdentity(token); } } } @Override public void revokeRuntimePermission(String packageName, String name, intuserId) { if (!sUserManager.exists(userId)) { Log.e(TAG, "No such user:" + userId); return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, "revokeRuntimePermission"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "revokeRuntimePermission"); final int appId; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { throw newIllegalArgumentException("Unknown package: " + packageName); } final BasePermission bp = mSettings.mPermissions.get(name); if (bp == null) { throw newIllegalArgumentException("Unknown permission: " + name); } enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp); SettingBase sb = (SettingBase) pkg.mExtras; if (sb == null) { throw newIllegalArgumentException("Unknown package: " + packageName); } final PermissionsState permissionsState = sb.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(name, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { throw newSecurityException("Cannot revoke system fixed permission: " + name + " forpackage: " + packageName); } if (bp.isDevelopment()) { // Development permissions mustbe handled specially, since they are not // normal runtimepermissions. For now they apply to allusers. if(permissionsState.revokeInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { scheduleWriteSettingsLocked(); } return; } if (permissionsState.revokeRuntimePermission(bp,userId) == PermissionsState.PERMISSION_OPERATION_FAILURE) { return; } mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid); // Critical, after this call app should never have the permission. mSettings.writeRuntimePermissionsForUserLPr(userId, true); appId = UserHandle.getAppId(pkg.applicationInfo.uid); } killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); }
大家咋一看這三個方法,是不是對裡面的PermissionsState是不是同一個東西產生懷疑,別想多了,他們就是一個玩意,有興趣的可以看看這個方法Settings.getPackageLPw這個方法,這是在安裝應用掃描的時候scanPackageDirtyLI方法調用的,裡面可以看到Settings類中的mUserIds、mPackages裡面存的value還有PackageManagerService中的mPackages.pkg. mExtras都是同一個玩意奏是個PackageSetting。其實上面說的檢查權限的流程是本來就有的,差異,差異,差異僅在於可以動態修改:也就是修改PermissionState的mGranted值。
最後大家可能在
這裡看到讀寫存儲的權限變化還需要另外一個服務(MountServiceInternal)的策略變化,這個以後在分析,先埋伏一下。
四、默認授予規則:
默認授予是在PackageManagerService執行systemReady的時候執行的,主要是這個類DefaultPermissionGrantPolicy,名字也一目了然。
public void grantDefaultPermissions(int userId) { //針對系統組件和Privileged的應用做默認權限的處理 grantPermissionsToSysComponentsAndPrivApps(userId); //對符合系統處理原則的模塊進行默認權限的處理 grantDefaultSystemHandlerPermissions(userId); } private voidgrantPermissionsToSysComponentsAndPrivApps(int userId) { Log.i(TAG, "Granting permissionsto platform components for user " + userId); synchronized (mService.mPackages) { for (PackageParser.Package pkg :mService.mPackages.values()) { //遍歷所有的package,如果是系統組的,或者是platform簽名的特權應用和persistent應用就可以默認授予 if(!isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg) ||!doesPackageSupportRuntimePermissions(pkg) ||pkg.requestedPermissions.isEmpty()) { continue; } Set permissions =new ArraySet<>(); final int permissionCount =pkg.requestedPermissions.size(); for (int i = 0; i String permission =pkg.requestedPermissions.get(i); BasePermission bp =mService.mSettings.mPermissions.get(permission); if (bp != null &&bp.isRuntime()) { permissions.add(permission); } } if (!permissions.isEmpty()) { grantRuntimePermissionsLPw(pkg, permissions, true, userId); } } } } privatebooleanisSysComponentOrPersistentPlatformSignedPrivAppLPr(PackageParser.Package pkg) { //小於10000的系統進程 if(UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) { return true; } if(!pkg.isPrivilegedApp()) { //這裡我心存疑惑不確定這一類APP的范圍 return false; } //下面是對當前禁用的APP如果不是persistent的就不用授予了 PackageSetting sysPkg =mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName); if(sysPkg != null) { if((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0){ return false; } } else if((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { return false; } //必須還要滿足platform簽名 returnPackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH; } private voidgrantRuntimePermissionsLPw(PackageParser.Package pkg, Setpermissions, boolean systemFixed, booleanoverrideUserChoice, int userId) { if (pkg.requestedPermissions.isEmpty()){ return; } List requestedPermissions= pkg.requestedPermissions; Set grantablePermissions= null; if (pkg.isUpdatedSystemApp()) { PackageSetting sysPs =mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName); if (sysPs != null) { if(sysPs.pkg.requestedPermissions.isEmpty()) { return; } if(!requestedPermissions.equals(sysPs.pkg.requestedPermissions)) { grantablePermissions = newArraySet<>(requestedPermissions); requestedPermissions =sysPs.pkg.requestedPermissions; } } } final int grantablePermissionCount =requestedPermissions.size(); for (int i = 0; i String permission =requestedPermissions.get(i); // If there is a disabled systemapp it may request a permission the updated // version ot the data partitiondoesn't, In this case skip the permission. if (grantablePermissions != null&& !grantablePermissions.contains(permission)) { continue; } if(permissions.contains(permission)) { final int flags =mService.getPermissionFlags(permission, pkg.packageName, userId); // If any flags are set to thepermission, then it is either set in // its current state by thesystem or device/profile owner or the user. // In all these cases we do notwant to clobber the current state. // Unless the caller wants tooverride user choices. The override is // to make sure we can grantthe needed permission to the default // sms and phone apps after theuser chooses this in the UI. if (flags == 0 ||overrideUserChoice) { // Never clobber policy orsystem. final int fixedFlags =PackageManager.FLAG_PERMISSION_SYSTEM_FIXED |PackageManager.FLAG_PERMISSION_POLICY_FIXED; if ((flags &fixedFlags) != 0) { continue; } mService.grantRuntimePermission(pkg.packageName, permission, userId); if (DEBUG) { Log.i(TAG,"Granted " + permission + " to default handler " +pkg.packageName); } int newFlags =PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; if (systemFixed) { newFlags |=PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; } mService.updatePermissionFlags(permission, pkg.packageName, newFlags, newFlags,userId); } } } }
上面這個授予的方法我就不細說了,大家需要注意的是這裡授予權限的同時會控制一下權限的Flags,這個東西記錄了當前授予的這個運行時權限的狀態,主要有以下幾種,分表代碼什麼含義英文注釋已經夠清晰了不用我翻譯了吧。
/** * Permission flag: The permission is set inits current state * by the user and apps can still request itat runtime. * @hide */ public static final intFLAG_PERMISSION_USER_SET = 1 << 0; /** * Permission flag: The permission is setin its current state * by the user and it is fixed, i.e. appscan no longer request * this permission. * @hide */ public static final intFLAG_PERMISSION_USER_FIXED = 1 <<1; /** * Permission flag: The permission is setin its current state * by device policy and neither apps northe user can change * its state. * @hide */ public static final intFLAG_PERMISSION_POLICY_FIXED = 1<< 2; /** * Permission flag: The permission is setin a granted state but * access to resources it guards isrestricted by other means to * enable revoking a permission on legacyapps that do not support * runtime permissions. If this permissionis upgraded to runtime * because the app was updated to supportruntime permissions, the * the permission will be revoked in theupgrade process. * @hide */ public static final intFLAG_PERMISSION_REVOKE_ON_UPGRADE = 1<< 3; /** * Permission flag: The permission is setin its current state * because the app is a component that is apart of the system. * @hide */ public static final intFLAG_PERMISSION_SYSTEM_FIXED = 1<< 4; /** * Permission flag: The permission isgranted by default because it * enables app functionality that isexpected to work out-of-the-box * for providing a smooth user experience.For example, the phone app * is expected to have the phonepermission. * @hide */ public static final intFLAG_PERMISSION_GRANTED_BY_DEFAULT = 1<< 5;
在我的有限知識裡,一直對ApplicationInfo.PRIVATE_FLAG_PRIVILEGED這個flag也就是特權應用的范圍不是很清楚,還請知道的朋友指點一二。
下面繼續說符合系統默認規則的一類應用的默認授予情況,下面這個方法:
private voidgrantDefaultSystemHandlerPermissions(int userId) { Log.i(TAG, "Granting permissions todefault platform handlers for user " + userId); final PackagesProviderimePackagesProvider; final PackagesProviderlocationPackagesProvider; final PackagesProvidervoiceInteractionPackagesProvider; final PackagesProvidersmsAppPackagesProvider; final PackagesProviderdialerAppPackagesProvider; final PackagesProvidersimCallManagerPackagesProvider; final SyncAdapterPackagesProvidersyncAdapterPackagesProvider; synchronized (mService.mPackages) { imePackagesProvider =mImePackagesProvider; locationPackagesProvider =mLocationPackagesProvider; voiceInteractionPackagesProvider =mVoiceInteractionPackagesProvider; smsAppPackagesProvider =mSmsAppPackagesProvider; dialerAppPackagesProvider =mDialerAppPackagesProvider; simCallManagerPackagesProvider =mSimCallManagerPackagesProvider; syncAdapterPackagesProvider =mSyncAdapterPackagesProvider; } String[] imePackageNames =(imePackagesProvider != null) ?imePackagesProvider.getPackages(userId) : null; String[] voiceInteractPackageNames =(voiceInteractionPackagesProvider != null) ?voiceInteractionPackagesProvider.getPackages(userId) : null; String[] locationPackageNames =(locationPackagesProvider != null) ?locationPackagesProvider.getPackages(userId) : null; String[] smsAppPackageNames = (smsAppPackagesProvider!= null) ?smsAppPackagesProvider.getPackages(userId) : null; String[] dialerAppPackageNames =(dialerAppPackagesProvider != null) ?dialerAppPackagesProvider.getPackages(userId) : null; String[] simCallManagerPackageNames =(simCallManagerPackagesProvider != null) ?simCallManagerPackagesProvider.getPackages(userId) : null; String[] contactsSyncAdapterPackages =(syncAdapterPackagesProvider != null) ? syncAdapterPackagesProvider.getPackages(ContactsContract.AUTHORITY,userId) : null; String[] calendarSyncAdapterPackages =(syncAdapterPackagesProvider != null) ? syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY,userId) : null; synchronized (mService.mPackages) { // Installer PackageParser.PackageinstallerPackage = getSystemPackageLPr( mService.mRequiredInstallerPackage); if (installerPackage != null &&doesPackageSupportRuntimePermissions(installerPackage)) { grantRuntimePermissionsLPw(installerPackage, STORAGE_PERMISSIONS, true,userId); } // Verifier PackageParser.PackageverifierPackage = getSystemPackageLPr( mService.mRequiredVerifierPackage); if (verifierPackage != null &&doesPackageSupportRuntimePermissions(verifierPackage)) { grantRuntimePermissionsLPw(verifierPackage,STORAGE_PERMISSIONS, true, userId); grantRuntimePermissionsLPw(verifierPackage, PHONE_PERMISSIONS, false,userId); grantRuntimePermissionsLPw(verifierPackage, SMS_PERMISSIONS, false,userId); } // SetupWizard Intent setupIntent = newIntent(Intent.ACTION_MAIN); setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD); PackageParser.Package setupPackage= getDefaultSystemHandlerActivityPackageLPr( setupIntent, userId); if (setupPackage != null &&doesPackageSupportRuntimePermissions(setupPackage)) { grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId); grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId); } // Camera Intent cameraIntent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE); PackageParser.Package cameraPackage= getDefaultSystemHandlerActivityPackageLPr( cameraIntent, userId); if (cameraPackage != null &&doesPackageSupportRuntimePermissions(cameraPackage)) { grantRuntimePermissionsLPw(cameraPackage,CAMERA_PERMISSIONS, userId); grantRuntimePermissionsLPw(cameraPackage, MICROPHONE_PERMISSIONS,userId); grantRuntimePermissionsLPw(cameraPackage, STORAGE_PERMISSIONS, userId); } // Media provider PackageParser.PackagemediaStorePackage = getDefaultProviderAuthorityPackageLPr( MediaStore.AUTHORITY,userId); if (mediaStorePackage != null) { grantRuntimePermissionsLPw(mediaStorePackage,STORAGE_PERMISSIONS, true, userId); } // Downloads provider PackageParser.PackagedownloadsPackage = getDefaultProviderAuthorityPackageLPr( "downloads", userId); if (downloadsPackage != null) { grantRuntimePermissionsLPw(downloadsPackage, STORAGE_PERMISSIONS, true,userId); } // Downloads UI Intent downloadsUiIntent = newIntent(DownloadManager.ACTION_VIEW_DOWNLOADS); PackageParser.PackagedownloadsUiPackage = getDefaultSystemHandlerActivityPackageLPr( downloadsUiIntent, userId); if (downloadsUiPackage != null &&doesPackageSupportRuntimePermissions(downloadsUiPackage)) { grantRuntimePermissionsLPw(downloadsUiPackage, STORAGE_PERMISSIONS,true, userId); } // Storage provider PackageParser.PackagestoragePackage = getDefaultProviderAuthorityPackageLPr( "com.android.externalstorage.documents", userId); if (storagePackage != null) { grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, true,userId); } // CertInstaller Intent certInstallerIntent = newIntent(Credentials.INSTALL_ACTION); PackageParser.PackagecertInstallerPackage = getDefaultSystemHandlerActivityPackageLPr( certInstallerIntent, userId); if (certInstallerPackage != null &&doesPackageSupportRuntimePermissions(certInstallerPackage)) { grantRuntimePermissionsLPw(certInstallerPackage, STORAGE_PERMISSIONS,true, userId); } // Dialer if (dialerAppPackageNames == null){ Intent dialerIntent = newIntent(Intent.ACTION_DIAL); PackageParser.PackagedialerPackage = getDefaultSystemHandlerActivityPackageLPr( dialerIntent, userId); if (dialerPackage != null) { grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage,userId); } } else { for (StringdialerAppPackageName : dialerAppPackageNames) { PackageParser.PackagedialerPackage = getSystemPackageLPr(dialerAppPackageName); if (dialerPackage != null){ grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage,userId); } } } // Sim call manager if (simCallManagerPackageNames !=null) { for (String simCallManagerPackageName: simCallManagerPackageNames) { PackageParser.PackagesimCallManagerPackage = getSystemPackageLPr(simCallManagerPackageName); if (simCallManagerPackage!= null) { grantDefaultPermissionsToDefaultSimCallManagerLPr(simCallManagerPackage, userId); } } } // SMS if (smsAppPackageNames == null) { Intent smsIntent = newIntent(Intent.ACTION_MAIN); smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING); PackageParser.PackagesmsPackage = getDefaultSystemHandlerActivityPackageLPr( smsIntent, userId); if (smsPackage != null) { grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId); } } else { for (String smsPackageName :smsAppPackageNames) { PackageParser.PackagesmsPackage = getSystemPackageLPr(smsPackageName); if (smsPackage != null) { grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId); } } } // Cell Broadcast Receiver Intent cbrIntent = newIntent(Intents.SMS_CB_RECEIVED_ACTION); PackageParser.Package cbrPackage = getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId); if (cbrPackage != null &&doesPackageSupportRuntimePermissions(cbrPackage)) { grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, userId); } // Carrier Provisioning Service Intent carrierProvIntent = newIntent(Intents.SMS_CARRIER_PROVISION_ACTION); PackageParser.PackagecarrierProvPackage = getDefaultSystemHandlerServicePackageLPr(carrierProvIntent, userId); if (carrierProvPackage != null&& doesPackageSupportRuntimePermissions(carrierProvPackage)) { grantRuntimePermissionsLPw(carrierProvPackage, SMS_PERMISSIONS, false,userId); } // Calendar Intent calendarIntent = newIntent(Intent.ACTION_MAIN); calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR); PackageParser.PackagecalendarPackage = getDefaultSystemHandlerActivityPackageLPr( calendarIntent, userId); if (calendarPackage != null &&doesPackageSupportRuntimePermissions(calendarPackage)) { grantRuntimePermissionsLPw(calendarPackage, CALENDAR_PERMISSIONS,userId); grantRuntimePermissionsLPw(calendarPackage,CONTACTS_PERMISSIONS, userId); } // Calendar provider PackageParser.PackagecalendarProviderPackage = getDefaultProviderAuthorityPackageLPr( CalendarContract.AUTHORITY,userId); if (calendarProviderPackage !=null) { grantRuntimePermissionsLPw(calendarProviderPackage,CONTACTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(calendarProviderPackage,CALENDAR_PERMISSIONS, true, userId); grantRuntimePermissionsLPw(calendarProviderPackage, STORAGE_PERMISSIONS,userId); } // Calendar provider sync adapters ListcalendarSyncAdapters = getHeadlessSyncAdapterPackagesLPr( calendarSyncAdapterPackages, userId); final int calendarSyncAdapterCount= calendarSyncAdapters.size(); for (int i = 0; i PackageParser.Package calendarSyncAdapter =calendarSyncAdapters.get(i); if(doesPackageSupportRuntimePermissions(calendarSyncAdapter)) { grantRuntimePermissionsLPw(calendarSyncAdapter, CALENDAR_PERMISSIONS,userId); } } // Contacts Intent contactsIntent = newIntent(Intent.ACTION_MAIN); contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS); PackageParser.PackagecontactsPackage = getDefaultSystemHandlerActivityPackageLPr( contactsIntent, userId); if (contactsPackage != null &&doesPackageSupportRuntimePermissions(contactsPackage)) { grantRuntimePermissionsLPw(contactsPackage, CONTACTS_PERMISSIONS,userId); grantRuntimePermissionsLPw(contactsPackage, PHONE_PERMISSIONS, userId); } // Contacts provider sync adapters ListcontactsSyncAdapters = getHeadlessSyncAdapterPackagesLPr( contactsSyncAdapterPackages, userId); final int contactsSyncAdapterCount= contactsSyncAdapters.size(); for (int i = 0; i < contactsSyncAdapterCount;i++) { PackageParser.PackagecontactsSyncAdapter = contactsSyncAdapters.get(i); if(doesPackageSupportRuntimePermissions(contactsSyncAdapter)) { grantRuntimePermissionsLPw(contactsSyncAdapter, CONTACTS_PERMISSIONS,userId); } } // Contacts provider PackageParser.PackagecontactsProviderPackage = getDefaultProviderAuthorityPackageLPr( ContactsContract.AUTHORITY,userId); if (contactsProviderPackage !=null) { grantRuntimePermissionsLPw(contactsProviderPackage,CONTACTS_PERMISSIONS, true, userId); grantRuntimePermissionsLPw(contactsProviderPackage, PHONE_PERMISSIONS, true, userId); grantRuntimePermissionsLPw(contactsProviderPackage, STORAGE_PERMISSIONS,userId); } // Device provisioning Intent deviceProvisionIntent = newIntent( DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE); PackageParser.PackagedeviceProvisionPackage = getDefaultSystemHandlerActivityPackageLPr(deviceProvisionIntent,userId); if (deviceProvisionPackage != null &&doesPackageSupportRuntimePermissions(deviceProvisionPackage)) { grantRuntimePermissionsLPw(deviceProvisionPackage, CONTACTS_PERMISSIONS,userId); } // Maps Intent mapsIntent = newIntent(Intent.ACTION_MAIN); mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS); PackageParser.Package mapsPackage =getDefaultSystemHandlerActivityPackageLPr( mapsIntent, userId); if (mapsPackage != null &&doesPackageSupportRuntimePermissions(mapsPackage)) { grantRuntimePermissionsLPw(mapsPackage, LOCATION_PERMISSIONS, userId); } // Gallery Intent galleryIntent = newIntent(Intent.ACTION_MAIN); galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY); PackageParser.PackagegalleryPackage = getDefaultSystemHandlerActivityPackageLPr( galleryIntent, userId); if (galleryPackage != null &&doesPackageSupportRuntimePermissions(galleryPackage)) { grantRuntimePermissionsLPw(galleryPackage, STORAGE_PERMISSIONS, userId); } // Email Intent emailIntent = newIntent(Intent.ACTION_MAIN); emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL); PackageParser.Package emailPackage =getDefaultSystemHandlerActivityPackageLPr( emailIntent, userId); if (emailPackage != null &&doesPackageSupportRuntimePermissions(emailPackage)) { grantRuntimePermissionsLPw(emailPackage,CONTACTS_PERMISSIONS, userId); } // Browser PackageParser.PackagebrowserPackage = null; String defaultBrowserPackage =mService.getDefaultBrowserPackageName(userId); if (defaultBrowserPackage != null){ browserPackage =getPackageLPr(defaultBrowserPackage); } if (browserPackage == null) { Intent browserIntent = newIntent(Intent.ACTION_MAIN); browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER); browserPackage =getDefaultSystemHandlerActivityPackageLPr( browserIntent, userId); } if (browserPackage != null &&doesPackageSupportRuntimePermissions(browserPackage)) { grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS,userId); } // IME if (imePackageNames != null) { for (String imePackageName :imePackageNames) { PackageParser.PackageimePackage = getSystemPackageLPr(imePackageName); if (imePackage != null &&doesPackageSupportRuntimePermissions(imePackage)) { grantRuntimePermissionsLPw(imePackage, CONTACTS_PERMISSIONS, userId); } } } // Voice interaction if (voiceInteractPackageNames !=null) { for (String voiceInteractPackageName: voiceInteractPackageNames) { PackageParser.PackagevoiceInteractPackage = getSystemPackageLPr( voiceInteractPackageName); if (voiceInteractPackage !=null &&doesPackageSupportRuntimePermissions(voiceInteractPackage)) { grantRuntimePermissionsLPw(voiceInteractPackage, CONTACTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(voiceInteractPackage, CALENDAR_PERMISSIONS, userId); grantRuntimePermissionsLPw(voiceInteractPackage, MICROPHONE_PERMISSIONS, userId); grantRuntimePermissionsLPw(voiceInteractPackage, PHONE_PERMISSIONS, userId); grantRuntimePermissionsLPw(voiceInteractPackage, SMS_PERMISSIONS, userId); grantRuntimePermissionsLPw(voiceInteractPackage, LOCATION_PERMISSIONS, userId); } } } // Voice recognition Intent voiceRecoIntent = newIntent("android.speech.RecognitionService"); voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT); PackageParser.PackagevoiceRecoPackage = getDefaultSystemHandlerServicePackageLPr( voiceRecoIntent, userId); if (voiceRecoPackage != null &&doesPackageSupportRuntimePermissions(voiceRecoPackage)) { grantRuntimePermissionsLPw(voiceRecoPackage, MICROPHONE_PERMISSIONS,userId); } // Location if (locationPackageNames != null) { for (String packageName :locationPackageNames) { PackageParser.PackagelocationPackage = getSystemPackageLPr(packageName); if (locationPackage != null &&doesPackageSupportRuntimePermissions(locationPackage)) { grantRuntimePermissionsLPw(locationPackage, CONTACTS_PERMISSIONS,userId); grantRuntimePermissionsLPw(locationPackage,CALENDAR_PERMISSIONS, userId); grantRuntimePermissionsLPw(locationPackage, MICROPHONE_PERMISSIONS,userId); grantRuntimePermissionsLPw(locationPackage, PHONE_PERMISSIONS, userId); grantRuntimePermissionsLPw(locationPackage, SMS_PERMISSIONS, userId); grantRuntimePermissionsLPw(locationPackage, LOCATION_PERMISSIONS, true, userId); grantRuntimePermissionsLPw(locationPackage, CAMERA_PERMISSIONS, userId); grantRuntimePermissionsLPw(locationPackage, SENSORS_PERMISSIONS,userId); grantRuntimePermissionsLPw(locationPackage, STORAGE_PERMISSIONS,userId); } } } // Music Intent musicIntent = newIntent(Intent.ACTION_VIEW); musicIntent.addCategory(Intent.CATEGORY_DEFAULT); musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE); PackageParser.Package musicPackage= getDefaultSystemHandlerActivityPackageLPr( musicIntent, userId); if (musicPackage != null &&doesPackageSupportRuntimePermissions(musicPackage)) { grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId); } mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId); } }
這個方法好長好長,其實說白了就是針對滿足一些系統固有的規則(必須應用安裝,校驗,聯系人存儲、下載、撥號等等)的應用授予最基本的權限(其實就是強關聯的權限,比如downloadprovider授予讀寫存儲的權限和網絡權限),同時這個權限並不是fix的是可以關閉的。
五、特別的權限:
android.permission.SYSTEM_ALERT_WINDOW
android.permission.WRITE_SETTINGS
這兩個權限的實現是完全新加的也是跟上面的檢查過程不一樣的。
android.permission.WRITE_SETTINGS權限的設置和驗證代碼主要Settings應用和SettingsProvider裡面
WriteSettingsDetails中進行設置,方法如下:
private void setCanWriteSettings(boolean newState) { mAppOpsManager.setMode(AppOpsManager.OP_WRITE_SETTINGS, mPackageInfo.applicationInfo.uid, mPackageName, newState ? AppOpsManager.MODE_ALLOWED: AppOpsManager.MODE_ERRORED); }
SettingsProvider的讀寫方法中進行檢驗
可以看看這個類中見的幾個mutate****Setting的方法,針對其中的Global和Secure表都需要權限Manifest.permission.WRITE_SECURE_SETTINGS,這個如果沒有權限就直接異常了。
private voidenforceWritePermission(String permission) { if (getContext().checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED){ throw new SecurityException("Permissiondenial: writing to settings requires:" + permission); } }
對於System表的寫操作,先檢測是否有WRITE_SECURE_SETTINGS權限,如果沒有則進行檢查是否已授權WRITE_SETTINGS權限,後一個檢查過程就是可以動態控制的了(稍後再看),檢查完權限之後接下來做一個操作的限制。
if (!hasWriteSecureSettingsPermission()) { // If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whetherthis // operation is allowed for the calling package through appops. if (!Settings.checkAndNoteWriteSettingsOperation(getContext(), Binder.getCallingUid(),getCallingPackage(), true)) { return false; } }
下面這個方法做限制其大意就是,如果是systemUID或者shell或者root不受限制,其他進程插入和更新操作都只能操作PUBLIC_SETTINGS,對其他表的數據如果應用的targetsdkversion>=23都會異常,對於刪除操作則都不能進行(例外的是targetsdkversion<23的可以刪除自定義的字段)
private voidenforceRestrictedSystemSettingsMutationForCallingPackage(int operation, String name) { // System/root/shell can mutate whatever secure settings they want. final int callingUid= Binder.getCallingUid(); if (callingUid == android.os.Process.SYSTEM_UID || callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { return; } switch (operation) { case MUTATION_OPERATION_INSERT: // Insert updates. case MUTATION_OPERATION_UPDATE: { if (Settings.System.PUBLIC_SETTINGS.contains(name)) { return; } // The calling package is already verified. PackageInfo packageInfo =getCallingPackageInfoOrThrow(); // Privileged apps can do whatever they want. if ((packageInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)!= 0) { return; } warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( packageInfo.applicationInfo.targetSdkVersion, name); } break; case MUTATION_OPERATION_DELETE: { if (Settings.System.PUBLIC_SETTINGS.contains(name) || Settings.System.PRIVATE_SETTINGS.contains(name)) { throw new IllegalArgumentException("You cannotdelete system defined" + " secure settings."); } // The calling package is already verified. PackageInfo packageInfo =getCallingPackageInfoOrThrow(); // Privileged apps can do whatever they want. if ((packageInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)!= 0) { return; } warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( packageInfo.applicationInfo.targetSdkVersion, name); } break; } } private voidwarnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( int targetSdkVersion, String name){ // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash. if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) { if (Settings.System.PRIVATE_SETTINGS.contains(name)) { Slog.w(LOG_TAG, "You shouldn't not change private systemsettings." + " This will soon become an error."); } else { Slog.w(LOG_TAG, "You shouldn't keep your settings in the securesettings." + " This will soon become an error."); } } else { if (Settings.System.PRIVATE_SETTINGS.contains(name)) { throw new IllegalArgumentException("You cannotchange private system settings."); } else { throw new IllegalArgumentException("You cannot keepyour settings in" + " the secure settings. oppo app can requestoppo.permission.OPPO_COMPONENT_SAFE permission!"); } } }
綜合上面的描述得出的結論是,targetsdkversion>=23也就是6.0之後,只有系統應用才可以寫Global和Secure表,對於System表則第三方應用在授權WRITE_SETTINGS的前提下也只能寫其中的PUBLIC_SETTINGS字段。
然後看動態檢驗過程,檢驗都是動態的,這裡指的是檢驗的值可以動態變化,變化的途徑前面將了是通過AppOpsManager.setMode,為什麼會生效呢就得看剛剛留下的一個方法。在framework的Settings中
public static booleancheckAndNoteDrawOverlaysOperation(Context context, int uid, String callingPackage, boolean throwException) { returnisCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_SYSTEM_ALERT_WINDOW, PM_SYSTEM_ALERT_WINDOW, true); } /** * Helper method toperform a general and comprehensive check of whether an operation that is * protected by appopscan be performed by a caller or not. e.g. OP_SYSTEM_ALERT_WINDOW and * OP_WRITE_SETTINGS * @hide */ public static booleanisCallingPackageAllowedToPerformAppOpsProtectedOperation(Context context, int uid,String callingPackage, boolean throwException, int appOpsOpCode, String[] permissions,boolean makeNote) { if (callingPackage== null) { return false; } AppOpsManagerappOpsMgr = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); int mode =AppOpsManager.MODE_DEFAULT; if (makeNote) { mode =appOpsMgr.noteOpNoThrow(appOpsOpCode, uid, callingPackage); } else { mode =appOpsMgr.checkOpNoThrow(appOpsOpCode, uid, callingPackage); } switch (mode) { caseAppOpsManager.MODE_ALLOWED: returntrue; case AppOpsManager.MODE_DEFAULT: // this isthe default operating mode after an app's installation // In thiscase we will check all associated static permission to see // if itis granted during install time. for (String permission :permissions) { if(context.checkCallingOrSelfPermission(permission) == PackageManager .PERMISSION_GRANTED) { //if either of the permissions are granted, we will allow it return true; } } default: // this isfor all other cases trickled down here... if(!throwException) { returnfalse; } } // prepare stringto throw SecurityException StringBuilderexceptionMessage = new StringBuilder(); exceptionMessage.append(callingPackage); exceptionMessage.append(" was not granted "); if(permissions.length > 1) { exceptionMessage.append(" either of these permissions: "); } else { exceptionMessage.append(" this permission: "); } for (int i = 0; i< permissions.length; i++) { exceptionMessage.append(permissions[i]); exceptionMessage.append((i == permissions.length - 1) ? "." :", "); } throw newSecurityException(exceptionMessage.toString()); }
這個方法的做法一目了然,就是直接從AppOpsManager去讀取對應的OpCode的模式,如果是允許的那就判斷為授予,如果是默認狀態則使用之前權限是否靜態授予的狀態(其實這個默認狀態對於其他未修改的動態權限也是有類似操作的在PackageManagerService. GrantPermissionsLPw()方法中)。
最後,android.permission.SYSTEM_ALERT_WINDOW這個的設置也在設置應用中(DrawOverlayDetails這個類中設置,同樣也是通過AppOpsManager.setMode來進行控制),但是檢驗過程在framework的window管理部分本篇暫不涉及。
獲取到sha1後,下面開始進入百度地圖sdk的資源獲取;一、獲取密鑰和SDK;1、搜索百度地圖sdk;2、點擊獲取密鑰;3、創建應用;4、進入概述下的“相關下
這是作為上一篇Android 數據存儲 如何搞定SQLite Database的實例練習,之所以單獨列出來是因為除了數據庫方面的知識,還涉及其它方面的知識,
我們經常在做項目過程中遇到內存溢出的問題,同時面試中關於OOM的問題也常常出現。這裡,我將前輩們解決Andorid內存溢出的方法重新整理一番,方便自己以後使用。一、And
當我們為新浪微博的登陸設置了賬號保護、手機綁定之後,便將新浪微博賬號的安全與我們的手機號聯系起來了。由於換號或者其它原因,我們需要解除綁定的時候該怎麼辦呢?