安卓高手之路之PackageManagerservice(二)
adb install 流程 - new_abc的专栏 - 博客频道 - CSDN.NET
应用安装涉及目录:
system/app ---------------系统自带的应用程序,获得adb root权限才能删除
data/app ---------------用户程序安装的目录。安装时把 apk文件复制到此目录
data/data ---------------存放应用程序的数据
data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)
安装过程:
复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。
卸载过程:
删除安装过程中在上述三个目录下创建的文件及目录
带着这些知识去看安装过程,可能会更容易理解引起。
当我们利用adb安装一个软件包时,到底流程是怎么样的呢,这里主要介绍一个安装包在目标机中的安装过程。
adb install 也是用的pm命令去安装的,所以开始是在pm.java中。
我们看下流程:
1、调用pm程序开始安装
得用Pm安装时,一般是shell运行一个pm命令,并传送相应的参数,我们通过adb连接到机器,输入pm,会打出pm的一些参数
# pm
pm
usage: pm [list|path|install|uninstall]
pm list packages [-f] [-d] [-e] [-u] [FILTER]
pm list permission-groups
pm list permissions [-g] [-f] [-d] [-u] [GROUP]
pm list instrumentation [-f] [TARGET-PACKAGE]
pm list features
pm list libraries
pm path PACKAGE
pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-
pm uninstall [-k] PACKAGE
pm clear PACKAGE
pm enable PACKAGE_OR_COMPONENT
pm disable PACKAGE_OR_COMPONENT
pm setInstallLocation [0/auto] [1/internal] [2/external]
当我们安装一个软件包时,shell运行pm程序并传入pm install ***等参数,我们看下pm.java
- public static void main(String[] args) {
- new Pm().run(args);
- }
public static void main(String[] args) { new Pm().run(args); }这里运行pm的run方法
- public void run(String[] args) {
- .
- .
- if ("install".equals(op)) {
- runInstall();
- return;
- }
- }
public void run(String[] args) { . . if ("install".equals(op)) { runInstall(); return; } }
匹配到install时,运行runInstallrunInstall主要对其它参数进行解析,最后调用:
- try {
- mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
- installerPackageName);
- synchronized (obs) {
- while (!obs.finished) {
- try {
- obs.wait();
- } catch (InterruptedException e) {
- }
- }
- if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
- System.out.println("Success");
- } else {
- System.err.println("Failure ["
- + installFailureToString(obs.result)
- + "]");
- }
- }
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(PM_NOT_RUNNING_ERR);
- }
try { mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, installerPackageName); synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } if (obs.result == PackageManager.INSTALL_SUCCEEDED) { System.out.println("Success"); } else { System.err.println("Failure [" + installFailureToString(obs.result) + "]"); } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); }
2、PackageManagerService安装前处理
这里调用了PackageManager的installPackage接口,并最终调用PackageManagerService的installPackage进行具体的安装工作在installPackage中,主要发送一条INIT_COPY消息到PackageHandler,PackageHandler处理这条消息最后调用doHandleMessage,这中间的过程就不说了,对于INIT_COPY消息 ,首先调用connectToService,连接服务DefaultContainerService
在连接成功的时候触发DefaultContainerConnection的onServiceConnected,这里面又往PackageHandler发了一条MCS_BOUND。这里面触发startCopy
- final void startCopy() {
- try {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
- retry++;
- if (retry > MAX_RETRIES) {
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mHandler.sendEmptyMessage(MCS_GIVE_UP);
- handleServiceError();
- return;
- } else {
- handleStartCopy();
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
- mHandler.sendEmptyMessage(MCS_UNBIND);
- }
- } catch (RemoteException e) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
- mHandler.sendEmptyMessage(MCS_RECONNECT);
- }
- handleReturnCode();
- }
final void startCopy() { try { if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy"); retry++; if (retry > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return; } else { handleStartCopy(); if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND"); mHandler.sendEmptyMessage(MCS_UNBIND); } } catch (RemoteException e) { if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); } handleReturnCode(); }
handleStartCopy进行一些安装前准备工作,最后调用handleReturnCode
- 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);
- }
- }
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); } }
我们看下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.returnCode = currentStatus;
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = new PackageRemovedInfo();
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- args.doPreInstall(res.returnCode);
- synchronized (mInstallLock) {
- installPackageLI(args, true, res);
- }
- args.doPostInstall(res.returnCode);
- }
- // 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 a backupAgent defined.
- final boolean update = res.removedInfo.removedPackage != null;
- boolean doRestore = (!update
- && res.pkg != null
- && res.pkg.applicationInfo.backupAgentName != null);
- // 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);
- 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");
- try {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
- } 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);
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
- mHandler.sendMessage(msg);
- }
- }
- });
- }
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.returnCode = currentStatus; res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageLI(args, true, res); } args.doPostInstall(res.returnCode); } // 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 a backupAgent defined. final boolean update = res.removedInfo.removedPackage != null; boolean doRestore = (!update && res.pkg != null && res.pkg.applicationInfo.backupAgentName != null); // 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); 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"); try { bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); } 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); Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } } }); }这里New了一个消息,把它的callback设置为这里new出来的Runnable,这里重载了run方法,最后会通过Handle,Looper,Message机制调用到这个run方法中进行。
这里主要是调用了installPackageLI函数进行安装
3、解析apk
在installPackageLI中,会new 一个PackageParser对package进行解析,调用parsePackage函数 parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags)函数根据参数进行一些处理后最终调用parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)对包进行解析,我们看到这个函数里面主要对配置文件AndroidManifest.xml文件进行了解析。我们会看到如下类似的代码
- private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, String[] outError)
- throws XmlPullParserException, IOException {
- .
- .
- int outerDepth = parser.getDepth();
- while ((type=parser.next()) != parser.END_DOCUMENT
- && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == parser.END_TAG || type == parser.TEXT) {
- continue;
- }
- String tagName = parser.getName();
- if (tagName.equals("application")) {
- if (foundApp) {
- if (RIGID_PARSER) {
- outError[0] = "<manifest> has more than one <application>";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return null;
- } else {
- Log.w(TAG, "<manifest> has more than one <application>");
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- }
- .
- .
- }
private Package parsePackage( Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { . . int outerDepth = parser.getDepth(); while ((type=parser.next()) != parser.END_DOCUMENT && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { if (type == parser.END_TAG || type == parser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals("application")) { if (foundApp) { if (RIGID_PARSER) { outError[0] = "<manifest> has more than one <application>"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Log.w(TAG, "<manifest> has more than one <application>"); XmlUtils.skipCurrentTag(parser); continue; } } . . }4、安装包
解析完之后 ,调用installNewPackageLI进行包的安装
这里主要调用了scanPackageLI,对包进行安装,及保存package、provider、service、receiver和activity等信息保存在PackageManagerService服务中,我们会看到有如下代码
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
- int parseFlags, int scanMode, long currentTime) {
- // And now re-install the app.
- ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- .
- // Add the new setting to mSettings
- mSettings.insertPackageSettingLP(pkgSetting, pkg);
- // Add the new setting to mPackages
- mPackages.put(pkg.applicationInfo.packageName, pkg);
- // Make sure we don‘t accidentally delete its data.
- mSettings.mPackagesToBeCleaned.remove(pkgName);
- }
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime) { // And now re-install the app. ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid, pkg.applicationInfo.uid); . // Add the new setting to mSettings mSettings.insertPackageSettingLP(pkgSetting, pkg); // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); // Make sure we don‘t accidentally delete its data. mSettings.mPackagesToBeCleaned.remove(pkgName); }
这里的install最终会通过socket通信调用到installd.c中的do_install,其实也就是创建了一些目录而已。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。