Android Runtime权限检查与访问控制源码解析
一、Android Runtime权限体系概述
Android Runtime(ART)的权限检查与访问控制是保障系统安全的核心机制,它贯穿于应用运行的全生命周期,从应用安装到资源访问、系统服务调用等各个环节。该体系基于Android系统的安全模型设计,旨在防止应用越权访问敏感资源,保护用户数据和系统安全。
在Android开源项目(AOSP)中,权限相关代码分散于多个模块。核心逻辑主要存在于frameworks/base目录下,其中core/java/android/Manifest.permission定义了系统所有权限常量,而frameworks/base/services/core/java/com/android/server目录下的服务类则负责具体的权限检查操作 。例如,android.Manifest.permission类中定义了如android.permission.INTERNET、android.permission.READ_CONTACTS等权限标识,这些常量作为权限检查的基础依据:
// android.Manifest.permission类部分定义,用于声明权限常量
public final class Manifest.permission {
// 网络访问权限
public static final String INTERNET = "android.permission.INTERNET";
// 读取联系人权限
public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
// 更多权限常量定义...
}
ART权限体系通过应用清单文件(AndroidManifest.xml)、权限授予机制、运行时检查等多层防护,构建起完整的访问控制链条。应用在安装时,系统会解析清单文件中的权限声明,在运行时,每当涉及敏感操作,都会触发严格的权限检查流程,只有通过检查的操作才能继续执行。
二、应用安装时的权限声明与校验
应用安装阶段是权限管理的起点,系统通过解析AndroidManifest.xml文件中的权限声明,校验应用申请权限的合法性,并向用户展示申请信息。相关源码主要集中在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java文件中,PackageManagerService类负责管理系统中的所有应用包,包括权限处理。
在应用安装过程中,PackageManagerService的installPackage方法会调用parsePackage方法解析应用的清单文件:
// PackageManagerService.installPackage方法处理应用安装
public void installPackage(...) {
// 解析应用包,包含权限声明解析
PackageParser.Package pkg = parsePackage(installArgs.installerPackageName,
installArgs.sourcePath, parseFlags,
installerContext.getUserId());
// 校验权限声明
if (!verifyPermissions(pkg)) {
// 权限声明不合法,安装失败
throw new InstallFailedException("Invalid permissions declared");
}
// 后续安装流程...
}
// PackageManagerService.parsePackage方法解析应用包信息
private PackageParser.Package parsePackage(String installerPackageName, String sourcePath,
int flags, int userId) {
PackageParser pp = new PackageParser(sourcePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
// 解析应用清单文件
return pp.parsePackage(installerPackageName, sourcePath, metrics, flags, userId);
}
PackageParser类进一步解析清单文件中的权限声明:
// PackageParser.parsePackage方法解析应用包的详细信息
public Package parsePackage(String installerPackageName, String sourcePath,
DisplayMetrics metrics, int flags, int userId) {
Package pkg = new Package();
// 解析AndroidManifest.xml文件
XmlResourceParser parser = getPackageArchiveHandle().getMainAsset().openXmlResourceParser(
ANDROID_MANIFEST_FILENAME);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG) {
if (parser.getName().equals("uses-permission")) {
// 提取权限声明
String permission = parser.getAttributeValue(null, "name");
pkg.requestedPermissions.add(permission);
}
// 解析其他标签...
}
}
return pkg;
}
解析完成后,PackageManagerService通过verifyPermissions方法校验权限声明是否合法,例如检查权限是否为系统预定义权限,是否与应用签名级别匹配等。只有通过校验的应用才能继续完成安装,这一过程从源头保障了应用权限使用的合规性。
三、权限授予机制原理
应用安装完成后,用户需要对应用申请的权限进行授予操作,系统通过权限授予机制决定应用能够实际使用的权限。权限授予的核心逻辑在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java和frameworks/base/core/java/android/content/pm/PackageManager.java中。
用户在设置中对应用进行权限授予时,最终会调用PackageManagerService的setApplicationEnabledSetting方法或grantRuntimePermission方法。以运行时权限授予为例,grantRuntimePermission方法的实现如下:
// PackageManagerService.grantRuntimePermission方法授予运行时权限
public void grantRuntimePermission(String packageName, String permission, int userId) {
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
return;
}
// 将权限添加到应用的已授予权限列表
pkg.requestedPermissionsFlags.put(permission, PackageParser.PERMISSION_GRANTED);
// 通知应用权限已变更
sendPackageBroadcasts(packageName, null, null,
PackageManager.BROADCAST_PACKAGE_PERMISSIONS_CHANGED,
null, userId);
}
}
系统通过PackageParser.Package类中的requestedPermissionsFlags集合记录应用已授予的权限。当应用尝试进行需要权限的操作时,系统会从该集合中查询权限授予状态。此外,对于危险权限,系统还会在授予前向用户展示详细的权限说明和风险提示,确保用户知情同意,这一过程通过frameworks/base/core/java/android/app/AlertDialog等类实现界面展示与交互逻辑。
四、运行时权限检查流程
运行时权限检查是保障系统安全的关键环节,当应用执行涉及敏感资源访问或系统服务调用的操作时,ART会触发权限检查流程。相关源码分布在多个系统服务类中,以访问联系人数据为例,ContactsProvider2类作为联系人数据的提供者,在处理数据查询请求时会进行权限检查:
// ContactsProvider2.query方法处理联系人数据查询请求
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// 检查读取联系人权限
if (checkCallingPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Permission Denial: reading " + uri +
" without permission");
}
// 权限通过,执行实际查询操作
SQLiteDatabase db = getWritableDatabase();
return db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
}
上述代码中,checkCallingPermission方法是权限检查的核心,它由ActivityManagerService实现:
// ActivityManagerService.checkCallingPermission方法检查调用者权限
public int checkCallingPermission(String permission) {
final int callingUid = Binder.getCallingUid();
return checkUidPermission(permission, callingUid);
}
// ActivityManagerService.checkUidPermission方法检查指定UID的权限
public int checkUidPermission(String permission, int uid) {
// 从PackageManagerService获取权限授予状态
PackageManagerService pms = mPackageManagerService;
return pms.checkUidPermission(permission, uid);
}
PackageManagerService的checkUidPermission方法最终查询应用的已授予权限列表,判断当前操作是否具有相应权限:
// PackageManagerService.checkUidPermission方法检查UID对应的权限
public int checkUidPermission(String permission, int uid) {
synchronized (mPackages) {
PackageParser.Package pkg = getPackageLPr(uid);
if (pkg == null) {
return PackageManager.PERMISSION_DENIED;
}
// 查询权限授予状态
Integer flag = pkg.requestedPermissionsFlags.get(permission);
return flag == null? PackageManager.PERMISSION_DENIED : flag;
}
}
如果权限检查未通过,系统会抛出SecurityException异常,阻止操作执行,从而实现对敏感资源的严格访问控制。
五、系统服务权限控制机制
Android系统中存在大量系统服务,如ActivityManagerService、LocationManagerService等,这些服务提供了重要的系统功能,同时也需要严格的权限控制。系统服务权限控制的源码主要在frameworks/base/services/core/java/com/android/server目录下对应的服务类中。
以LocationManagerService为例,当应用请求获取位置信息时,LocationManagerService的getLastKnownLocation方法会进行权限检查:
// LocationManagerService.getLastKnownLocation方法获取最后已知位置
public Location getLastKnownLocation(String provider) {
// 检查获取位置信息权限
if (checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PERMISSION_GRANTED &&
checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) != PERMISSION_GRANTED) {
throw new SecurityException("Client must have ACCESS_COARSE_LOCATION or " +
"ACCESS_FINE_LOCATION permission to perform this operation");
}
// 权限通过,执行获取位置逻辑
//...
}
除了运行时权限检查,系统服务还通过权限白名单、签名权限等机制进一步加强安全防护。例如,部分系统服务只允许特定签名的系统应用访问,这一逻辑通过PackageManagerService的checkSignatures方法实现:
// PackageManagerService.checkSignatures方法检查应用签名
public int checkSignatures(int uid1, int uid2) {
PackageParser.Package pkg1 = getPackageLPr(uid1);
PackageParser.Package pkg2 = getPackageLPr(uid2);
if (pkg1 == null || pkg2 == null) {
return PackageManager.SIGNATURE_MISMATCH;
}
// 检查两个应用的签名是否一致
return compareSignatures(pkg1.signatures, pkg2.signatures);
}
通过多种权限控制手段的结合,系统服务能够在保障功能正常提供的同时,有效防止非法访问和越权操作。
六、跨进程通信(IPC)中的权限检查
在Android系统中,跨进程通信(IPC)是应用与系统服务、应用与应用之间交互的重要方式,如通过Binder机制实现的远程过程调用(RPC)。在IPC过程中,权限检查是保障通信安全的必要措施,相关源码主要在frameworks/base/core/java/android/os/Binder.java和frameworks/base/core/jni/android_os_Binder.cpp中。
当客户端进程通过Binder调用服务端方法时,服务端在接收到请求后会进行权限检查。以ActivityManagerService为例,它作为系统核心服务,通过Binder接收来自应用进程的请求,其attachApplication方法在处理应用进程绑定请求时会检查调用者权限:
// ActivityManagerService.attachApplication方法处理应用进程绑定
public final boolean attachApplication(IApplicationThread thread) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
// 检查调用者权限
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "attachApplication: Request from pid " + callingPid + " (uid " + callingUid +
") without INTERACT_ACROSS_USERS; rejecting");
return false;
}
// 权限通过,继续处理绑定逻辑
//...
}
在Binder机制的底层实现中,android_os_Binder.cpp文件中的android_os_Binder_transact函数负责处理跨进程调用,它会获取调用者的进程ID(PID)和用户ID(UID),传递给上层进行权限检查:
// android_os_Binder_transact函数处理跨进程调用
static jboolean android_os_Binder_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj,
jint flags) {
// 获取调用者的PID和UID
pid_t callingPid = IPCThreadState::self()->getCallingPid();
uid_t callingUid = IPCThreadState::self()->getCallingUid();
// 调用Java层的权限检查逻辑
//...
}
通过在IPC过程中层层进行权限检查,确保只有具备相应权限的进程才能合法调用服务端方法,防止恶意进程通过跨进程通信进行非法操作。
七、权限检查的优化与缓存机制
为了提高权限检查的效率,减少重复检查带来的性能开销,ART引入了权限检查的优化与缓存机制。相关逻辑在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java和frameworks/base/core/java/android/content/pm/PackageManager.java中有所体现。
PackageManagerService会维护一个权限检查结果的缓存,当应用频繁进行相同的权限检查时,可直接从缓存中获取结果。例如,在checkUidPermission方法中,会先检查缓存:
// PackageManagerService.checkUidPermission方法检查UID对应的权限
public int checkUidPermission(String permission, int uid) {
synchronized (mPackages) {
// 尝试从缓存中获取权限检查结果
Integer cachedResult = permissionCheckCache.get(permission + uid);
if (cachedResult != null) {
return cachedResult;
}
PackageParser.Package pkg = getPackageLPr(uid);
if (pkg == null) {
return PackageManager.PERMISSION_DENIED;
}
Integer flag = pkg.requestedPermissionsFlags.get(permission);
int result = flag == null? PackageManager.PERMISSION_DENIED : flag;
// 将结果存入缓存
permissionCheckCache.put(permission + uid, result);
return result;
}
}
此外,系统还会根据应用的使用频率、权限变更情况等动态更新缓存,确保缓存结果的有效性。通过权限检查的优化与缓存机制,系统在保障安全的同时,提升了应用运行的整体性能,减少了权限检查对系统资源的消耗。
八、权限拒绝后的处理机制
当应用的权限检查未通过时,系统会拒绝操作并触发相应的处理机制,这一过程涉及异常处理、日志记录以及向应用提供错误反馈等。相关源码分布在各个系统服务类和异常处理类中。
如前文所述,当权限检查失败时,系统会抛出SecurityException异常。在ContactsProvider2类的query方法中,权限未通过时抛出异常后,应用进程会捕获该异常并进行处理:
// 应用中捕获SecurityException异常示例
try {
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
} catch (SecurityException e) {
// 权限被拒绝,提示用户
Toast.makeText(this, "权限不足,无法访问联系人", Toast.LENGTH_SHORT).show();
}
同时,系统层面会记录权限拒绝的日志信息,便于开发者和系统维护人员排查问题。在ActivityManagerService中,权限拒绝时会记录日志:
// ActivityManagerService权限拒绝时记录日志
public final boolean attachApplication(IApplicationThread thread) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "attachApplication: Request from pid " + callingPid + " (uid " + callingUid +
") without INTERACT_ACROSS_USERS; rejecting");
return false;
}
//...
}
通过权限拒绝后的处理机制,系统不仅能够及时阻止非法操作,还能向应用和开发者提供清晰的反馈信息,便于后续权限管理和功能优化。
九、动态权限管理原理
Android 6.0(Marshmallow)引入了动态权限管理机制,允许应用在运行过程中向用户申请权限,进一步提升了用户对应用权限的掌控力。动态权限管理的核心源码在frameworks/base/core/java/android/app/Activity.java和frameworks/base/core/java/android/content/pm/PackageManager.java中。
在应用中,通过Activity类的requestPermissions方法向用户申请权限:
// Activity.requestPermissions方法请求权限
public void requestPermissions(String[] permissions, int requestCode) {
// 构建权限请求对象
PermissionRequest request = new PermissionRequest(this);
request.setPermissions(permissions);
request.setRequestCode(requestCode);
// 发起权限请求
request.start();
}
当用户对权限请求做出响应后,Activity的onRequestPermissionsResult方法会接收结果:
// Activity.onRequestPermissionsResult方法处理权限请求结果
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
// 处理权限授予或拒绝的情况
if (requestCode
在onRequestPermissionsResult方法接收到权限请求结果后,系统会根据grantResults数组判断权限是否被授予。若权限被授予,应用可继续执行需要该权限的操作;若被拒绝,应用通常需要给出相应提示或调整功能:
// Activity.onRequestPermissionsResult方法处理权限请求结果
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == MY_PERMISSIONS_REQUEST_READ_CONTACTS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限已授予,执行读取联系人操作
readContacts();
} else {
// 权限被拒绝,显示提示信息
Toast.makeText(this, "读取联系人权限被拒绝,部分功能无法使用", Toast.LENGTH_SHORT).show();
}
}
}
从系统层面看,PackageManagerService在处理动态权限请求时,会更新应用的权限授予状态。当应用通过requestPermissions发起请求后,最终会调用到PackageManagerService的相关方法:
// PackageManagerService处理动态权限请求的部分逻辑
void handleRuntimePermissionRequest(...) {
String packageName =...;
String[] permissions =...;
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg!= null) {
for (String permission : permissions) {
// 更新权限授予状态
pkg.requestedPermissionsFlags.put(permission, PERMISSION_GRANTED);
}
// 通知应用权限已变更
sendPackageBroadcasts(packageName,...);
}
}
}
动态权限管理还涉及“不再询问”选项的处理。当用户勾选“不再询问”并拒绝权限后,下次应用请求该权限时,系统不会再弹出权限请求对话框。Activity类在请求权限前,会通过shouldShowRequestPermissionRationale方法判断是否需要展示权限请求解释:
// Activity.shouldShowRequestPermissionRationale方法判断是否展示权限解释
public boolean shouldShowRequestPermissionRationale(String permission) {
// 检查权限状态和用户选择
// 如果用户之前拒绝过权限且勾选了“不再询问”,则返回false
// 否则返回true,提示应用展示权限必要性说明
return shouldShowRationaleInternally(permission);
}
十、权限组与权限树管理机制
Android系统将权限划分为不同的权限组,以此简化权限管理和用户授权流程。权限组的定义和管理在frameworks/base/core/java/android/Manifest.permission_group中体现,例如android.permission_group.CONTACTS权限组包含了READ_CONTACTS、WRITE_CONTACTS等相关权限:
// Manifest.permission_group类定义权限组常量
public final class Manifest.permission_group {
// 联系人权限组
public static final String CONTACTS = "android.permission_group.CONTACTS";
// 存储权限组
public static final String STORAGE = "android.permission_group.STORAGE";
}
在权限检查时,系统会考虑权限组的关系。当应用申请权限组中的某个权限时,系统可能会同时授予该权限组内的其他相关权限(在用户同意的情况下) 。PackageManagerService在处理权限授予时,会检查权限所属的权限组:
// PackageManagerService授予权限时处理权限组逻辑
void grantPermissionForGroup(String packageName, String permission) {
String group = getPermissionGroup(permission);
if (group!= null) {
String[] groupPermissions = getPermissionsInGroup(group);
for (String groupPermission : groupPermissions) {
if (!pkg.requestedPermissions.contains(groupPermission)) {
// 将权限组内其他权限一并授予
grantRuntimePermission(packageName, groupPermission,...);
}
}
}
}
权限树的概念则体现在权限的层级关系和依赖关系上。部分权限的使用依赖于其他基础权限,例如使用ACCESS_FINE_LOCATION高精度定位权限,可能依赖于ACCESS_COARSE_LOCATION粗略定位权限。在权限检查过程中,PackageManagerService会检查权限的依赖关系:
// PackageManagerService检查权限依赖关系
boolean checkPermissionDependency(String permission) {
String[] dependencies = getPermissionDependencies(permission);
if (dependencies!= null) {
for (String dep : dependencies) {
if (!isPermissionGranted(dep)) {
return false;
}
}
}
return true;
}
通过权限组和权限树的管理,系统能够更高效地进行权限授予和检查,同时降低用户授权的复杂度,提升用户体验。
十一、权限检查与沙盒环境的协同
Android应用运行在沙盒环境中,每个应用都有独立的文件系统空间和资源访问范围,权限检查与沙盒机制紧密协同,共同保障系统安全。从源码角度看,在文件系统访问方面,android.os.File类的文件操作方法在执行前会进行权限检查。例如,File类的write方法在向文件写入数据时:
// File.write方法写入文件前进行权限检查
public void write(byte[] data) throws IOException {
if (!checkWritePermission()) {
throw new SecurityException("没有写入文件权限");
}
// 执行实际写入操作
nativeWrite(data);
}
// 检查写入文件权限的方法
private boolean checkWritePermission() {
return checkCallingPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
}
在进程隔离层面,Linux内核的UID/GID机制为每个应用分配独立的用户ID和组ID,应用只能访问与自身UID/GID匹配的资源。ART在进行跨进程通信或资源访问时,会结合UID/GID和权限检查双重机制。例如,ActivityManagerService在处理应用进程间通信时:
// ActivityManagerService处理进程间通信时检查UID和权限
void handleInterProcessCommunication(...) {
int callingUid = Binder.getCallingUid();
String requiredPermission =...;
if (!isUidSystem(callingUid) &&
checkUidPermission(requiredPermission, callingUid)!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("进程UID " + callingUid + " 权限不足");
}
// 允许通信并处理后续逻辑
}
沙盒环境与权限检查的协同,使得应用只能在授权范围内访问资源,有效防止应用越界访问其他应用或系统资源,即使某个应用存在漏洞被攻击,也能将影响范围限制在自身沙盒内。
十二、SELinux与权限检查的整合
安全增强型Linux(SELinux)是Android系统安全的重要组成部分,它与ART的权限检查机制深度整合,进一步强化系统安全。在Android源码中,system/sepolicy目录下存放着SELinux的策略文件,定义了各种安全规则。
当应用进行系统调用时,SELinux会在底层进行策略检查。以网络访问为例,在netd网络守护进程处理网络请求时,会调用SELinux的相关接口进行检查:
// netd处理网络请求时调用SELinux检查
int handleNetworkRequest(...) {
if (selinux_check_access(net_context, "network", "send")!= 0) {
// SELinux策略检查不通过
return -1;
}
// 继续处理网络请求
}
在Java层,android.os.Process类的部分方法也会与SELinux交互。例如,Process类在创建新进程时,会根据SELinux策略设置进程的安全上下文:
// Process类创建新进程时设置SELinux安全上下文
public static ProcessBuilder start(String[] args) {
String seContext = getSELinuxContextForProcess();
ProcessBuilder builder = new ProcessBuilder(args);
builder.environment().put("ANDROID_SEC_CONTEXT", seContext);
return builder;
}
// 获取进程的SELinux安全上下文
private static String getSELinuxContextForProcess() {
// 调用底层接口获取上下文
return nativeGetSELinuxContext();
}
ART在进行权限检查时,会参考SELinux的策略结果。例如,PackageManagerService在授予应用权限时,会检查该权限授予是否符合SELinux策略:
// PackageManagerService授予权限时检查SELinux策略
void grantRuntimePermission(String packageName, String permission) {
if (!isSELinuxPolicyCompliant(packageName, permission)) {
// 不符合SELinux策略,拒绝授予
return;
}
// 符合策略,继续授予权限流程
}
// 检查权限授予是否符合SELinux策略
private boolean isSELinuxPolicyCompliant(String packageName, String permission) {
// 调用底层接口检查策略
return nativeCheckSELinuxPolicy(packageName, permission);
}
通过与SELinux的整合,Android系统实现了基于角色和策略的细粒度访问控制,即使权限检查机制存在部分漏洞,SELinux也能从底层进一步限制应用的非法操作,极大提升了系统的整体安全性。
十三、权限检查在系统升级与兼容性中的处理
在Android系统升级过程中,权限检查机制需要处理新旧版本权限规则的差异,保证应用的兼容性。PackageManagerService在系统升级时,会对应用的权限进行迁移和适配。
当系统从旧版本升级到新版本,权限定义或权限组关系可能发生变化。PackageManagerService的upgradePackages方法会处理应用的权限升级:
// PackageManagerService.upgradePackages方法处理应用权限升级
void upgradePackages(...) {
for (PackageParser.Package pkg : packagesToUpgrade) {
updatePermissionsForUpgrade(pkg);
}
}
// 更新应用权限以适配升级
private void updatePermissionsForUpgrade(PackageParser.Package pkg) {
String[] oldPermissions = pkg.requestedPermissions.toArray(new String[0]);
for (String oldPermission : oldPermissions) {
String newPermission = getMappedPermissionForUpgrade(oldPermission);
if (newPermission!= null) {
// 将旧权限替换为新权限
pkg.requestedPermissions.remove(oldPermission);
pkg.requestedPermissions.add(newPermission);
}
}
}
对于废弃的权限,系统会在应用升级时进行处理。如果应用申请了旧版本存在但新版本已废弃的权限,PackageManagerService会进行转换或提示:
// 处理废弃权限的方法
void handleDeprecatedPermissions(PackageParser.Package pkg) {
String[] deprecatedPermissions = getDeprecatedPermissions();
for (String deprecatedPermission : deprecatedPermissions) {
if (pkg.requestedPermissions.contains(deprecatedPermission)) {
// 记录日志提示权限废弃
Slog.w(TAG, "应用 " + pkg.packageName + " 申请了废弃权限 " + deprecatedPermission);
// 可选择转换为替代权限或直接移除
convertOrRemoveDeprecatedPermission(pkg, deprecatedPermission);
}
}
}
在兼容性方面,对于低版本应用在高版本系统上运行,系统会根据兼容性规则调整权限检查逻辑。例如,某些高版本新增的权限检查,对于低目标版本的应用可能会放宽要求:
// 根据应用目标版本调整权限检查逻辑
boolean adjustPermissionCheckForCompatibility(String packageName, String permission) {
int targetSdkVersion = getTargetSdkVersion(packageName);
if (targetSdkVersion < COMPATIBILITY_TARGET_VERSION) {
// 对于低目标版本应用,可能跳过某些新权限检查
return true;
}
return false;
}
通过这些在系统升级和兼容性方面的权限处理机制,Android系统能够在不断演进安全规则的同时,保障大量存量应用的正常运行,平衡安全性与兼容性。