在app代码中,如果想安装另一个应用,一般通过下列代码实现,调用后会显示系统安装界面
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType("the apkPath of app...",
"application/vnd.android.package-archive");
startActivity(intent);
系统安装界面是com.android.packageinstaller.PackageInstallerActivity,它在manifest里的声明是
".PackageInstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true">
"1">
"android.intent.action.VIEW" />
"android.intent.action.INSTALL_PACKAGE" />
"android.intent.category.DEFAULT" />
"file" />
"application/vnd.android.package-archive" />
"1">
"android.intent.action.INSTALL_PACKAGE" />
"android.intent.category.DEFAULT" />
"file" />
"package" />
"1">
"android.content.pm.action.CONFIRM_PERMISSIONS" />
"android.intent.category.DEFAULT" />
可以看到这个activity支持三种action,VIEW、INSTALL_PACKAGE、CONFIRM_PERMISSIONS,其中VIEW和INSTALL_PACKAGE都可以启动应用的安装。
PackageInstallerActivity根据用户设置(比如是否允许安装未知来源的应用等)进行一些检查,同时查询应用需要的权限进行显示,在用户点击“安装”以后,启动界面InstallAppProgress进行安装。这里整个流程比较简单,不再贴代码进行分析了,不过其中获取应用信息、获取权限信息的调用可以学习一下。
在流程的最后,调用了PMS.installPackageWithVerificationAndEncryption()正式进入安装流程
通过context.getPackageManager得到的PackageManager实际上是ApplicationPackageManager的实例,所以调用到的就是
/**
* packageURI -- 要安装的apk的uri
* obesrver -- 安装过程的观察者
* flags -- 这个流程里,表示是否覆盖安装,当然其他流程中会有其他值
* installerPackageName -- 安装者的包名
* verificationParams -- 一些校验参数,后续流程中看它的具体使用
* encryptionParams -- 一些加密参数,这个流程里是null
**/
@Override
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, encryptionParams);
}
installCommon在校验参数之后调用了PMS.installPackage,然后调用到PMS.installPackageAsUser
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {
// 主要做几个事情,1、检查安装者权限;2、更新flag;3、创建UserHandle实例;4、创建OriginInfo
// ...
// 这里的Handler是内部类PackageHandler
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
}
PackageHandler的message处理方法如下,这里先仅列出两个事件的处理
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (!mBound) {
if (!connectToService()) {
params.serviceError();
return;
} else {
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
case MCS_BOUND: {
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
if (!mBound) {
// 异常情况处理
}
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
if (params.startCopy()) {
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
sendMessageDelayed(ubmsg, 10000);
}
} else {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
// 异常情况,打印log
}
break;
}
}
}
仔细看一下,安装过程是需要调用IMediaContainerService mContainerService的,在第一次调用到INIT_COPY的时候还没有bindService,所以mBound是false,mContainerService的是空,所以要先调用connectToService,然后把安装参数add到pending队列,在bindService成功后,会发送MCS_BOUND事件,mContainerService会被赋值为DefaultContainerService.IMediaContainerService.Stub实例,然后开始处理pending队列。
真正的处理从InstallParams.startCopy()开始,依次调用handleStartCopy()和handleReturnCode()
final boolean startCopy() {
boolean res;
try {
if (++mRetries > MAX_RETRIES) {
// 超过重试次数
return false;
} else {
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
// ...
}
handleReturnCode();
return res;
}
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
if (origin.staged) {
// 第一次是false,这里更新installFlags
}
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// 异常情况
} else {
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// 没有足够的安装空间
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// 前面的流程没有异常就会走到这里
int loc = pkgLite.recommendedInstallLocation;
if (loc == ***) {
// 各种异常的流程的处理,对ret赋值
} else {
// 再次对安装位置进行调整
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (!onSd && !onInt) {
// 调整installFlags
}
}
}
// 根据安装位置创建InstallArgs实例,这里以FileInstallArgs为例走流程
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
/*
* ADB installs appear as UserHandle.USER_ALL, and can only be performed by
* UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
*/
int userIdentifier = getUser().getIdentifier();
if (userIdentifier == UserHandle.USER_ALL
&& ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
userIdentifier = UserHandle.USER_OWNER;
}
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, userIdentifier);
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(userIdentifier, installFlags)) {
// 如果需要验证应用(android的安全机制)
} else {
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
以FileInstallArgs为例,看一下copyApk的实现
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
// 已经stage,直接返回
}
try {
// 创建/data/app下的安装路径,同时修改为755权限
final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
// ...
}
};
int ret = PackageManager.INSTALL_SUCCEEDED;
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
return ret;
}
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(codeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
abiOverride);
} catch (IOException e) {
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
实现的逻辑比较清晰,执行copyApk的结果就是生成了以下文件
..data
….app
……com.fr.demo
……..base.apk
……..lib
……….x86 –
因为是用模拟器运行,所以是x86
…………libxxx.so
然后执行handleReturnCode方法,该方法直接调用processPendingInstall,所以直接看一下processPendingInstall的实现,如下列代码中的注释,一共5步
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
// ...
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// 1. preInsall
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
// 2. install
installPackageLI(args, res);
}
// 3. postInstall
args.doPostInstall(res.returnCode, res.uid);
}
// 4. do restore or not
// ...
// 5. handler, handle(POST_INSTALL)
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
});
}
还是以FileInstallArgs为例,分别看一下上述5步的实现
正常流程下,可以看到,什么都不做直接返回
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
````
"se-preview-section-delimiter">
#### installPackage
首先调用的是installPackageLI方法,这个方法有很多行,主要做的是收集包信息,检查是否覆盖安装、manifest签名是否正确等,最后的安装调用的是installNewPackageLI方法,如果是覆盖安装就调用replacePackageLI,这里看一下新安装的情况
"se-preview-section-delimiter">
```java
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
// 可能存在的重复包的检查
// ...
try {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
// ...
} catch (PackageManagerException e) {
}
}
一共会调用两个方法
scanPackageLI会调用,这个方法实在太长,下面的代码中做了大量精简,主要是把处理系统app和覆盖安装的部分删掉了,即使这样,还是有很多细节看不太明白
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
final File scanFile = new File(pkg.codePath);
pkg.coreApp = false;
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
setUpCustomResolverActivity(pkg);
}
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
// writer
synchronized (mPackages) {
// Check if we are renaming from an original package name.
PackageSetting origPackage = null;
String realName = null;
// 1、创建PackageSetting,PackageSetting保存了包从一些信息
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi,
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
user, false);
if (realName != null) {
// Make a note of it.
mTransferedPackages.add(pkg.packageName);
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// 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.
updateSharedLibrariesLPw(pkg, null);
}
if (mFoundPolicyFile) {
SELinuxMMAC.assignSeinfoValue(pkg);
}
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags)) {
// ...
} else {
try {
verifySignaturesLP(pkgSetting, pkg);
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} catch (PackageManagerException e) {
// ...
}
}
// Verify that this new package doesn't have any content providers
// that conflict with existing packages. Only do this if the
// package isn't already installed, since we don't want to break
// things that are installed.
// 2、检查将要安装的apk的content provider是否跟已有的冲突
if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
final int N = pkg.providers.size();
int i;
for (i=0; iif (p.info.authority != null) {
String names[] = p.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
if (mProvidersByAuthority.containsKey(names[j])) {
throw new PackageManagerException("....");
}
}
}
}
}
// 权限管理?
if (pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
// ...
}
}
}
final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
// ...
} else {
// This is a normal package, need to make its data directory.
dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid,
UserHandle.USER_OWNER, pkg.packageName);
boolean uidError = false;
if (dataPath.exists()) {
// 如果已经存在,表示跟当前安装的包跟以前的包存在相同的data路径,做异常处理
} else {
// 3、正常流程,创建data目录
int ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
pkg.applicationInfo.dataDir = null;
}
}
pkgSetting.uidError = uidError;
}
final String path = scanFile.getPath();
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
// 4、设置native lib path
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
// 不是新装包
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
// We haven't run dex-opt for this move (since we've moved the compiled output too)
// but we already have this packages package info in the PackageSetting. We just
// use that and derive the native library path based on the new codepath.
pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
}
// Set native library paths again. For moves, the path will be updated based on the
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
setNativeLibraryPaths(pkg);
}
final int[] userIds = sUserManager.getUserIds();
synchronized (mInstallLock) {
// Make sure all user data directories are ready to roll; we're okay
// if they already exist
if (!TextUtils.isEmpty(pkg.volumeUuid)) {
for (int userId : userIds) {
if (userId != 0) {
mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
pkg.applicationInfo.seinfo);
}
}
}
// Create a native library symlink only if we have native libraries
// and if the native libraries are 32 bit libraries. We do not provide
// this symlink for 64 bit libraries.
if (pkg.applicationInfo.primaryCpuAbi != null &&
!VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
// 处理32位lib
}
}
// This is a special case for the "system" package, where the ABI is
// dictated by the zygote configuration (and init.rc). We should keep track
// of this ABI so that we can deal with "normal" applications that run under
// the same UID correctly.
if (mPlatformPackage == pkg) {
// system app
}
// If there's a mismatch between the abi-override in the package setting
// and the abiOverride specified for the install. Warn about this because we
// would've already compiled the app without taking the package setting into
// account.
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
" for package: " + pkg.packageName);
}
}
pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
// Copy the derived override back to the parsed package, so that we can
// update the package settings accordingly.
pkg.cpuAbiOverride = cpuAbiOverride;
// Push the derived path down into PackageSettings so we know what to
// clean up at uninstall time.
pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
if ((scanFlags&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
//
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0);
}
// 5、做dexOpt
if ((scanFlags & SCAN_NO_DEX) == 0) {
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
}
}
if (mFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
// ...
}
ArrayList clientLibPkgs = null;
// writer
synchronized (mPackages) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// 只有system app会走到这里
}
}
// We also need to dexopt any apps that are dependent on this library. Note that
// if these fail, we should abort the install since installing the library will
// result in some apps being broken.
if (clientLibPkgs != null) {
// 只有system app会走到这里
}
if ((scanFlags & SCAN_REPLACING) != 0) {
// 覆盖安装
}
// Also need to kill any apps that are dependent on the library.
if (clientLibPkgs != null) {
// 只有system app会走到这里
}
// Make sure we're not adding any bogus keyset info
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
// writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
final Iterator iter = mSettings.mPackagesToBeCleaned.iterator();
while (iter.hasNext()) {
PackageCleanItem item = iter.next();
if (pkgName.equals(item.packageName)) {
iter.remove();
}
}
// 更新pkgSetting的firstInstallTime、lastUpdateTime
// ...
// Add the package's KeySets to the global KeySetManagerService
ksms.addScannedPackageLPw(pkg);
// 处理应用中的provider,把provider信息存储在mProviders和mProvidersByAuthority
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i// ...
}
// 处理应用中的service,把provider信息存储在mServices
N = pkg.services.size();
r = null;
for (i=0; i// ...
}
// 处理应用中的receiver,把provider信息存储在mReceivers
N = pkg.receivers.size();
r = null;
for (i=0; i// ...
}
// 处理应用中的activity,把provider信息存储在mActivities
N = pkg.activities.size();
r = null;
for (i=0; i// ...
}
// 处理应用中的permissson,把provider信息存储在mPermissionGroups
N = pkg.activities.size();
N = pkg.permissionGroups.size();
r = null;
for (i=0; i// ...
}
// 处理应用中的permissson,把provider信息存储在mPermissionGroups
N = pkg.activities.size();
N = pkg.permissions.size();
r = null;
for (i=0; i// 处理Instrumentation,注意这里有各种路径的赋值,包括nativeLibraryDir
N = pkg.instrumentation.size();
r = null;
for (i=0; i// TODO: Update instrumentation.nativeLibraryDir as well ? Does it
// need other information about the application, like the ABI and what not ?
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
}
if (pkg.protectedBroadcasts != null) {
N = pkg.protectedBroadcasts.size();
for (i=0; i// Create idmap files for pairs of (packages, overlay packages).
// Note: "android", ie framework-res.apk, is handled by native layers.
if (pkg.mOverlayTarget != null) {
// This is an overlay package.
if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
mOverlays.put(pkg.mOverlayTarget,
new ArrayMap());
}
ArrayMap map = mOverlays.get(pkg.mOverlayTarget);
map.put(pkg.packageName, pkg);
PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"scanPackageLI failed to createIdmap");
}
}
} else if (mOverlays.containsKey(pkg.packageName) &&
!pkg.packageName.equals("android")) {
// This is a regular package, with one or more known overlay packages.
createIdmapsForPackageLI(pkg);
}
}
return pkg;
}
上面是总结出来的个人认为比较主要的流程
之后,更新PackageSetting
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
UserHandle user) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
// 1. 状态设置为未完成
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
mSettings.writeLPr();
}
synchronized (mPackages) {
// 2. 更新权限信息,同时申请必要的权限(6.0以下的所有权限和6.0以上的基本权限)
updatePermissionsLPw(newPackage.packageName, newPackage,
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
// 3. 更新状态
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (isSystemApp(newPackage)) {
// ...
}
// It's implied that when a user requests installation, they want the app to be
// installed and enabled.
int userId = user.getIdentifier();
if (userId != UserHandle.USER_ALL) {
ps.setInstalled(true, userId);
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
}
}
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLPr();
}
}
int doPostInstall(int status, int uid) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
调用BackupManager进行restore,即应用的备份,为以后的恢复做准备
根据需要处理动态权限申请,之后发送广播,最后通知观察者,也就是之前的安装界面
整个安装流程上看比较清晰,不过细节很多,还是有很多地方不太明白。其中包的解析,权限的处理,provider等的处理可以仔细再看一看。dexopt也可以看一下。
根据需要处理动态权限申请,之后发送广播,最后通知观察者,也就是之前的安装界面
整个安装流程上看比较清晰,不过细节很多,还是有很多地方不太明白。其中包的解析,权限的处理,provider等的处理可以仔细再看一看。dexopt也可以看一下。
The Dalvik optimizer does the following: