接着上节的内容来说,之前说到了PackageInstallerSession中调用PackageManaPgerService(简称PMS)的installStage这个方法来完成后续的安装流程
下面的流程基本的都是在PMS中进行的,我们来看下流程
1、PackageManaPgerService#installStage
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
if (DEBUG_EPHEMERAL) {
if ((sessionParams.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
Slog.d(TAG, "Ephemeral install of " + packageName);
}
}
final VerificationInfo verificationInfo = new VerificationInfo(
sessionParams.originatingUri, sessionParams.referrerUri,
sessionParams.originatingUid, installerUid);
final OriginInfo origin;
if (stagedDir != null) {
origin = OriginInfo.fromStagedFile(stagedDir);
} else {
origin = OriginInfo.fromStagedContainer(stagedCid);
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
//实例化一个安装参数,里面有传进来的安装信息
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions, certificates);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
//发送一个INIT_COPY 的message
mHandler.sendMessage(msg);
}
这个方法就干了一个事情,发送了一个首次copy的消息,然后处理,看看这个handler怎么处理的
2、PackageManaPgerService#doHandleMessage
void doHandleMessage(Message msg) {
switch (msg.what) {
//这个就是发来的消息
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// If a bind was already initiated we dont really
// need to do anything. The pending install
// will be processed later on.
//启动pms的时候 mContainerService 服务已经被绑定了
if (!mBound) {
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
// If this is the only one pending we might
// have to bind to the service again.
// 尝试绑定服务,这里就是bindService
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
params.traceCookie);
}
return;
} else {
// Once we bind to the service, the first
// pending request will be processed.
//绑定成功就添加一个待copy的apk 数据 等待copy
//每次连接成功都会发送一个MCS_BOUND 消息 然后处理copy任务,
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (idx == 0) {
//触发下面的MCS_BOUND,进行拷贝apk,然后就是不断循环,消耗
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
System.identityHashCode(mHandler));
}
if (mContainerService == null) {
if (!mBound) {
// Something seriously wrong since we are not bound and we are not
// waiting for connection. Bail out.
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
params.serviceError();
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
if (params.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
params.traceMethod, params.traceCookie);
}
return;
}
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
//开始拷贝
if (params.startCopy()) {
// We are done... look for more work or to
// go idle.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Checking for more work or unbind...");
// Delete pending install
if (mPendingInstalls.size() > 0) {
//拷贝成功了就移除拷贝任务数据
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
//数据没有了 等待10s 就断开服务
sendMessageDelayed(ubmsg, 10000);
}
} else {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing
// of next pending install.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting MCS_BOUND for next work");
//如果数据还有就继续执行下一个copy
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
x
x
x
x
x
x
x 省略代码,,,
总结:
目的:把apk从PackageInstallerSession的暂存目录中 复制到data/app/ 目录下面 或则sdcard的目录下面,这个根据安装参数的flag来区分,为后续工作做准备
过程:
1、这个复制的过程是交给DefaultContainerService 这个服务去做的,这个服务在单独的进程
2、每次需要复制的时候先连接服务
private boolean connectToService() {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
" DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
//可以看到是通过bind方式的
if (mContext.bindServiceAsUser(service, mDefContainerConn,
Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
3、然后启动了这个服务,在这个同时做了这个操作 mPendingInstalls.add(idx, params); 还有发送了一个MCS_BOUND消息给handler执行拷贝,这个消息是绑定服务成功后做的事情
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
IMediaContainerService imcs =
IMediaContainerService.Stub.asInterface(service);
//可以看到绑定成功发送了一个MCS_BOUND消息,可以完成后续的拷贝工作
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
}
}
4、MCS_BOUND 的指令下 最后调用了HandlerParams的startCopy方法,HandlerParams是一个抽象类,这里用的实现类是InstallParams ,这里多说一句HandlerParams的实现类有2种MeasureParams,和InstallParams ,
MeasureParams 是测量的作用,计算apk所占用的空间大小
InstallParams 是安装apk的拷贝作用,处理拷贝的任务
HandlerParams的startCopy方法最终会依次调用到handleStartCopy() 还有handleReturnCode() 两个方法
handleStartCopy处理拷贝,需要子类实现
handleReturnCode 处理返回结果,引发后续流程,需要子类实现
5、InstallParams 的handleStartCopy
......省略......
} else {
/*
* No package verification is enabled, so immediately start
* the remote call to initiate copy using temporary file.
*/
ret = args.copyApk(mContainerService, true);
}
我们看到这个arsg 其实是
final InstallArgs args = createInstallArgs(this);
createInstallArgs方法是
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
}
这里有三个实现类,
MoveInstallArgs :是处理已经安装了的apk的数据转移的
AsecInstallArgs:这个是处理asec 就是在sdcard安装apk的拷贝类型
FileInstallArgs:这个就是系统内存储的,拷贝到data/app/ 下的类型
我们就来看下FileInstallArgs类型的copyApk
最终 调用了doCopyApk,
private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
//从PackageInstallerService 获取目录,这个最终是在Environment中设置好的
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
//这个是跨进程 实现文件流的读写作用的类,下面很明显是根据文件名称,然后实例化一个文件描述符,最终转为Out流,进行读写
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
@Override
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid filename: " + name);
}
try {
final File file = new File(codeFile, name);
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
O_RDWR | O_CREAT, 0644);
Os.chmod(file.getAbsolutePath(), 0644);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw new RemoteException("Failed to open: " + e.getMessage());
}
}
};
int ret = PackageManager.INSTALL_SUCCEEDED;
//最终调用了DefaultContainerService 的 copyPackage方法
ret = imcs.copyPackage(.getAbsolutePaorigin.fileth(), target);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
//下面是so库的拷贝
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) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
最后在看下DafaultContainerService的拷贝实现
@Override
public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
if (packagePath == null || target == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
//这个是轻量化的apk包,这个包有可能是一个apk文件是全量的,有可能是一个apk的目录,李米娜有很多的子apk。还有其他文件,这种情况是因为方法数65535超过后,google做的把apk拆分的策略
PackageLite pkg = null;
try {
final File packageFile = new File(packagePath);
pkg = PackageParser.parsePackageLite(packageFile, 0);
return copyPackageInner(pkg, target);
} catch (PackageParserException | IOException | RemoteException e) {
Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
}
下面是后续实现
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
throws IOException, RemoteException {
copyFile(pkg.baseCodePath, target, "base.apk");
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
//看到如果是多个apk就是splitNames 数组 多个了,以此都要拷贝
for (int i = 0; i < pkg.splitNames.length; i++) {
copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
}
}
//拷贝完成就返回成功
return PackageManager.INSTALL_SUCCEEDED;
}
private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
throws IOException, RemoteException {
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(sourcePath);
out = new ParcelFileDescriptor.AutoCloseOutputStream(
//这里这个open 就是前面的 open 传过来的的ParcelFileDescriptor
target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
//最终的复制工作,拷贝完成
Streams.copy(in, out);
} finally {
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
}
}
6、InstallParams#handleReturnCode
@Override
void handleReturnCode() {
// If mArgs is null, then MCS couldn't be reached. When it
// reconnects, it will try again to install. At that point, this
// will succeed.
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
这个方法是执行完成了拷贝apk任务后返回的结果
最终调用了PMS的processPendingInstall方法
3、PackageManaPgerService#processPendingInstall
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() {
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.setReturnCode(currentStatus);
res.uid = -1;
res.pkg = null;
res.removedInfo = null;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
//如果安装成功 执行doPreInstall 主要是解析apk前的清理工作
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
//核心方法
installPackageTracedLI(args, res);
}
//后续操作,如果没安装成功 就做清理工作
args.doPostInstall(res.returnCode, res.uid);
}
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
// there's a restore pass performed. Token values are >= 1.
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
//如果apk 程序设置了备份 就执行备份操作
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ " to BM for possible restore");
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
// TODO: http://b/22388012
if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
} else {
doRestore = false;
}
} catch (RemoteException e) {
// can't happen; the backup manager is local
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Slog.e(TAG, "Backup Manager not found!");
doRestore = false;
}
}
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
//发送消息给上层 安装完成,整个安装执行完毕
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
我们继续看installPackageTracedLI
4、PackageManaPgerService#installPackageTracedLI
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
installPackageLI(args, res);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
5、PackageManaPgerService#installPackageLI
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
...
// 1. 解析package信息,
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// 2. 签名校验
try {
verifySignaturesLP(signatureCheckPs, pkg);
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
}
// 3. 对dex进行优化
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null , false ,
getCompilerFilterForReason(REASON_INSTALL),
getOrCreateCompilerPackageStats(pkg),
mDexManager.isUsedByOtherApps(pkg.packageName));
// 4. 重命名 将文件夹的名称重命名为 “包名”,就是data/app/com.xx.xx/ 这样
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
return;
}
// 5. 替换或新安装APK,走不同的路线
if (replace) {
replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
installerPackageName, res, args.installReason);
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
}
上面的这个方法很长,我做了重点提取 以及注释
我们看下最后的installNewPackageLIF 安装一个新的apk文件
6、PackageManaPgerService#installNewPackageLIF
/*
* Install a non-existing package.
*/
private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
// it has been renamed to an older name. The package we
// are trying to install should be installed as an update to
// the existing one, but that has not been requested, so bail.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
+ " without first uninstalling package running as "
+ mSettings.mRenamedPackages.get(pkgName));
return;
}
if (mPackages.containsKey(pkgName)) {
// Don't allow installation over an existing package with the same name.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
+ " without first uninstalling.");
return;
}
}
try {
//扫描这个apk
PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);
//将扫描的结果 更新到setting中
updateSettingsLI(newPackage, installerPackageName, null, res, user);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
prepareAppDataAfterInstallLIF(newPackage);
} else {
// Remove package from internal structures, but keep around any
// data that might have already existed
//如果失败了就删除 中间的临时文件
deletePackageLIF(pkgName, UserHandle.ALL, false, null,
PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
7、PackageManaPgerService#scanPackageTracedLI
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
try {
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
8、PackageManaPgerService#scanPackageLI
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}
9、PackageManaPgerService#scanPackageLI
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
final int policyFlags, int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
// packages (parent and children) would be successfully scanned before the
// actual scan since scanning mutates internal state and we want to atomically
// install the package and its children.
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
scanFlags |= SCAN_CHECK_ONLY;
}
} else {
scanFlags &= ~SCAN_CHECK_ONLY;
}
// Scan the parent
PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
}
return scannedPkg;
}
10、PackageManaPgerService#scanPackageLI
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
try {
final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
currentTime, user);
success = true;
return res;
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
// DELETE_DATA_ON_FAILURES is only used by frozen paths
destroyAppDataLIF(pkg, UserHandle.USER_ALL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
}
}
上面这些scanPackageLI 都是同名的方法,但是参数不同,
11、PackageManaPgerService#scanPackageDirtyLI
这个方法是很长的核心方法
主要功能:
对扫描的package 进行解析,然后把四大组件还有权限的信息 添加到PMS的内部数据集合中保存起来,供系统中的其他app或者服务来访问,PMS在系统中的作用相当于是系统的app数据中心,存储了app的一切信息,
scanPackageDirtyLI
{
// 针对包名为"android" 的APK进行处理, 这个app 主要是
//选择是ChoseActivity 就是有相同的Intent 弹出的界面
//还有个关机app的界面
if (pkg.packageName.equals("android")) {
//shouldCheckUpgradeKeySetLP方法进行密钥检查,是否一致
if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags))
// 重新验证签名
verifySignaturesLP(pkgSetting, pkg);
// 确定 进程的名称
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
// 设置native相关属性 系统app native 会统一放在/system/lib/
//如果是普通app 在/data/data/packageName/lib下建立和CPU类型对应的目录,例如ARM平台 arm,MIP平台 mips/
//设置native 库的路径
// 创建native库链接
//注册pkg里面的provider到PMS上的mProvider上
// 注册该Package中的service到PMS的mServices上
// 注册pkg里面的receiver到PMS上的receivers上
//注册pkg里面的activity到PMS上的activities上
//注册pkg里面的PermissionGroup到PMS上的mPermissionGroups上
//注册pkg里面的Permission到PMS上的permissionMap上
//注册pkg里面的instrumentation到PMS的mInstrumentation中
经历了上面的过程在PMS的安装过程已经完成了,接下来就是通知上层创建成功了
12、PackageManagerService#handlePackagePostInstall
安装完成后,后续流程会发送一个POST_INSTALL消息给mHandler 然后执行handlePackagePostInstall方法
。。。。。。。省略。。。。。。
// If someone is watching installs - notify them
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(res);
//回调通知上层
installObserver.onPackageInstalled(res.name, res.returnCode,
res.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
13、PackageInstallerSession#dispatchSessionFinished
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
}
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
};
然后
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
mFinalStatus = returnCode;
mFinalMessage = msg;
if (mRemoteObserver != null) {
try {
mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
} catch (RemoteException ignored) {
}
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
mCallback.onSessionFinished(this, success);
}
14、PackageInstallObserverAdapter#onPackageInstalled
@Override
1037 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1038 Bundle extras) {
1039 if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
1040 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
1041 Notification notification = buildSuccessNotification(mContext,
1042 mContext.getResources()
1043 .getString(update ? R.string.package_updated_device_owner :
1044 R.string.package_installed_device_owner),
1045 basePackageName,
1046 mUserId);
1047 if (notification != null) {
1048 NotificationManager notificationManager = (NotificationManager)
1049 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
1050 notificationManager.notify(basePackageName, 0, notification);
1051 }
1052 }
1053 final Intent fillIn = new Intent();
1054 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
1055 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
1056 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
1057 PackageManager.installStatusToPublicStatus(returnCode));
1058 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
1059 PackageManager.installStatusToString(returnCode, msg));
1060 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
1061 if (extras != null) {
1062 final String existing = extras.getString(
1063 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
1064 if (!TextUtils.isEmpty(existing)) {
1065 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
1066 }
1067 }
1068 try {
1069 mTarget.sendIntent(mContext, 0, fillIn, null, null);
1070 } catch (SendIntentException ignored) {
1071 }
1072 }
1073 }
最后可以看到,安装完成后,发送了一个广播,在luncher 注册了这个广播,然后更新页面,添加一个图标