所有的权限定义在 Android 系统的源代码中,路径通常位于 frameworks/base/core/res/AndroidManifest.xml
。
本篇文章以Android 15 原生源码来做的讲解。
LI 、LIF、LPr、LPw 是什么?
首先L代表Lock,I代表mInstall,P代表mPackages,F代表frozen,r代表读,w代表写。
这类权限不会对用户隐私和系统安全构成重大风险,如查看网络连接状态、访问 Wi-Fi 状态等。应用在 AndroidManifest.xml 文件中声明所需要的权限后,在安装时系统会自动授予,无需用户额外确认。系统会为普通权限分配 normal 保护级别。
在项目的 AndroidManifest.xml 文件中,使用
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<!-- 声明查看网络连接状态的权限 -->
<uses - permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 声明查看 Wi-Fi 状态的权限 -->
<uses - permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application...>
...
</application>
</manifest>
完成权限声明后,像平常一样构建应用(可以通过 Android Studio 的构建工具进行编译和打包)。在代码中使用权限相关功能:
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
public class NetworkUtils {
fun isNetworkConnected(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManagerval
networkInfo: NetworkInfo? = connectivityManager.activeNetworkInforeturn
networkInfo!= null && networkInfo.isConnected
}
}
在上述代码中,getSystemService 方法获取 ConnectivityManager 实例,进而可以调用 getActiveNetworkInfo 方法来获取网络连接信息。由于在 AndroidManifest.xml 中已经声明了 ACCESS_NETWORK_STATE 权限,系统会自动授予该权限,使得代码能够正常执行。
当用户在设备上安装应用时,系统会检查应用声明的普通权限列表。由于这些权限被标记为普通权限,系统会自动将它们授予应用,无需用户进行任何手动操作。
在PackageInstallerRecive收到安装通知,调用frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java的postAppInstalledNotification()来发送一个安装通知。并打开installer的lauch intent;
解析APK流程
系统首先需要通过文件路径或 URI 来读取 APK 文件。在 frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java 中初始化mPm、mInstaller,并通过packageUri来读去APK文件。
public class PackageInstallerActivity extends AlertActivity {
...
private int mSessionId = -1;
PackageManager mPm;
IPackageManager mIpm;...
PackageInstaller mInstaller;
PackageInfo mPkgInfo; //解析apk得到的PackageInfo
...
protected void onCreate(Bundle icicle) {
...
mPm = getPackageManager(); //ApplicationPackageManager
...
mInstaller = mPm.getPackageInstaller(); // mInstaller,安装器
...
final Intent intent = getIntent();
final Object packageSource;
if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(action)) {
...
packageSource = Uri.fromFile(new File(resolvedPath));
...
} else if (PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL.equals(action)) {
...
final SessionInfo info = mInstaller.getSessionInfo(sessionId);
...
packageSource = info;
...
} else {
...
packageSource = intent.getData();
...
}
...
final boolean wasSetUp = processAppSnippet(packageSource);
...
}
@Override
protected void onResume() {
super.onResume();
if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
if (mAppSnippet != null) {
// 开启安装确认
bindUi();
checkIfAllowedAndInitiateInstall();
}
if (mOk != null) {
mOk.setEnabled(mEnableOk);
}
}
...
private boolean processPackageUri(final Uri packageUri) {
mPackageURI = packageUri;
final String scheme = packageUri.getScheme();
switch (scheme) {
...
case ContentResolver.SCHEME_FILE: {
File sourceFile = new File(packageUri.getPath());
//解析APK,注意参数是 GET_PERMISSIONS
mPkgInfo = PackageUtil.getPackageInfo(this, sourceFile, PackageManager.GET_PERMISSIONS);
..
//获取apk摘要:图标、名字
mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
...
}
break;
...
}
return true;
}
...
}
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java中调用PackageManager 类解析了参数flags 是 PackageManager.GET_PERMISSIONS的APK权限信息。
@Nullable
public static PackageInfo getPackageInfo(Context context, File sourceFile, int flags) {
String filePath = sourceFile.getAbsolutePath();
if (filePath.endsWith(SPLIT_BASE_APK_END_WITH)) { //SPLIT_BASE_APK_END_WITH:base.apk
File dir = sourceFile.getParentFile();
if (dir.listFiles().length > 1) {
// split apks, use file directory to get archive info
filePath = dir.getPath();
}
}
try {
return context.getPackageManager().getPackageArchiveInfo(filePath, flags);
} catch (Exception ignored) {
return null;
}
}
//PackageManager.java 解析apk后归档处理
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
@NonNull PackageInfoFlags flags) {
final File apkFile = new File(archiveFilePath);
...
try {
ParsedPackage pp = parser2.parsePackage(apkFile, parserFlags, false);
return PackageInfoCommonUtils.generate(pp, flagsBits, UserHandle.myUserId());
} catch (PackageParserException e) {
Log.w(TAG, "Failure to parse package archive apkFile= " +apkFile);
return null;
}
}
// frameworks/base/core/java/com/android/internal/pm/parsing/PackageParser2.java中继续调用ParsingPackageUtils.parsePackage()去解析APK包并返回一个解析结果,然后把解析结果放到缓存中去。
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
var files = packageFile.listFiles();
...
ParseResult<ParsingPackage> result = mParsingUtils.parsePackage(input, packageFile, flags);
...
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (mCacher != null) {
mCacher.cacheResult(packageFile, flags, parsed);
}
...
return parsed;
}
//ApkLiteParseUtils.java
private static ParseResult<ApkLite> parseApkLiteInner(ParseInput input,
File apkFile, FileDescriptor fd, String debugPathName, int flags) {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
XmlResourceParser parser = null;
ApkAssets apkAssets = null;
try {
...
parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
...
//解析APK的签名、使用的SDK版本、APK版本号等等
return parseApkLite(input, apkPath, parser, signingDetails, flags);
}
...
// TODO(b/72056911): Implement AutoCloseable on ApkAssets.
}
}
//ParsingPackageUtils.java
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags,
boolean shouldSkipComponents) {
final String apkPath = apkFile.getAbsolutePath();
final String volumeUuid = getVolumeUuid(apkPath);
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final AssetManager assets;
...
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
//解析Application下的四大组件
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags, shouldSkipComponents);
...
final ParsingPackage pkg = result.getResult();
...
return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
}
}
@Nullable
public static PackageInfo generate(@Nullable AndroidPackage pkg,
@PackageManager.PackageInfoFlagsBits long flags, int userId) {
if (pkg == null) {
return null;
}
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, userId);
PackageInfo info = new PackageInfo();
info.packageName = pkg.getPackageName();
...
if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
int size = ArrayUtils.size(pkg.getPermissions());
if (size > 0) {
info.permissions = new PermissionInfo[size];
for (int i = 0; i < size; i++) {
final var permission = pkg.getPermissions().get(i);
//把解析后的权限(比如组、权限类型)放到PermissionInfo中去
final var permissionInfo = generatePermissionInfo(permission, flags);
info.permissions[i] = permissionInfo;
}
}
//获取APP解析后的权限列表
final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
size = usesPermissions.size();
if (size > 0) {
info.requestedPermissions = new String[size];
info.requestedPermissionsFlags = new int[size];
for (int i = 0; i < size; i++) {
final ParsedUsesPermission usesPermission = usesPermissions.get(i);
info.requestedPermissions[i] = usesPermission.getName();
// The notion of required permissions is deprecated but for compatibility.
...
if (pkg.getImplicitPermissions().contains(info.requestedPermissions[i])) {
info.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_IMPLICIT;
}
}
}
}
...
return info;
}
//InstallInstalling.java
@Override
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) {
PackageInstaller installer = getPackageManager().getPackageInstaller();
//把包信息写入mSessionId对应的session
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
if (sessionInfo != null && !sessionInfo.isActive()) {
mInstallingTask = new InstallingAsyncTask();
...
}
}
}
//发送包到 installer
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
...
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
try {
//创建mSessionId对应的session
return getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
return null;
}
...
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
...
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
// Delay committing the session by 100ms to fix a UI glitch while displaying the
// Update-Owner change dialog on top of the Installing dialog
new Handler(Looper.getMainLooper()).postDelayed(() -> {
try {
//包写入session后,进行提交
session.commit(pendingIntent.getIntentSender());
} catch (Exception e) {
Log.e(LOG_TAG, "Cannot install package: ", e);
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
return;
}
}, 100);
...
}
...
}
}
//PackageInstallerSession.java
//根据session.commit()继续往下看具体做了哪些操作
private List<CompletableFuture<InstallResult>> installNonStaged() {
try {
...
final InstallingSession installingSession = createInstallingSession(future);
if (isMultiPackage()) {
...
if (!installingChildSessions.isEmpty()) {
Objects.requireNonNull(installingSession).installStage(installingChildSessions);
}
} else if (installingSession != null) {
installingSession.installStage();
}
return futures;
}
...
}
//frameworks/base/services/core/java/com/android/server/pm/InstallingSession.java
public void installStage() {
setTraceMethod("installStage").setTraceCookie(System.identityHashCode(this));
...
//安装走到了InstallingSession的start()中,并通过PackageManagerService的mHandler排队执行一个异步操作
mPm.mHandler.post(this::start);
}
public void installStage(List<InstallingSession> children)
throws PackageManagerException {
final MultiPackageInstallingSession installingSession =
new MultiPackageInstallingSession(getUser(), children, mPm); ...
//安装走到了InstallingSession的start()中,并通过PackageManagerService的mHandler排队执行一个异步操作
mPm.mHandler.post(installingSession::start);
}
private void handleStartCopy(InstallRequest request) {
if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
// For staged session, there is a delay between its verification and install. Device
// state can change within this delay and hence we need to re-verify certain conditions.
boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
if (isStaged) {
Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
mRet = ret.first;
if (mRet != INSTALL_SUCCEEDED) {
request.setError(mRet, "Failed to verify version code");
return;
}
}
final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
if (DEBUG_INSTANT && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
if (!mOriginInfo.mStaged && pkgLite.recommendedInstallLocation
== InstallLocationUtils.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// If we are not staged and have too little free space, try to free cache
// before giving up.
pkgLite.recommendedInstallLocation = mPm.freeCacheForInstallation(
pkgLite.recommendedInstallLocation, mPackageLite,
mOriginInfo.mResolvedPath, mPackageAbiOverride, mInstallFlags);
}
//Override install location based on default policy if needed.
mRet = overrideInstallLocation(pkgLite.packageName, pkgLite.recommendedInstallLocation,
pkgLite.installLocation);
if (mRet != INSTALL_SUCCEEDED) {
request.setError(mRet, "Failed to override installation location");
}
}
handleReturnCode()中只调用了processPendingInstall()
private void processPendingInstall(InstallRequest installRequest) {
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//如果前面校验ok,这里执行apk、NativeLibrary的拷贝
mRet = copyApk(installRequest);
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
F2fsUtils.releaseCompressedBlocks(
mPm.mContext.getContentResolver(), new File(installRequest.getCodePath()));
}
installRequest.setReturnCode(mRet);
if (mParentInstallingSession != null) {
//MultiPackageInstallingSession: 多个APK session发起安装请求
mParentInstallingSession.tryProcessInstallRequest(installRequest);
} else {
// Queue up an async operation since the package installation may take a little while.
mPm.mHandler.post(() -> processInstallRequests(
mRet == PackageManager.INSTALL_SUCCEEDED /* success */,
Collections.singletonList(installRequest)));
}
}
// processInstallRequests()主要做了两件事情:APEX安装、APK安装。这里主要讲解APK安装,他调用了processApkInstallRequests()方法来继续安装APK
private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) {
if (!success) {
//走到PackageManagerService中清除APK的相关缓存以及安装路径
for (InstallRequest request : installRequests) {
if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
cleanUpForFailedInstall(request);
}
}
} else {
//到PackageManagerService中调用InstallPackageHelper的installPackagesTraced()方法去开启安装;
//主要调用了installPackagesLI(requests);
mPm.installPackagesTraced(installRequests);
for (InstallRequest request : installRequests) {
//如果上面安装成功,就会移除包名和CodePath
doPostInstall(request);
}
}
for (InstallRequest request : installRequests) {
//安装后续:备份、可能的回滚、发送安装完成先关广播
mPm.restoreAndPostInstall(request);
}
}
@GuardedBy("mPm.mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
...
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
try {
...
//1.准备:分析当前安装状态,解析包并初始验证
preparePackageLI(request);
}
...
try {
//2.扫描:根据准备阶段解析的包信息上下文 进一步解析
final ScanResult scanResult = scanPackageTracedLI(request.getParsedPackage(),
request.getParseFlags(), request.getScanFlags(),
System.currentTimeMillis(), request.getUser(),
request.getAbiOverride());
...
//注册appId
createdAppId.put(packageName, optimisticallyRegisterAppId(request));
//保存version信息
versionInfos.put(packageName,
mPm.getSettingsVersionForPackage(packageToScan));
}
...
}
List<ReconciledPackage> reconciledPackages;
synchronized (mPm.mLock) {
try {
//3.核对:验证扫描后的包信息和系统状态,确保安装成功
reconciledPackages = ReconcilePackageUtils.reconcilePackages(
requests, Collections.unmodifiableMap(mPm.mPackages),
versionInfos, mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
mPm.mSettings, mPm.mInjector.getSystemConfig());
}
...
try {
//4.提交:提交扫描的包、更新系统状态。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。
commitPackagesLocked(reconciledPackages, mPm.mUserManager.getUserIds());
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//安装成功的后续才做:准备app数据、编译布局资源、执行dex优化
//执行dex优化:dexopt 是对 dex 文件 进行 verification 和 optimization 的操作,其对 dex 文件的优化结果变成了 odex 文件,这个文件和 dex 文件很像,只是使用了一些优化操作码(譬如优化调用虚拟指令等)。
executePostCommitStepsLIF(reconciledPackages);
} finally {
if (success) {
for (InstallRequest request : requests) {
...
//对于增量安装,我们在安装前绕过验证程序。既然我们已经知道软件包是有效的,那么向验证程序发送一条通知,其中包含 base.apk 的根哈希值。
//增量安装是一种安装方式,它仅更新软件包中发生变化的部分,而不是重新安装整个软件包。
final String rootHashString = PackageManagerServiceUtils
.buildVerificationRootHashString(baseCodePath, splitCodePaths);
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, rootHashString,
request.getDataLoaderType(), request.getUser(), mContext);
}
} ...
}
}
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
@GuardedBy("mPm.mInstallLock")
private void preparePackageLI(InstallRequest request) throws PrepareFailure {
...
// either use what we've been given or parse directly from the APK
if (request.getSigningDetails() != SigningDetails.UNKNOWN) {
parsedPackage.setSigningDetails(request.getSigningDetails());
} else {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
input, parsedPackage, false /*skipVerify*/);
if (result.isError()) {
throw new PrepareFailure("Failed collect during installPackageLI",
result.getException());
}
parsedPackage.setSigningDetails(result.getResult());
}
...
// Quick validity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
final SharedUserSetting signatureCheckSus = mPm.mSettings.getSharedUserSettingLPr(
signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, signatureCheckSus,
scanFlags)) {
...
}
//检查APK中的权限组;
final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
for (int groupNum = 0; groupNum < numGroups; groupNum++) {
final ParsedPermissionGroup group =
parsedPackage.getPermissionGroups().get(groupNum);
final PermissionGroupInfo sourceGroup = mPm.getPermissionGroupInfo(group.getName(),
0);
...
}
// TODO: Move logic for checking permission compatibility into PermissionManagerService
final int n = ArrayUtils.size(parsedPackage.getPermissions());
for (int i = n - 1; i >= 0; i--) {
final ParsedPermission perm = parsedPackage.getPermissions().get(i);
final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName());
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
...
}
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
final String sourcePackageName = bp.getPackageName();
if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
scanFlags)) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
...
} else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
// Prevent apps to change protection level to dangerous from any other
// type as this would allow a privilege escalation where an app adds a
// normal/signature permission in other app's group and later redefines
// it as dangerous leading to the group auto-grant.
...
}
}
...
}
}
...
if (!isApex) {
/**
* Rename package into final resting place. All paths on the given
* scanned package should be updated to reflect the rename.
*/
doRenameLI(request, parsedPackage);
...
}
...
}
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
@GuardedBy("mPm.mInstallLock")
private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
final @ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user, String cpuAbiOverride)
throws PackageManagerException {
final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags,
scanFlags, user, cpuAbiOverride);
...
synchronized (mPm.mLock) {
...
return ScanPackageUtils.scanPackageOnlyLI(request, mPm.mInjector, mPm.mFactoryTest,
currentTime);
}
}
//frameworks/base/services/core/java/com/android/server/pm/ScanPackageUtils.java
public static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
PackageManagerServiceInjector injector,
boolean isUnderFactoryTest, long currentTime)
throws PackageManagerException {
...
if (createNewPackage) {
...
// REMOVE SharedUserSetting from method; update in a separate call
pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
destCodeFile, parsedPackage.getNativeLibraryRootDir(),
AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user,
true /*allowInstall*/, instantApp, virtualPreload, isStoppedSystemApp,
UserManagerService.getInstance(), usesSdkLibraries,
parsedPackage.getUsesSdkLibrariesVersionsMajor(),
parsedPackage.getUsesSdkLibrariesOptional(), usesStaticLibraries,
parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(),
newDomainSetId,
parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash());
...
}
...
}
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos,
SharedLibrariesImpl sharedLibraries,
KeySetManagerService ksms, Settings settings, SystemConfig systemConfig)
throws ReconcileFailure {
final List<ReconciledPackage> result = new ArrayList<>(installRequests.size());
// make a copy of the existing set of packages so we can combine them with incoming packages
final ArrayMap<String, AndroidPackage> combinedPackages =
new ArrayMap<>(allPackages.size() + installRequests.size());
combinedPackages.putAll(allPackages);
//incomingSharedLibraries对象是安装包对象中声明的即将安装的库。
final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
new ArrayMap<>();
...
for (InstallRequest installRequest : installRequests) {
final String installPackageName = installRequest.getParsedPackage().getPackageName();
final List<SharedLibraryInfo> allowedSharedLibInfos =
sharedLibraries.getAllowedSharedLibInfos(installRequest);
...
//封装到ReconciledPackage对象的包括ReconcileRequest对象request、安装参数installArgs、新生成的PackageSettingscanResult.pkgSetting、安装信息res、准备结果对象、浏览结果对象、待删除包行动兑对象deletePackageAction、允许添加的包中的共享库信息、解析包签名信息对象、共享用户签名是否改变、是否删除签名信息removeAppKeySetData。
final ReconciledPackage reconciledPackage =
new ReconciledPackage(installRequests, allPackages, installRequest,
deletePackageAction, allowedSharedLibInfos, signingDetails,
sharedUserSignaturesChanged, removeAppKeySetData);
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this. We
// will take care of the system apps by updating all of their
// library paths after the scan is done. Also during the initial
// scan don't update any libs as we do this wholesale after all
// apps are scanned to avoid dependency based scanning.
...
try {
reconciledPackage.mCollectedSharedLibraryInfos =
sharedLibraries.collectSharedLibraryInfos(
installRequest.getParsedPackage(), combinedPackages,
incomingSharedLibraries);
}
...
}
return result;
}
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
@GuardedBy("mPm.mLock")
private void commitPackagesLocked(List<ReconciledPackage> reconciledPackages,
@NonNull int[] allUsers) {
// TODO: remove any expected failures from this method; this should only be able to fail due
// to unavoidable errors (I/O, etc.)
for (ReconciledPackage reconciledPkg : reconciledPackages) {
...
AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, allUsers);
updateSettingsLI(pkg, allUsers, installRequest);
...
if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
// If this is an archival installation then we'll initialize the archive status,
// while also marking package as not installed.
// Doing this at the very end of the install as we are using ps.getInstalled
// to figure out which users were changed.
...
}
}
...
}
private void updateSettingsLI(AndroidPackage newPackage,
int[] allUsers, InstallRequest installRequest) {
updateSettingsInternalLI(newPackage, allUsers, installRequest);
}
private void updateSettingsInternalLI(AndroidPackage pkg,
int[] allUsers, InstallRequest installRequest) {
...
synchronized (mPm.mLock) {
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
if (ps != null) {
...
final PermissionManagerServiceInternal.PackageInstalledParams.Builder
permissionParamsBuilder =
new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
//权限授权
final boolean grantRequestedPermissions = (installRequest.getInstallFlags()
& PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS) != 0;
if (grantRequestedPermissions) {
var permissionStates = new ArrayMap<String, Integer>();
for (var permissionName : pkg.getRequestedPermissions()) {
permissionStates.put(permissionName,
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED);
}
permissionParamsBuilder.setPermissionStates(permissionStates);
} else {
var permissionStates = installRequest.getPermissionStates();
if (permissionStates != null) {
permissionParamsBuilder
.setPermissionStates(permissionStates);
}
}
//记录受限的权限
final boolean allowlistAllRestrictedPermissions =
(installRequest.getInstallFlags()
& PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
final List<String> allowlistedRestrictedPermissions =
allowlistAllRestrictedPermissions
? new ArrayList<>(pkg.getRequestedPermissions())
: installRequest.getAllowlistedRestrictedPermissions();
if (allowlistedRestrictedPermissions != null) {
permissionParamsBuilder.setAllowlistedRestrictedPermissions(
allowlistedRestrictedPermissions);
}
//记录自动撤销权限模型
final int autoRevokePermissionsMode = installRequest.getAutoRevokePermissionsMode();
permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
//下面的方法将负责移除过时的权限并授予安装权限
mPm.mPermissionManager.onPackageInstalled(pkg, installRequest.getPreviousAppId(),
permissionParamsBuilder.build(), userId);
}
...
mPm.writeSettingsLPrTEMP();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
public void restoreAndPostInstall(InstallRequest request) {
...
if (succeeded && doRestore && !request.hasPostInstallRunnable()) {
boolean hasNeverBeenRestored =
packageSetting != null && packageSetting.isPendingRestore();
request.setPostInstallRunnable(() -> {
// Permissions should be restored on each user that has the app installed for the
// first time, unless it's an unarchive install for an archived app, in which case
// the permissions should be restored on each user that has the app updated.
int[] userIdsToRestorePermissions = hasNeverBeenRestored
? request.getUpdateBroadcastUserIds()
: request.getFirstTimeBroadcastUserIds();
for (int restorePermissionUserId : userIdsToRestorePermissions) {
//将应用程序在 AndroidManifest.xml 中声明的权限赋予用户,使得应用程序能够正常访问设备的各种资源
mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(),
restorePermissionUserId);
}
});
}
...
}
//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
@UserIdInt int userId) {
// We may also need to apply pending (restored) runtime permission grants
// within these users.
//未被使用的权限去做备份
mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
// Restore default browser setting if it is now installed.
String defaultBrowser;
synchronized (mLock) {
defaultBrowser = mSettings.getPendingDefaultBrowserLPr(userId);
}
if (Objects.equals(packageName, defaultBrowser)) {
mDefaultAppProvider.setDefaultBrowser(packageName, userId);
synchronized (mLock) {
mSettings.removePendingDefaultBrowserLPw(userId);
}
}
// Persistent preferred activity might have came into effect due to this
// install.
mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId);
}
用于系统定制开发中,不同的系统组件或特定应用之间需要进行深度的交互和协作,并且这些交互涉及到对系统资源的敏感访问。系统会为签名权限分配 signature 保护级别。
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
……
//证书信息在这里配置
signingConfigs {
main {
storeFile file("./platform.jks") //签名文件路径,根目录
storePassword "skg202302"
keyAlias "skg"
keyPassword "skg202302"
}
}
……
}
在 Android 中,每个 APK 都必须进行签名校验,确保 APK 文件没有被篡改。签名校验是通过 PackageManager调用 PackageParser2来进行解析获取的。在Android原生的源码路径:frameworks/base/core/java/com/android/internal/pm/parsing/PackageParser2.java。如果解析异常会报异常。
解析到最后会调用ParsingPackageUtils.parseBaseApk()去解析包,调用setSigningDetails()去设置签名;
ParseResult<ParsingPackage> result = mParsingUtils.parsePackage(input, packageFile, flags);
if (result.isError()) {
throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
result.getException());
}
//frameworks/base/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
final ParseResult<SigningDetails> ret =
getSigningDetails(input, pkg, false /*skipVerify*/);
if (ret.isError()) {
return input.error(ret);
}
pkg.setSigningDetails(ret.getResult());
} else {
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}
当(flags & PARSE_COLLECT_CERTIFICATES) != 0为true时,会调用ApkSignatureVerifier(frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java).verifySignaturesInternal()去校验签名;
/**
* Verifies the provided APK using all allowed signing schemas.
* @return the certificates associated with each signer and content digests.
* @param verifyFull whether to verify all contents of this APK or just collect certificates.
* @hide
*/
public static ParseResult<SigningDetailsWithDigests> verifySignaturesInternal(ParseInput input,
String apkPath, @SignatureSchemeVersion int minSignatureSchemeVersion,
boolean verifyFull) {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V4) {
// V4 and before are older than the requested minimum signing version
return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// first try v4
try {
//V4是V3或者V2的一个升级版验证方式
//虽然调用的是V4,内部实现还是会先用到V3去校验
//如果V3不行的话会使用V2去实现校验
return verifyV4Signature(input, apkPath, minSignatureSchemeVersion, verifyFull);
} catch (SignatureNotFoundException e) {
// not signed with v4, try older if allowed
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V4) {
return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v4 signature in package " + apkPath, e);
}
}
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
// V3 and before are older than the requested minimum signing version
return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
//如果V4验证失败会采用V3认证的方式;
//无论V4还是V3都会使用ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
return verifyV3AndBelowSignatures(input, apkPath, minSignatureSchemeVersion, verifyFull);
}
以V4校验方式为例,frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java中,先得到最好算法对应的JCA算法,再得到最好算法对应的JCA签名算法和参数。之后得到公钥,然后通过公钥验证signed data和签名bestSigAlgorithmSignatureBytes。如果验证没通过,会报SecurityException异常。
private static Pair<Certificate, byte[]> verifySigner(V4Signature.SigningInfo signingInfo,
final byte[] signedData) throws SecurityException {
if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) {
throw new SecurityException("No supported signatures found");
}
final int signatureAlgorithmId = signingInfo.signatureAlgorithmId;//获取签名算法的ID
final byte[] signatureBytes = signingInfo.signature;//获取签名
final byte[] publicKeyBytes = signingInfo.publicKey;//获取公钥
final byte[] encodedCert = signingInfo.certificate;//获取证书
String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(signatureAlgorithmId);
Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams =
getSignatureAlgorithmJcaSignatureAlgorithm(signatureAlgorithmId);//JCA 签名算法。
String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
boolean sigVerified;
try {
PublicKey publicKey =
KeyFactory.getInstance(keyAlgorithm)
.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
sig.initVerify(publicKey);
if (jcaSignatureAlgorithmParams != null) {
sig.setParameter(jcaSignatureAlgorithmParams);
}
sig.update(signedData);
sigVerified = sig.verify(signatureBytes);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException
| InvalidAlgorithmParameterException | SignatureException e) {
throw new SecurityException(
"Failed to verify " + jcaSignatureAlgorithm + " signature", e);
}
if (!sigVerified) {
throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
}
// Signature over signedData has verified.
CertificateFactory certFactory;
try {
certFactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
}
X509Certificate certificate;
try {
certificate = (X509Certificate)
certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
} catch (CertificateException e) {
throw new SecurityException("Failed to decode certificate", e);
}
certificate = new VerbatimX509Certificate(certificate, encodedCert);
byte[] certificatePublicKeyBytes = certificate.getPublicKey().getEncoded();
if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
throw new SecurityException(
"Public key mismatch between certificate and signature record");
}
return Pair.create(certificate, signingInfo.apkDigest);
}
四种应用签名校验方案:
确认应用声明的权限是否符合系统要求,源码路径:frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
在安装过程中,InstallPackageHelper在准备安装的时候调用preparePackageLI(),主要做了以下几件事情:
@GuardedBy("mPm.mInstallLock")
private void preparePackageLI(InstallRequest request) throws PrepareFailure {
final int[] allUsers = mPm.mUserManager.getUserIds();
// 要么使用我们已获得的签名内容,要么直接从 APK 中解析签名内容。
if (request.getSigningDetails() != SigningDetails.UNKNOWN) {
parsedPackage.setSigningDetails(request.getSigningDetails());
} else {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(input, parsedPackage, false /*skipVerify*/);
if (result.isError()) {
throw new PrepareFailure("Failed collect during installPackageLI",
result.getException());
}
parsedPackage.setSigningDetails(result.getResult());
}
...
PackageSetting signatureCheckPs = ps;
if (signatureCheckPs != null) {
// 快速有效性检查,以确认在更新时我们是否正确签名;我们将在扫描时再次检查此项,但在此处,我们希望在遇到重新定义的权限问题之前尽早退出。
final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
final SharedUserSetting signatureCheckSus = mPm.mSettings.getSharedUserSettingLPr(signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, signatureCheckSus,
scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ parsedPackage.getPackageName() + " upgrade keys do not match the "
+ "previously installed version");
}
} else {
try {
final boolean compareCompat =
ReconcilePackageUtils.isCompatSignatureUpdateNeeded(
mPm.getSettingsVersionForPackage(parsedPackage));
final boolean compareRecover =
ReconcilePackageUtils.isRecoverSignatureUpdateNeeded(
mPm.getSettingsVersionForPackage(parsedPackage));
// We don't care about disabledPkgSetting on install for now.
final boolean compatMatch =
PackageManagerServiceUtils.verifySignatures(signatureCheckPs,
signatureCheckSus, null,
parsedPackage.getSigningDetails(), compareCompat, compareRecover,
isRollback);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPm.mLock) {
ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
}
}
} catch (PackageManagerException e) {
throw new PrepareFailure(e.error, e.getMessage());
}
}
}
// TODO: Move logic for checking permission compatibility into PermissionManagerService
final int n = ArrayUtils.size(parsedPackage.getPermissions());
for (int i = n - 1; i >= 0; i--) {
final ParsedPermission perm = parsedPackage.getPermissions().get(i);
final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName());
// 除了系统之外,不允许任何一方定义临时权限。
if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
&& !systemApp) {
Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
+ " attempting to delcare ephemeral permission "
+ perm.getName() + "; Removing ephemeral.");
ComponentMutateUtils.setProtectionLevel(perm,
perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
}
// 检查新扫描的包是否想要定义一个已经被定义过的权限。
if (bp != null) {
final String sourcePackageName = bp.getPackageName();
if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
scanFlags)) {
// 如果拥有该包的是系统本身,我们会记录日志,但允许继续安装;对于所有其他权限的重新定义情况,我们会使安装失败。
if (!sourcePackageName.equals("android")) {
throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION,
"Package "
+ parsedPackage.getPackageName()
+ " attempting to redeclare permission "
+ perm.getName() + " already owned by "
+ sourcePackageName)
.conflictsWithExistingPermission(perm.getName(),
sourcePackageName);
} else {
Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ " attempting to redeclare system permission "
+ perm.getName() + "; ignoring new declaration");
parsedPackage.removePermission(i);
}
} else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
// 防止应用程序将保护级别从任何其他类型更改为 “危险”,因为这会允许权限提升,即一个应用程序在另一个应用程序的组中添加一个普通 / 签名权限,然后将其重新定义为 “危险”,从而导致该组自动授予权限。
if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS) {
if (!bp.isRuntime()) {
Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+ " trying to change a non-runtime permission "
+ perm.getName()
+ " to runtime; keeping old protection level");
ComponentMutateUtils.setProtectionLevel(perm,
bp.getProtectionLevel());
}
}
}
}
...
}
private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
@NonNull ParsedPackage parsedPackage, int scanFlags) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final PackageSetting sourcePackageSetting;
final KeySetManagerService ksms;
final SharedUserSetting sharedUserSetting;
synchronized (mPm.mLock) {
sourcePackageSetting = mPm.mSettings.getPackageLPr(sourcePackageName);
ksms = mPm.mSettings.getKeySetManagerService();
sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(sourcePackageSetting);
}
final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, sharedUserSetting, scanFlags))) {
return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourceSigningDetails.checkCapability(
parsedPackage.getSigningDetails(),
SigningDetails.CertCapabilities.PERMISSION)) {
return true;
} else if (parsedPackage.getSigningDetails().checkCapability(
sourceSigningDetails,
SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
synchronized (mPm.mLock) {
sourcePackageSetting.setSigningDetails(parsedPackage.getSigningDetails());
}
return true;
} else {
return false;
}
}
}
在应用安装时,frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 会调用 grantPermissions() 方法来根据 AndroidManifest.xml 中声明的权限,为应用授予相应的权限。
`在应用安装提交时,frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java 会调用 commitPackageSettings() 方法提交相关的设置;来根据 AndroidManifest.xml 中声明的权限,为应用授予相应的权限。
/**
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
*/
private void commitPackageSettings(@NonNull AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
ReconciledPackage reconciledPkg) {
final String pkgName = pkg.getPackageName();
...
// If the app metadata file path is not null then this is a system app with a preloaded app
// metadata file on the system image. Do not reset the path and source if this is the
// case.
if (pkgSetting.getAppMetadataFilePath() == null) {
String dir = pkg.getPath();
if (pkgSetting.isSystem()) {
dir = Environment.getDataDirectoryPath() + "/app-metadata/" + pkg.getPackageName();
}
String appMetadataFilePath = dir + "/" + APP_METADATA_FILE_NAME;
if (request.hasAppMetadataFile()) {
pkgSetting.setAppMetadataFilePath(appMetadataFilePath);
if (Flags.aslInApkAppMetadataSource()) {
pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
}
} else if (Flags.aslInApkAppMetadataSource()) {
Map<String, PackageManager.Property> properties = pkg.getProperties();
if (properties.containsKey(PROPERTY_ANDROID_SAFETY_LABEL)) {
// ASL file extraction is done in post-install
pkgSetting.setAppMetadataFilePath(appMetadataFilePath);
pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_APK);
}
}
}
if (pkg.getPackageName().equals("android")) {
mPm.setPlatformPackage(pkg, pkgSetting);
}
if ((scanFlags & SCAN_BOOTING) != 0) {
// No apps can run during boot scan, so they don't need to be frozen
} else if ((scanFlags & SCAN_DONT_KILL_APP) != 0) {
// Caller asked to not kill app, so it's probably not frozen
} else if ((scanFlags & SCAN_IGNORE_FROZEN) != 0) {
// Caller asked us to ignore frozen check for some reason; they
// probably didn't know the package name
} else {
// 显示APP
mPm.snapshotComputer().checkPackageFrozen(pkgName);
}
final boolean isReplace = request.isInstallReplace();
// Also need to kill any apps that are dependent on the library, except the case of
// installation of new version static shared library.
if (clientLibPkgs != null) {
if (pkg.getStaticSharedLibraryName() == null || isReplace) {
for (int i = 0; i < clientLibPkgs.size(); i++) {
AndroidPackage clientPkg = clientLibPkgs.get(i);
String packageName = clientPkg.getPackageName();
mPm.killApplication(packageName,
clientPkg.getUid(), "update lib",
ApplicationExitInfo.REASON_DEPENDENCY_DIED);
}
}
}
// writer
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
synchronized (mPm.mLock) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mPm.mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPm.mPackages.put(pkg.getPackageName(), pkg);
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
mApexManager.registerApkInApex(pkg);
}
if ((mPm.isDeviceUpgrading() && pkgSetting.isSystem()) || isReplace) {
for (int userId : mPm.mUserManager.getUserIds()) {
pkgSetting.restoreComponentSettings(userId);
}
}
// Don't add keysets for APEX as their package settings are not persisted and will
// result in orphaned keysets.
if ((scanFlags & SCAN_AS_APEX) == 0) {
// Add the package's KeySets to the global KeySetManagerService
KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
ksms.addScannedPackageLPw(pkg);
}
final Computer snapshot = mPm.snapshotComputer();
mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
mPm.mAppsFilter.addPackage(snapshot, pkgSetting, isReplace,
(scanFlags & SCAN_DONT_KILL_APP) != 0 /* retainImplicitGrantOnReplace */);
mPm.addAllPackageProperties(pkg);
// Only verify app links for non-archival installations, otherwise there won't be any
// declared app links.
if (!request.isArchived()) {
if (oldPkgSetting == null || oldPkgSetting.getPkg() == null) {
mPm.mDomainVerificationManager.addPackage(pkgSetting,
request.getPreVerifiedDomains());
} else {
mPm.mDomainVerificationManager.migrateState(oldPkgSetting, pkgSetting,
request.getPreVerifiedDomains());
}
}
int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
StringBuilder r = null;
int i;
for (i = 0; i < collectionSize; i++) {
ParsedInstrumentation a = pkg.getInstrumentations().get(i);
ComponentMutateUtils.setPackageName(a, pkg.getPackageName());
mPm.addInstrumentation(a.getComponentName(), a);
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.getName());
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
final List<String> protectedBroadcasts = pkg.getProtectedBroadcasts();
if (!protectedBroadcasts.isEmpty()) {
synchronized (mPm.mProtectedBroadcasts) {
mPm.mProtectedBroadcasts.addAll(protectedBroadcasts);
}
}
mPm.mPermissionManager.onPackageAdded(pkgSetting,
(scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
为危险权限设置成默认权限有两种方式:
只有经过系统签名的系统应用才可能被授予某些特殊权限。例如,某些系统级应用才具备的访问底层硬件驱动、修改系统设置、管理其他应用进程等权限。并且只有平台和原始设备制造商 (OEM) 可以定义特殊权限。一些特殊权限示例:设定精确的闹钟、在其他应用前方显示和绘图、访问所有存储数据。
系统会为特殊权限分配 appop 保护级别。