引言
众所周知,Android应用最终是打包成.apk格式(其实就是一个压缩包),然后安装至手机并运行的。APK即Android Package的缩写,那么,Android安装应用APK的具体方式及其详细过程是怎样的呢?下面,我们逐一揭开里面的层层面纱。
Android应用APK安装的方式
一般而言,Android应用安装有如下四种方式:
- 系统应用安装:开机时加载系统的APK和应用,没有安装界面;
- 网络下载应用安装:通过各种market应用完成,没有安装界面;
- ADB工具安装:即通过Android的SDK开发tools里面的adb.exe程序安装,没有安装界面;
- 第三方应用安装:通过SD卡里的APK文件安装(比如双击APK文件触发),有安装界面,系统默认已经安装了一个安装卸载应用的程序,即由packageinstaller.apk应用处理安装及卸载过程的界面。
Android APK安装概述
应用安装涉及到的目录
- /system/app :系统自带的应用程序,获得adb root权限才能删除
- /data/app :用户程序安装的目录。安装时把apk文件复制到此目录
- /data/data :存放应用程序的数据
- /data/dalvik-cache:将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,当然,ART–Android Runtime的可执行文件格式为oat,启用ART时,系统会执行dex文件转换至oat文件)
- /data/system :该目录下的packages.xml文件,类似于Windows的注册表,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
/data/system/packages.xml中内容详解(这里列举的标签内容不一定完整,只是列举核心内容,packages.xml的完整定义详见官方文档):
该文件的根节点是…,内容树结构如下图所示:
/data/system/packages.xml结构图
(1)permissions标签定义了目前系统中定义的所有权限。主要分为两类:系统定义的(package属性为android)和APK定义的(package属性为APK的包名)。
(2)package代表一个APK的属性,它的属性含义如下(这里并未完全列出,如需了解全部属性,请查看官方文档)。
name:APK的包名
codePath:安装路径。有/system/app系统APK和/data/app两种。/system/app存放系统出厂时预置的一些APK,/data/app存放用户安装的第三方APK。
system:如果APK被安装在/system/app下,system的值为true;安装在/data/app下面的话,值为true。
ts:时间戳
version:APK的版本号
sharedUserId/userId:Android系统启动一个普通的APK时,会为这个APK分配一个独立的UID,这就是userId。如果APK要和系统中其它APK使用相同的UID的话,那就是sharedUserId。关于共享UID,下面有更详细的描述。
package的子标签perms:APK的AndroidManifest.xml文件中,每使用一个标签,标签中就会增加一项。
(3)代表一个共享UID,通常,共同实现一系列相似功能的APK共享一个UID。其子标签中的权限代表了这个共享UID的权限,所有使用的同一个共享UID的APK运行在同一进程中,这个进程的UID就是这个共享UID,这些APK都具有这个共享UID的权限。其属性包括:
name:共享UID的名字,在APK的android:sharedUserId属性中使用。
userId:使用这个共享UID的所有APK运行时所在的进程的UID。
安装过程总述
安卓系统安装一个应用时,系统大致会进行如下操作:
- 复制APK安装包到data/app目录下,文件名会以应用的package命名;
- 解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录(一般情况下,会先执行dexopt即dex文件的优化,将优化后的dex文件保存至该目录下),并data/data目录下创建对应的应用数据目录(data/data目录可读可写);
- 更新/data/system/packages.xml中的内容,将APK的信息加入进去。
卸载过程概述
对照安装过程,卸载过程与之相逆:
删除安装过程中在上述目录下创建的文件及目录。
安装应用的过程代码解析
鉴于APK安装有四种方式,这里分别对各种方式下的安装详细过程进行代码级的解析。
安装过程代码解析的前奏
注意:由于Android API迭代较快,版本众多,不过关于安装和卸载的逻辑核心(代码主干)是不变的,最新level级别的API可能会加入更多分支或细节完善代码,一般建议以低版本的API作为分析基础,这样便于更加快速地厘清代码流程和主干,本文以API level14的源码做切入点,引用源代码部分前面的数字表示行号,对应于源文件里面的行号
我们知道,Android里面的包信息管理、安装和卸载等均是通过android/content/pm/PackageManager.java()这个类来完成的。而获取PackageManager的方式一般是:android/content/Context.getPackageManager()方法获取。
查看Context.java,可以发现Context类是抽象的,getPackageManager()也是抽象的。
/**
* Interface to global information about an application environment. This is
* an abstract class whose implementation is provided by
* the Android system. It
* allows access to application-specific resources and classes, as well as
* up-calls for application-level operations such as launching activities,
* broadcasting and receiving intents, etc.
*/
51 public abstract class Context {
...
196 /** Return PackageManager instance to find global package information. */
197 public abstract PackageManager getPackageManager();
而Context的具体实现是android/app/ContextImpl.java里面的ContextImpl类,如下所示:
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
138 class ContextImpl extends Context {
...
481 @Override
482 public PackageManager getPackageManager() {
483 if (mPackageManager != null) {
484 return mPackageManager;
485 }
486
487 IPackageManager pm = ActivityThread.getPackageManager();
488 if (pm != null) {
489 // Doesn't matter if we make more than one instance.
490 return (mPackageManager = new ApplicationPackageManager(this, pm));
491 }
492
493 return null;
494 }
可以看出,获取到的实际上是android/app/ApplicationPackageManager.java定义的ApplicationPackageManager类的实例。进入ApplicationPackageManager.java,代码如下:
60 /*package*/
61 final class ApplicationPackageManager extends PackageManager {
...
723 ApplicationPackageManager(ContextImpl context,
724 IPackageManager pm) {
725 mContext = context;
726 mPM = pm;
727 }
...
934 @Override
935 public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
936 String installerPackageName) {
937 try {
938 mPM.installPackage(packageURI, observer, flags, installerPackageName);
939 } catch (RemoteException e) {
940 // Should never happen!
941 }
942 }
943
944 @Override
945 public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
946 int flags, String installerPackageName, Uri verificationURI,
947 ManifestDigest manifestDigest) {
948 try {
949 mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
950 verificationURI, manifestDigest);
951 } catch (RemoteException e) {
952 // Should never happen!
953 }
954 }
955
956 @Override
957 public void verifyPendingInstall(int id, int response) {
958 try {
959 mPM.verifyPendingInstall(id, response);
960 } catch (RemoteException e) {
961 // Should never happen!
962 }
963 }
...
1226 private final IPackageManager mPM;
进入ApplicationPackageManager,其继承了PackageManager,这里其实采用了组合模式,其实ApplicationPackageManager的installPackage方法内部是调用内部组合变量mPM的installPackage方法,其实其他继承自PackageManager的方法的内部逻辑也都是实际调用了mPM变量的对应方法。而mPM变量是在ApplicationPackageManager的构造方法传入(726行,mPM = pm;),因此回滚到Context.java的487行(IPackageManager pm = ActivityThread.getPackageManager();),这里的pm就是最终执行安装或者其他操作的对象。跟踪下去,android/app/ActivityThread.java:
114 /**
115 * This manages the execution of the main thread in an
116 * application process, scheduling and executing activities,
117 * broadcasts, and other operations on it as the activity
118 * manager requests.
119 *
120 * {@hide}
121 */
122 public final class ActivityThread {
...
1395 public static IPackageManager getPackageManager() {
1396 if (sPackageManager != null) {
1397 //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
1398 return sPackageManager;
1399 }
1400 IBinder b = ServiceManager.getService("package");
1401 //Slog.v("PackageManager", "default service binder = " + b);
1402 sPackageManager = IPackageManager.Stub.asInterface(b);
1403 //Slog.v("PackageManager", "default service = " + sPackageManager);
1404 return sPackageManager;
1405 }
1406
通过上面代码可以发现,最终返回的IPackageManager的实例对象是通过绑定系统的package服务获取到的,熟悉Android的朋友应该清楚,这实际就是调用PackageManager对应的service来完成。至此,可以明确PackageManager类的安装等等操作实际是通过com/android、server/pm/PackageManagerService.java中定义的类PackageManagerService来完成,其详细代码如下:
140 /**
141 * Keep track of all those .apks everywhere.
142 *
143 * This is very central to the platform's security; please run the unit
144 * tests whenever making modifications here:
145 *
146 mmm frameworks/base/tests/AndroidTests
147 adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
148 adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
149 *
150 * {@hide}
151 */
152 public class PackageManagerService extends IPackageManager.Stub {
...
439 class PackageHandler extends Handler {
440 private boolean mBound = false;
441 final ArrayList<HandlerParams> mPendingInstalls =
442 new ArrayList<HandlerParams>();
443
444 private boolean connectToService() {
445 if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
446 " DefaultContainerService");
447 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
448 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
449 if (mContext.bindService(service, mDefContainerConn,
450 Context.BIND_AUTO_CREATE)) {
451 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
452 mBound = true;
453 return true;
454 }
455 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
456 return false;
457 }
458
459 private void disconnectService() {
460 mContainerService = null;
461 mBound = false;
462 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
463 mContext.unbindService(mDefContainerConn);
464 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
465 }
466
467 PackageHandler(Looper looper) {
468 super(looper);
469 }
470
471 public void handleMessage(Message msg) {
472 try {
473 doHandleMessage(msg);
474 } finally {
475 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
476 }
477 }
478
479 void doHandleMessage(Message msg) {
480 switch (msg.what) {
481 case INIT_COPY: {
482 if (DEBUG_INSTALL) Slog.i(TAG, "init_copy");
483 HandlerParams params = (HandlerParams) msg.obj;
484 int idx = mPendingInstalls.size();
485 if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx);
486 // If a bind was already initiated we dont really
487 // need to do anything. The pending install
488 // will be processed later on.
489 if (!mBound) {
490 // If this is the only one pending we might
491 // have to bind to the service again.
492 if (!connectToService()) {
493 Slog.e(TAG, "Failed to bind to media container service");
494 params.serviceError();
495 return;
496 } else {
497 // Once we bind to the service, the first
498 // pending request will be processed.
499 mPendingInstalls.add(idx, params);
500 }
501 } else {
502 mPendingInstalls.add(idx, params);
503 // Already bound to the service. Just make
504 // sure we trigger off processing the first request.
505 if (idx == 0) {
506 mHandler.sendEmptyMessage(MCS_BOUND);
507 }
508 }
509 break;
510 }
511 case MCS_BOUND: {
512 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
513 if (msg.obj != null) {
514 mContainerService = (IMediaContainerService) msg.obj;
515 }
516 if (mContainerService == null) {
517 // Something seriously wrong. Bail out
518 Slog.e(TAG, "Cannot bind to media container service");
519 for (HandlerParams params : mPendingInstalls) {
520 mPendingInstalls.remove(0);
521 // Indicate service bind error
522 params.serviceError();
523 }
524 mPendingInstalls.clear();
525 } else if (mPendingInstalls.size() > 0) {
526 HandlerParams params = mPendingInstalls.get(0);
527 if (params != null) {
528 if (params.startCopy()) {
529 // We are done... look for more work or to
530 // go idle.
531 if (DEBUG_SD_INSTALL) Log.i(TAG,
532 "Checking for more work or unbind...");
533 // Delete pending install
534 if (mPendingInstalls.size() > 0) {
535 mPendingInstalls.remove(0);
536 }
537 if (mPendingInstalls.size() == 0) {
538 if (mBound) {
539 if (DEBUG_SD_INSTALL) Log.i(TAG,
540 "Posting delayed MCS_UNBIND");
541 removeMessages(MCS_UNBIND);
542 Message ubmsg = obtainMessage(MCS_UNBIND);
543 // Unbind after a little delay, to avoid
544 // continual thrashing.
545 sendMessageDelayed(ubmsg, 10000);
546 }
547 } else {
548 // There are more pending requests in queue.
549 // Just post MCS_BOUND message to trigger processing
550 // of next pending install.
551 if (DEBUG_SD_INSTALL) Log.i(TAG,
552 "Posting MCS_BOUND for next woek");
553 mHandler.sendEmptyMessage(MCS_BOUND);
554 }
555 }
556 }
557 } else {
558 // Should never happen ideally.
559 Slog.w(TAG, "Empty queue");
560 }
561 break;
562 }
563 case MCS_RECONNECT: {
564 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
565 if (mPendingInstalls.size() > 0) {
566 if (mBound) {
567 disconnectService();
568 }
569 if (!connectToService()) {
570 Slog.e(TAG, "Failed to bind to media container service");
571 for (HandlerParams params : mPendingInstalls) {
572 mPendingInstalls.remove(0);
573 // Indicate service bind error
574 params.serviceError();
575 }
576 mPendingInstalls.clear();
577 }
578 }
579 break;
580 }
581 case MCS_UNBIND: {
582 // If there is no actual work left, then time to unbind.
583 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
584
585 if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
586 if (mBound) {
587 if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
588
589 disconnectService();
590 }
591 } else if (mPendingInstalls.size() > 0) {
592 // There are more pending requests in queue.
593 // Just post MCS_BOUND message to trigger processing
594 // of next pending install.
595 mHandler.sendEmptyMessage(MCS_BOUND);
596 }
597
598 break;
599 }
600 case MCS_GIVE_UP: {
601 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
602 mPendingInstalls.remove(0);
603 break;
604 }
605 case SEND_PENDING_BROADCAST: {
606 String packages[];
607 ArrayList<String> components[];
608 int size = 0;
609 int uids[];
610 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
611 synchronized (mPackages) {
612 if (mPendingBroadcasts == null) {
613 return;
614 }
615 size = mPendingBroadcasts.size();
616 if (size <= 0) {
617 // Nothing to be done. Just return
618 return;
619 }
620 packages = new String[size];
621 components = new ArrayList[size];
622 uids = new int[size];
623 Iterator<HashMap.Entry<String, ArrayList<String>>>
624 it = mPendingBroadcasts.entrySet().iterator();
625 int i = 0;
626 while (it.hasNext() && i < size) {
627 HashMap.Entry<String, ArrayList<String>> ent = it.next();
628 packages[i] = ent.getKey();
629 components[i] = ent.getValue();
630 PackageSetting ps = mSettings.mPackages.get(ent.getKey());
631 uids[i] = (ps != null) ? ps.userId : -1;
632 i++;
633 }
634 size = i;
635 mPendingBroadcasts.clear();
636 }
637 // Send broadcasts
638 for (int i = 0; i < size; i++) {
639 sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);
640 }
641 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
642 break;
643 }
644 case START_CLEANING_PACKAGE: {
645 String packageName = (String)msg.obj;
646 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
647 synchronized (mPackages) {
648 if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
649 mSettings.mPackagesToBeCleaned.add(packageName);
650 }
651 }
652 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
653 startCleaningPackages();
654 } break;
655 case POST_INSTALL: {
656 if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
657 PostInstallData data = mRunningInstalls.get(msg.arg1);
658 mRunningInstalls.delete(msg.arg1);
659 boolean deleteOld = false;
660
661 if (data != null) {
662 InstallArgs args = data.args;
663 PackageInstalledInfo res = data.res;
664
665 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
666 res.removedInfo.sendBroadcast(false, true);
667 Bundle extras = new Bundle(1);
668 extras.putInt(Intent.EXTRA_UID, res.uid);
669 final boolean update = res.removedInfo.removedPackage != null;
670 if (update) {
671 extras.putBoolean(Intent.EXTRA_REPLACING, true);
672 }
673 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
674 res.pkg.applicationInfo.packageName,
675 extras, null, null);
676 if (update) {
677 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
678 res.pkg.applicationInfo.packageName,
679 extras, null, null);
680 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
681 null, null,
682 res.pkg.applicationInfo.packageName, null);
683 }
684 if (res.removedInfo.args != null) {
685 // Remove the replaced package's older resources safely now
686 deleteOld = true;
687 }
688 }
689 // Force a gc to clear up things
690 Runtime.getRuntime().gc();
691 // We delete after a gc for applications on sdcard.
692 if (deleteOld) {
693 synchronized (mInstallLock) {
694 res.removedInfo.args.doPostDeleteLI(true);
695 }
696 }
697 if (args.observer != null) {
698 try {
699 args.observer.packageInstalled(res.name, res.returnCode);
700 } catch (RemoteException e) {
701 Slog.i(TAG, "Observer no longer exists.");
702 }
703 }
704 } else {
705 Slog.e(TAG, "Bogus post-install token " + msg.arg1);
706 }
707 } break;
708 case UPDATED_MEDIA_STATUS: {
709 if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
710 boolean reportStatus = msg.arg1 == 1;
711 boolean doGc = msg.arg2 == 1;
712 if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
713 if (doGc) {
714 // Force a gc to clear up stale containers.
715 Runtime.getRuntime().gc();
716 }
717 if (msg.obj != null) {
718 @SuppressWarnings("unchecked")
719 Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
720 if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
721 // Unload containers
722 unloadAllContainers(args);
723 }
724 if (reportStatus) {
725 try {
726 if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
727 PackageHelper.getMountService().finishMediaUpdate();
728 } catch (RemoteException e) {
729 Log.e(TAG, "MountService not running?");
730 }
731 }
732 } break;
733 case WRITE_SETTINGS: {
734 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
735 synchronized (mPackages) {
736 removeMessages(WRITE_SETTINGS);
737 removeMessages(WRITE_STOPPED_PACKAGES);
738 mSettings.writeLPr();
739 }
740 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
741 } break;
742 case WRITE_STOPPED_PACKAGES: {
743 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
744 synchronized (mPackages) {
745 removeMessages(WRITE_STOPPED_PACKAGES);
746 mSettings.writeStoppedLPr();
747 }
748 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
749 } break;
750 case CHECK_PENDING_VERIFICATION: {
751 final int verificationId = msg.arg1;
752 final PackageVerificationState state = mPendingVerification.get(verificationId);
753
754 if (state != null) {
755 final InstallArgs args = state.getInstallArgs();
756 Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
757 mPendingVerification.remove(verificationId);
758
759 int ret = PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT;
760 processPendingInstall(args, ret);
761
762 mHandler.sendEmptyMessage(MCS_UNBIND);
763 }
764
765 break;
766 }
767 case PACKAGE_VERIFIED: {
768 final int verificationId = msg.arg1;
769
770 final PackageVerificationState state = mPendingVerification.get(verificationId);
771 if (state == null) {
772 Slog.w(TAG, "Invalid verification token " + verificationId + " received");
773 break;
774 }
775
776 final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
777
778 state.setVerifierResponse(response.callerUid, response.code);
779
780 if (state.isVerificationComplete()) {
781 mPendingVerification.remove(verificationId);
782
783 final InstallArgs args = state.getInstallArgs();
784
785 int ret;
786 if (state.isInstallAllowed()) {
787 ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
788 try {
789 ret = args.copyApk(mContainerService, true);
790 } catch (RemoteException e) {
791 Slog.e(TAG, "Could not contact the ContainerService");
792 }
793 } else {
794 ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
795 }
796
797 processPendingInstall(args, ret);
798
799 mHandler.sendEmptyMessage(MCS_UNBIND);
800 }
801
802 break;
803 }
804 }
805 }
806 }
...
...
831 public static final IPackageManager main(Context context, boolean factoryTest,
832 boolean onlyCore) {
833 PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
834 ServiceManager.addService("package", m);
835 return m;
836 }
...
...
860 public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
861 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
862 SystemClock.uptimeMillis());
863
864 if (mSdkVersion <= 0) {
865 Slog.w(TAG, "**** ro.build.version.sdk not set!");
866 }
867
868 mContext = context;
869 mFactoryTest = factoryTest;
870 mOnlyCore = onlyCore;
871 mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
872 mMetrics = new DisplayMetrics();
873 mSettings = new Settings();
874 mSettings.addSharedUserLPw("android.uid.system",
875 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
876 mSettings.addSharedUserLPw("android.uid.phone",
877 MULTIPLE_APPLICATION_UIDS
878 ? RADIO_UID : FIRST_APPLICATION_UID,
879 ApplicationInfo.FLAG_SYSTEM);
880 mSettings.addSharedUserLPw("android.uid.log",
881 MULTIPLE_APPLICATION_UIDS
882 ? LOG_UID : FIRST_APPLICATION_UID,
883 ApplicationInfo.FLAG_SYSTEM);
884 mSettings.addSharedUserLPw("android.uid.nfc",
885 MULTIPLE_APPLICATION_UIDS
886 ? NFC_UID : FIRST_APPLICATION_UID,
887 ApplicationInfo.FLAG_SYSTEM);
888
889 String separateProcesses = SystemProperties.get("debug.separate_processes");
890 if (separateProcesses != null && separateProcesses.length() > 0) {
891 if ("*".equals(separateProcesses)) {
892 mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
893 mSeparateProcesses = null;
894 Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
895 } else {
896 mDefParseFlags = 0;
897 mSeparateProcesses = separateProcesses.split(",");
898 Slog.w(TAG, "Running with debug.separate_processes: "
899 + separateProcesses);
900 }
901 } else {
902 mDefParseFlags = 0;
903 mSeparateProcesses = null;
904 }
905
906 mInstaller = new Installer();
907
908 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
909 Display d = wm.getDefaultDisplay();
910 d.getMetrics(mMetrics);
911
912 synchronized (mInstallLock) {
913 // writer
914 synchronized (mPackages) {
915 mHandlerThread.start();
916 mHandler = new PackageHandler(mHandlerThread.getLooper());
917
918 File dataDir = Environment.getDataDirectory();
919 mAppDataDir = new File(dataDir, "data");
920 mUserAppDataDir = new File(dataDir, "user");
921 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
922
923 mUserManager = new UserManager(mInstaller, mUserAppDataDir);
924
925 readPermissions();
926
927 mRestoredSettings = mSettings.readLPw();
928 long startTime = SystemClock.uptimeMillis();
929
930 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
931 startTime);
932
933 // Set flag to monitor and not change apk file paths when
934 // scanning install directories.
935 int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;
936 if (mNoDexOpt) {
937 Slog.w(TAG, "Running ENG build: no pre-dexopt!");
938 scanMode |= SCAN_NO_DEX;
939 }
940
941 final HashSet<String> libFiles = new HashSet<String>();
942
943 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
944 mDalvikCacheDir = new File(dataDir, "dalvik-cache");
945
946 boolean didDexOpt = false;
947
948 /**
949 * Out of paranoia, ensure that everything in the boot class
950 * path has been dexed.
951 */
952 String bootClassPath = System.getProperty("java.boot.class.path");
953 if (bootClassPath != null) {
954 String[] paths = splitString(bootClassPath, ':');
955 for (int i=0; i<paths.length; i++) {
956 try {
957 if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
958 libFiles.add(paths[i]);
959 mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
960 didDexOpt = true;
961 }
962 } catch (FileNotFoundException e) {
963 Slog.w(TAG, "Boot class path not found: " + paths[i]);
964 } catch (IOException e) {
965 Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "
966 + e.getMessage());
967 }
968 }
969 } else {
970 Slog.w(TAG, "No BOOTCLASSPATH found!");
971 }
972
973 /**
974 * Also ensure all external libraries have had dexopt run on them.
975 */
976 if (mSharedLibraries.size() > 0) {
977 Iterator<String> libs = mSharedLibraries.values().iterator();
978 while (libs.hasNext()) {
979 String lib = libs.next();
980 try {
981 if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
982 libFiles.add(lib);
983 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
984 didDexOpt = true;
985 }
986 } catch (FileNotFoundException e) {
987 Slog.w(TAG, "Library not found: " + lib);
988 } catch (IOException e) {
989 Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
990 + e.getMessage());
991 }
992 }
993 }
994
995 // Gross hack for now: we know this file doesn't contain any
996 // code, so don't dexopt it to avoid the resulting log spew.
997 libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
998
999 /**
1000 * And there are a number of commands implemented in Java, which
1001 * we currently need to do the dexopt on so that they can be
1002 * run from a non-root shell.
1003 */
1004 String[] frameworkFiles = mFrameworkDir.list();
1005 if (frameworkFiles != null) {
1006 for (int i=0; i<frameworkFiles.length; i++) {
1007 File libPath = new File(mFrameworkDir, frameworkFiles[i]);
1008 String path = libPath.getPath();
1009 // Skip the file if we alrady did it.
1010 if (libFiles.contains(path)) {
1011 continue;
1012 }
1013 // Skip the file if it is not a type we want to dexopt.
1014 if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
1015 continue;
1016 }
1017 try {
1018 if (dalvik.system.DexFile.isDexOptNeeded(path)) {
1019 mInstaller.dexopt(path, Process.SYSTEM_UID, true);
1020 didDexOpt = true;
1021 }
1022 } catch (FileNotFoundException e) {
1023 Slog.w(TAG, "Jar not found: " + path);
1024 } catch (IOException e) {
1025 Slog.w(TAG, "Exception reading jar: " + path, e);
1026 }
1027 }
1028 }
1029
1030 if (didDexOpt) {
1031 // If we had to do a dexopt of one of the previous
1032 // things, then something on the system has changed.
1033 // Consider this significant, and wipe away all other
1034 // existing dexopt files to ensure we don't leave any
1035 // dangling around.
1036 String[] files = mDalvikCacheDir.list();
1037 if (files != null) {
1038 for (int i=0; i<files.length; i++) {
1039 String fn = files[i];
1040 if (fn.startsWith("data@app@")
1041 || fn.startsWith("data@app-private@")) {
1042 Slog.i(TAG, "Pruning dalvik file: " + fn);
1043 (new File(mDalvikCacheDir, fn)).delete();
1044 }
1045 }
1046 }
1047 }
1048
1049 // Find base frameworks (resource packages without code).
1050 mFrameworkInstallObserver = new AppDirObserver(
1051 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
1052 mFrameworkInstallObserver.startWatching();
1053 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
1054 | PackageParser.PARSE_IS_SYSTEM_DIR,
1055 scanMode | SCAN_NO_DEX, 0);
1056
1057 // Collect all system packages.
1058 mSystemAppDir = new File(Environment.getRootDirectory(), "app");
1059 mSystemInstallObserver = new AppDirObserver(
1060 mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
1061 mSystemInstallObserver.startWatching();
1062 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
1063 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
1064
1065 // Collect all vendor packages.
1066 mVendorAppDir = new File("/vendor/app");
1067 mVendorInstallObserver = new AppDirObserver(
1068 mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
1069 mVendorInstallObserver.startWatching();
1070 scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
1071 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
1072
1073 if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
1074 mInstaller.moveFiles();
1075
1076 // Prune any system packages that no longer exist.
1077 if (!mOnlyCore) {
1078 Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
1079 while (psit.hasNext()) {
1080 PackageSetting ps = psit.next();
1081 if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
1082 && !mPackages.containsKey(ps.name)
1083 && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
1084 psit.remove();
1085 String msg = "System package " + ps.name
1086 + " no longer exists; wiping its data";
1087 reportSettingsProblem(Log.WARN, msg);
1088 mInstaller.remove(ps.name, 0);
1089 mUserManager.removePackageForAllUsers(ps.name);
1090 }
1091 }
1092 }
1093
1094 mAppInstallDir = new File(dataDir, "app");
1095 //look for any incomplete package installations
1096 ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
1097 //clean up list
1098 for(int i = 0; i < deletePkgsList.size(); i++) {
1099 //clean up here
1100 cleanupInstallFailedPackage(deletePkgsList.get(i));
1101 }
1102 //delete tmp files
1103 deleteTempPackageFiles();
1104
1105 if (!mOnlyCore) {
1106 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
1107 SystemClock.uptimeMillis());
1108 mAppInstallObserver = new AppDirObserver(
1109 mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
1110 mAppInstallObserver.startWatching();
1111 scanDirLI(mAppInstallDir, 0, scanMode, 0);
1112
1113 mDrmAppInstallObserver = new AppDirObserver(
1114 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
1115 mDrmAppInstallObserver.startWatching();
1116 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
1117 scanMode, 0);
1118 } else {
1119 mAppInstallObserver = null;
1120 mDrmAppInstallObserver = null;
1121 }
1122
1123 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
1124 SystemClock.uptimeMillis());
1125 Slog.i(TAG, "Time to scan packages: "
1126 + ((SystemClock.uptimeMillis()-startTime)/1000f)
1127 + " seconds");
1128
1129 // If the platform SDK has changed since the last time we booted,
1130 // we need to re-grant app permission to catch any new ones that
1131 // appear. This is really a hack, and means that apps can in some
1132 // cases get permissions that the user didn't initially explicitly
1133 // allow... it would be nice to have some better way to handle
1134 // this situation.
1135 final boolean regrantPermissions = mSettings.mInternalSdkPlatform
1136 != mSdkVersion;
1137 if (regrantPermissions) Slog.i(TAG, "Platform changed from "
1138 + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
1139 + "; regranting permissions for internal storage");
1140 mSettings.mInternalSdkPlatform = mSdkVersion;
1141
1142 updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
1143
1144 // can downgrade to reader
1145 mSettings.writeLPr();
1146
1147 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
1148 SystemClock.uptimeMillis());
1149
1150 // Now after opening every single application zip, make sure they
1151 // are all flushed. Not really needed, but keeps things nice and
1152 // tidy.
1153 Runtime.getRuntime().gc();
1154
1155 mRequiredVerifierPackage = getRequiredVerifierLPr();
1156 } // synchronized (mPackages)
1157 } // synchronized (mInstallLock)
1158 }
...
仔细分析上述代码,主要分两个部分:PackageManagerService的构造方法(启动流程)(860-1158行)、PackageHandler的逻辑(439-806行)。PackageManagerService是在系统启动阶段由systemserver启动的一个java层服务,用来管理/system/framework,/system/app,/data/app,/data/app-private等目录下的apk文件,PackageManagerService的启动流程主要包括:
PackageManagerService
以下是PackageManagerService主要的工作内容:
- 建立java层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现;
- 建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息;
- 解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系统支持的各种硬件模块的feature.主要工作:
(1)建立底层user ids和group ids 同上层permissions之间的映射;可以指定一个权限与几个组ID对应。当一个APK被授予这个权限时,它也同时属于这几个组。
(2)给一些底层用户分配权限,如给shell授予各种permission权限;把一个权限赋予一个UID,当进程使用这个UID运行时,就具备了这个权限。
(3) library,系统增加的一些应用需要link的扩展jar库;
(4) feature,系统每增加一个硬件,都要添加相应的feature.将解析结果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等几个集合中供系统查询和权限配置使用 - 检查/data/system/packages.xml是否存在,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
- 检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要的则通过dexopt进行优化;
- 启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。当有add event时调用scanPackageLI(File , int , int)处理;当有remove event时调用removePackageLI()处理;
- 对于以上几个目录下的apk逐个解析,主要是解析每个apk的AndroidMa-nifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息,并将每个apk的配置信息添加到全局列表进行管理。调用installer.install()进行安装工作,检查apk里的dex文件是否需要再优化,如果需要优化则通过辅助工具dexopt进行优化处理;将解析出的componet添加到pkg的对应列表里;对apk进行签名和证书校验,进行完整性验证。
- 将解析的每个apk的信息保存到packages.xml和packages.list文件里,packages.list记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)。
开机安装过程代码解析
有了上面的认识,接下来分析安装的过程就比较轻松了(均围绕PackageManagerService.java展开)。开机安装过程的代码流程如下:
- 扫描各目录(/system/framework、/system/app、/vendor/app、/data/app/、/data/app-private)下的jar包或安装包:
a.扫描安装“/system/framework”目录下的jar包(1049-1055行);
b.扫描安装系统/system/app的应用程序(1057-1063行);
c.制造商的目录下/vendor/app应用包(1065-1071行);
d.扫描“/data/app”目录,即用户安装的第三方应用(1108-1111行);
e.扫描” data\app-private”目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保护的视频是使用DRM保护的文件)(1113-1117行)。 - 扫描目录关键方法的代码清单:
2732 private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
2733 String[] files = dir.list();
2734 if (files == null) {
2735 Log.d(TAG, "No files in app dir " + dir);
2736 return;
2737 }
2738
2739 if (DEBUG_PACKAGE_SCANNING) {
2740 Log.d(TAG, "Scanning app dir " + dir);
2741 }
2742
2743 int i;
2744 for (i=0; i<files.length; i++) {
2745 File file = new File(dir, files[i]);
2746 if (!isPackageFilename(files[i])) {
2747 // Ignore entries which are not apk's
2748 continue;
2749 }
2750 PackageParser.Package pkg = scanPackageLI(file,
2751 flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
2752 // Don't mess around with apps in system partition.
2753 if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
2754 mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
2755 // Delete the apk
2756 Slog.w(TAG, "Cleaning up failed install of " + file);
2757 file.delete();
2758 }
2759 }
2760 }
- 从上面扫描方法的代码中可以看出实质是调用了scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime) ,其代码在2814-2923行定义。分析其代码,发现最终实质是调用scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime)。而后者这个方法代码定义在3106-3905行之间,前面一段主要是各种校验和检查,关键部分代码为:
3495 //invoke installer to do the actual installation
3496 int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
3497 pkg.applicationInfo.uid);
3498 if (ret < 0) {
3499 // Error from installer
3500 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
3501 return null;
3502 }
3503 // Create data directories for all users
3504 mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
不难看出,mInstaller.install是真正执行安装之处。而看看mInstaller的定义:
258 // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages
259 // LOCK HELD. Can be called with mInstallLock held.
260 final Installer mInstaller;
查看com/android/server/pm/Installer.java,其代码相对比较少,分析起来比较容易,其install方法调用了execute(String cmd)方法,而execute(String cmd)又调用transaction(cmd):
148 private synchronized String transaction(String cmd) {
149 if (!connect()) {
150 Slog.e(TAG, "connection failed");
151 return "-1";
152 }
153
154 if (!writeCommand(cmd)) {
155 /*
156 * If installd died and restarted in the background (unlikely but
157 * possible) we'll fail on the next write (this one). Try to
158 * reconnect and write the command one more time before giving up.
159 */
160 Slog.e(TAG, "write command failed? reconnect!");
161 if (!connect() || !writeCommand(cmd)) {
162 return "-1";
163 }
164 }
165 if (LOCAL_DEBUG) {
166 Slog.i(TAG, "send: '" + cmd + "'");
167 }
168 if (readReply()) {
169 String s = new String(buf, 0, buflen);
170 if (LOCAL_DEBUG) {
171 Slog.i(TAG, "recv: '" + s + "'");
172 }
173 return s;
174 } else {
175 if (LOCAL_DEBUG) {
176 Slog.i(TAG, "fail");
177 }
178 return "-1";
179 }
180 }
首先是149行的connect方法:
43 private boolean connect() {
44 if (mSocket != null) {
45 return true;
46 }
47 Slog.i(TAG, "connecting...");
48 try {
49 mSocket = new LocalSocket();
50
51 LocalSocketAddress address = new LocalSocketAddress("installd",
52 LocalSocketAddress.Namespace.RESERVED);
53
54 mSocket.connect(address);
55
56 mIn = mSocket.getInputStream();
57 mOut = mSocket.getOutputStream();
58 } catch (IOException ex) {
59 disconnect();
60 return false;
61 }
62 return true;
63 }
到这里已经很清楚了,实则是通过socket连接到本地方法,即指挥installd在C语言的文件中完成工作。
网络下载应用安装过程代码解析
当从网络上下载APK完成后,自动调用Packagemanager的安装方法installPackage。如前面所述,最终是调用PackageManagerService的installPackage方法。如下:
4882 /* Called when a downloaded package installation has been confirmed by the user */
4883 public void installPackage(
4884 final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
4885 installPackage(packageURI, observer, flags, null);
4886 }
4887
4888 /* Called when a downloaded package installation has been confirmed by the user */
4889 public void installPackage(
4890 final Uri packageURI, final IPackageInstallObserver observer, final int flags,
4891 final String installerPackageName) {
4892 installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
4893 null);
4894 }
4895
4896 @Override
4897 public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
4898 int flags, String installerPackageName, Uri verificationURI,
4899 ManifestDigest manifestDigest) {
4900 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
4901
4902 final int uid = Binder.getCallingUid();
4903
4904 final int filteredFlags;
4905
4906 if (uid == Process.SHELL_UID || uid == 0) {
4907 if (DEBUG_INSTALL) {
4908 Slog.v(TAG, "Install from ADB");
4909 }
4910 filteredFlags = flags | PackageManager.INSTALL_FROM_ADB;
4911 } else {
4912 filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB;
4913 }
4914
4915 final Message msg = mHandler.obtainMessage(INIT_COPY);
4916 msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
4917 verificationURI, manifestDigest);
4918 mHandler.sendMessage(msg);
4919 }
可以发现,调用之后进入到4945-4918行,通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法。在前面章节已经介绍了PackageManagerService中PackageHandler的定义。HandleMessage()把信息发给doHandleMessage()方法,方法中用switch语句进行判定传来Message进行分支处理。这里传入的消息的msg.what是INIT_COPY,进入到INIT_COPY分支,可以看到,一旦成功绑定了com.android.defcontainer.DefaultContainerService服务,则进入506行–mHandler.sendEmptyMessage(MCS_BOUND);此时进入doHandleMessage方法的switch语句的MCS_BOUND分支,跟踪进去,关键代码:
528 if (params.startCopy()) {
params是PackageManagerService中内部抽象类HandlerParams的子类InstallParams(参见上面4916行)的实例,HandlerParams代码清单:
5202 private abstract class HandlerParams {
5203 private static final int MAX_RETRIES = 4;
5204
5205 /**
5206 * Number of times startCopy() has been attempted and had a non-fatal
5207 * error.
5208 */
5209 private int mRetries = 0;
5210
5211 final boolean startCopy() {
5212 boolean res;
5213 try {
5214 if (DEBUG_INSTALL) Slog.i(TAG, "startCopy");
5215
5216 if (++mRetries > MAX_RETRIES) {
5217 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
5218 mHandler.sendEmptyMessage(MCS_GIVE_UP);
5219 handleServiceError();
5220 return false;
5221 } else {
5222 handleStartCopy();
5223 res = true;
5224 }
5225 } catch (RemoteException e) {
5226 if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
5227 mHandler.sendEmptyMessage(MCS_RECONNECT);
5228 res = false;
5229 }
5230 handleReturnCode();
5231 return res;
5232 }
5233
5234 final void serviceError() {
5235 if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
5236 handleServiceError();
5237 handleReturnCode();
5238 }
5239
5240 abstract void handleStartCopy() throws RemoteException;
5241 abstract void handleServiceError();
5242 abstract void handleReturnCode();
5243 }
5244
startCopy()方法中关键代码是先调用handleStartCopy()方法,再调用handleReturnCode()方法(由子类实现,这里即InstallParams的handleStartCopy()方法和handleReturnCode()方法),handleStartCopy()代码较多,但是前面基本是校验相关逻辑,关键部分在:
5557 } else {
5558 /*
5559 * No package verification is enabled, so immediately start
5560 * the remote call to initiate copy using temporary file.
5561 */
5562 ret = args.copyApk(mContainerService, true);
5563 }
args是抽象类InstallArgs的子类实现类SdInstallArgs(安装在SD卡时)或FileInstallArgs(非安装在)的实例对象,copyApk是负责将下载的APK文件copy到/data/app目录下。而handleReturnCode方法如下:
5569 @Override
5570 void handleReturnCode() {
5571 // If mArgs is null, then MCS couldn't be reached. When it
5572 // reconnects, it will try again to install. At that point, this
5573 // will succeed.
5574 if (mArgs != null) {
5575 processPendingInstall(mArgs, mRet);
5576 }
5577 }
这时可以清楚的看见processPendingInstall()被调用。其代码为:
5129 private void processPendingInstall(final InstallArgs args, final int currentStatus) {
5130 // Queue up an async operation since the package installation may take a little while.
5131 mHandler.post(new Runnable() {
5132 public void run() {
5133 mHandler.removeCallbacks(this);
5134 // Result object to be returned
5135 PackageInstalledInfo res = new PackageInstalledInfo();
5136 res.returnCode = currentStatus;
5137 res.uid = -1;
5138 res.pkg = null;
5139 res.removedInfo = new PackageRemovedInfo();
5140 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
5141 args.doPreInstall(res.returnCode);
5142 synchronized (mInstallLock) {
5143 installPackageLI(args, true, res);
5144 }
5145 args.doPostInstall(res.returnCode);
5146 }
5147
5148 // A restore should be performed at this point if (a) the install
5149 // succeeded, (b) the operation is not an update, and (c) the new
5150 // package has a backupAgent defined.
5151 final boolean update = res.removedInfo.removedPackage != null;
5152 boolean doRestore = (!update
5153 && res.pkg != null
5154 && res.pkg.applicationInfo.backupAgentName != null);
5155
5156 // Set up the post-install work request bookkeeping. This will be used
5157 // and cleaned up by the post-install event handling regardless of whether
5158 // there's a restore pass performed. Token values are >= 1.
5159 int token;
5160 if (mNextInstallToken < 0) mNextInstallToken = 1;
5161 token = mNextInstallToken++;
5162
5163 PostInstallData data = new PostInstallData(args, res);
5164 mRunningInstalls.put(token, data);
5165 if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
5166
5167 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
5168 // Pass responsibility to the Backup Manager. It will perform a
5169 // restore if appropriate, then pass responsibility back to the
5170 // Package Manager to run the post-install observer callbacks
5171 // and broadcasts.
5172 IBackupManager bm = IBackupManager.Stub.asInterface(
5173 ServiceManager.getService(Context.BACKUP_SERVICE));
5174 if (bm != null) {
5175 if (DEBUG_INSTALL) Log.v(TAG, "token " + token
5176 + " to BM for possible restore");
5177 try {
5178 bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
5179 } catch (RemoteException e) {
5180 // can't happen; the backup manager is local
5181 } catch (Exception e) {
5182 Slog.e(TAG, "Exception trying to enqueue restore", e);
5183 doRestore = false;
5184 }
5185 } else {
5186 Slog.e(TAG, "Backup Manager not found!");
5187 doRestore = false;
5188 }
5189 }
5190
5191 if (!doRestore) {
5192 // No restore possible, or the Backup Manager was mysteriously not
5193 // available -- just fire the post-install work request directly.
5194 if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
5195 Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
5196 mHandler.sendMessage(msg);
5197 }
5198 }
5199 });
5200 }
关键部分代码为5140-5146行:
5140 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
5141 args.doPreInstall(res.returnCode);
5142 synchronized (mInstallLock) {
5143 installPackageLI(args, true, res);
5144 }
5145 args.doPostInstall(res.returnCode);
5146 }
这里installPackageLI(args, true, res)的代码为:
5573 private void installPackageLI(InstallArgs args,
5574 boolean newInstall, PackageInstalledInfo res) {
5575 int pFlags = args.flags;
5576 String installerPackageName = args.installerPackageName;
5577 File tmpPackageFile = new File(args.getCodePath());
5578 boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
5579 boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
5580 boolean replace = false;
5581 int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
5582 | (newInstall ? SCAN_NEW_INSTALL : 0);
5583 // Result object to be returned
5584 res.returnCode = PackageManager.INSTALL_SUCCEEDED;
5585
5586 // Retrieve PackageSettings and parse package
5587 int parseFlags = PackageParser.PARSE_CHATTY |
5588 (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
5589 (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
5590 parseFlags |= mDefParseFlags;
5591 PackageParser pp = new PackageParser(tmpPackageFile.getPath());
5592 pp.setSeparateProcesses(mSeparateProcesses);
5593 final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
5594 null, mMetrics, parseFlags);
5595 if (pkg == null) {
5596 res.returnCode = pp.getParseError();
5597 return;
5598 }
5599 String pkgName = res.name = pkg.packageName;
5600 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
5601 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
5602 res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
5603 return;
5604 }
5605 }
5606 if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
5607 res.returnCode = pp.getParseError();
5608 return;
5609 }
5610
5611 /* If the installer passed in a manifest digest, compare it now. */
5612 if (args.manifestDigest != null) {
5613 if (DEBUG_INSTALL) {
5614 final String parsedManifest = pkg.manifestDigest == null ? "null"
5615 : pkg.manifestDigest.toString();
5616 Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
5617 + parsedManifest);
5618 }
5619
5620 if (!args.manifestDigest.equals(pkg.manifestDigest)) {
5621 res.returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
5622 return;
5623 }
5624 } else if (DEBUG_INSTALL) {
5625 final String parsedManifest = pkg.manifestDigest == null
5626 ? "null" : pkg.manifestDigest.toString();
5627 Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
5628 }
5629
5630 // Get rid of all references to package scan path via parser.
5631 pp = null;
5632 String oldCodePath = null;
5633 boolean systemApp = false;
5634 synchronized (mPackages) {
5635 // Check if installing already existing package
5636 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
5637 String oldName = mSettings.mRenamedPackages.get(pkgName);
5638 if (pkg.mOriginalPackages != null
5639 && pkg.mOriginalPackages.contains(oldName)
5640 && mPackages.containsKey(oldName)) {
5641 // This package is derived from an original package,
5642 // and this device has been updating from that original
5643 // name. We must continue using the original name, so
5644 // rename the new package here.
5645 pkg.setPackageName(oldName);
5646 pkgName = pkg.packageName;
5647 replace = true;
5648 } else if (mPackages.containsKey(pkgName)) {
5649 // This package, under its official name, already exists
5650 // on the device; we should replace it.
5651 replace = true;
5652 }
5653 }
5654 PackageSetting ps = mSettings.mPackages.get(pkgName);
5655 if (ps != null) {
5656 oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
5657 if (ps.pkg != null && ps.pkg.applicationInfo != null) {
5658 systemApp = (ps.pkg.applicationInfo.flags &
5659 ApplicationInfo.FLAG_SYSTEM) != 0;
5660 }
5661 }
5662 }
5663
5664 if (systemApp && onSd) {
5665 // Disable updates to system apps on sdcard
5666 Slog.w(TAG, "Cannot install updates to system apps on sdcard");
5667 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
5668 return;
5669 }
5670
5671 if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
5672 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
5673 return;
5674 }
5675 // Set application objects path explicitly after the rename
5676 setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
5677 pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
5678 if (replace) {
5679 replacePackageLI(pkg, parseFlags, scanMode,
5680 installerPackageName, res);
5681 } else {
5682 installNewPackageLI(pkg, parseFlags, scanMode,
5683 installerPackageName,res);
5684 }
5685 }
关键部分在最后的5678-5684行,如果是重复安装则调用replacePackageLI,负责调用installNewPackageLI(pkg, parseFlags, scanMode,installerPackageName,res);这里以installNewPackageLI为例:
6259 /*
6260 * Install a non-existing package.
6261 */
6262 private void installNewPackageLI(PackageParser.Package pkg,
6263 int parseFlags,
6264 int scanMode,
6265 String installerPackageName, PackageInstalledInfo res) {
6266 // Remember this for later, in case we need to rollback this install
6267 String pkgName = pkg.packageName;
6268
6269 boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
6270 res.name = pkgName;
6271 synchronized(mPackages) {
6272 if (mSettings.mRenamedPackages.containsKey(pkgName)) {
6273 // A package with the same name is already installed, though
6274 // it has been renamed to an older name. The package we
6275 // are trying to install should be installed as an update to
6276 // the existing one, but that has not been requested, so bail.
6277 Slog.w(TAG, "Attempt to re-install " + pkgName
6278 + " without first uninstalling package running as "
6279 + mSettings.mRenamedPackages.get(pkgName));
6280 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
6281 return;
6282 }
6283 if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
6284 // Don't allow installation over an existing package with the same name.
6285 Slog.w(TAG, "Attempt to re-install " + pkgName
6286 + " without first uninstalling.");
6287 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
6288 return;
6289 }
6290 }
6291 mLastScanError = PackageManager.INSTALL_SUCCEEDED;
6292 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
6293 System.currentTimeMillis());
6294 if (newPackage == null) {
6295 Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
6296 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
6297 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
6298 }
6299 } else {
6300 updateSettingsLI(newPackage,
6301 installerPackageName,
6302 res);
6303 // delete the partially installed application. the data directory will have to be
6304 // restored if it was already existing
6305 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
6306 // remove package from internal structures. Note that we want deletePackageX to
6307 // delete the package data and cache directories that it created in
6308 // scanPackageLocked, unless those directories existed before we even tried to
6309 // install.
6310 deletePackageLI(
6311 pkgName, false,
6312 dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
6313 res.removedInfo, true);
6314 }
6315 }
6316 }
关键代码部分为:
6292 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
6293 System.currentTimeMillis());
最终回到了和开机安装一样的地方,与开机方式安装调用统一方法scanPackageLI。后续步骤则完全一致了。
从ADB工具安装过程代码解析
通过adb命令方式,真实的入口其实是com/android/commands/pm/Pm.java,其中showUsage方法为使用方法说明:
1111 private static void showUsage() {
1112 System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]");
1113 System.err.println(" pm list permission-groups");
1114 System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
1115 System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
1116 System.err.println(" pm list features");
1117 System.err.println(" pm list libraries");
1118 System.err.println(" pm path PACKAGE");
1119 System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
1120 System.err.println(" pm uninstall [-k] PACKAGE");
1121 System.err.println(" pm clear PACKAGE");
1122 System.err.println(" pm enable PACKAGE_OR_COMPONENT");
1123 System.err.println(" pm disable PACKAGE_OR_COMPONENT");
1124 System.err.println(" pm disable-user PACKAGE_OR_COMPONENT");
1125 System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
1126 System.err.println(" pm get-install-location");
1127 System.err.println(" pm createUser USER_NAME");
1128 System.err.println(" pm removeUser USER_ID");
1129 System.err.println("");
1130 System.err.println("pm list packages: prints all packages, optionally only");
1131 System.err.println(" those whose package name contains the text in FILTER. Options:");
1132 System.err.println(" -f: see their associated file.");
1133 System.err.println(" -d: filter to only show disbled packages.");
1134 System.err.println(" -e: filter to only show enabled packages.");
1135 System.err.println(" -s: filter to only show system packages.");
1136 System.err.println(" -3: filter to only show third party packages.");
1137 System.err.println(" -u: also include uninstalled packages.");
...
而安装时调用的方法即runInstall(),方法内的关键代码为:
798 PackageInstallObserver obs = new PackageInstallObserver();
799 try {
800 mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName,
801 verificationURI, null);
802
803 synchronized (obs) {
804 while (!obs.finished) {
805 try {
806 obs.wait();
807 } catch (InterruptedException e) {
808 }
809 }
810 if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
811 System.out.println("Success");
812 } else {
813 System.err.println("Failure ["
814 + installFailureToString(obs.result)
815 + "]");
816 }
817 }
818 } catch (RemoteException e) {
819 System.err.println(e.toString());
820 System.err.println(PM_NOT_RUNNING_ERR);
821 }
可以看出,实则调用mPm变量的installPackageWithVerification方法。mPm变量为IPackageManager接口的实现类的对象,通过78行,不难发现,其实又是绑定远程的PackageManagerService来完成具体的操作,此时就回到与网络下载的地方了,后续步骤可参加网络下载部分的分析。
53 public final class Pm {
54 IPackageManager mPm;
55
56 private WeakHashMap<String, Resources> mResourceCache
57 = new WeakHashMap<String, Resources>();
58
59 private String[] mArgs;
60 private int mNextArg;
61 private String mCurArgData;
62
63 private static final String PM_NOT_RUNNING_ERR =
64 "Error: Could not access the Package Manager. Is the system running?";
65 private static final int ROOT_UID = 0;
66
67 public static void main(String[] args) {
68 new Pm().run(args);
69 }
70
71 public void run(String[] args) {
72 boolean validCommand = false;
73 if (args.length < 1) {
74 showUsage();
75 return;
76 }
77
78 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
79 if (mPm == null) {
80 System.err.println(PM_NOT_RUNNING_ERR);
81 return;
82 }
通过第三方应用从SD卡安装的过程代码分析
这其实相当于在PackagManager之上提供一个更便捷的方式给用户安装APK,系统上层的源码中有一个类(Activity)com/android/packageinstaller/PackageInstallerActivity.java,通过它可以便捷地使UI方式安装APK。PackageInstallerActivity的oncreate方法如下(本文的采用的版本可能与读者的版本不同,所以行号和代码细节会有差异,请注意):
235 @Override
236 protected void onCreate(Bundle icicle) {
237 super.onCreate(icicle);
238 //get intent information
239 final Intent intent = getIntent();
240 mPackageURI = intent.getData();
241 mPm = getPackageManager();
242 mPkgInfo = PackageUtil.getPackageInfo(mPackageURI);
243
244 // Check for parse errors
245 if(mPkgInfo == null) {
246 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
247 showDialogInner(DLG_PACKAGE_ERROR);
248 return;
249 }
250
251 //set view
252 requestWindowFeature(Window.FEATURE_NO_TITLE);
253 setContentView(R.layout.install_start);
254 mInstallConfirm = findViewById(R.id.install_confirm_panel);
255 mInstallConfirm.setVisibility(View.INVISIBLE);
256 PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this,
257 mPkgInfo.applicationInfo, mPackageURI);
258 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
259 //check setting
260 if(!isInstallingUnknownAppsAllowed()) {
261 //ask user to enable setting first
262 showDialogInner(DLG_UNKNOWN_APPS);
263 return;
264 }
265 initiateInstall();
266 }
如265行所示,进入initiateInstall方法,跟踪可以发现,又进入startInstallConfirm()方法,这主要是弹出对话框,让用户确认是否安装,如果确认,那么即进入:
273 public void onClick(View v) {
274 if(v == mOk) {
275 // Start subactivity to actually install the application
276 Intent newIntent = new Intent();
277 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
278 mPkgInfo.applicationInfo);
279 newIntent.setData(mPackageURI);
280 newIntent.setClass(this, InstallAppProgress.class);
281 String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
282 if (installerPackageName != null) {
283 newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
284 }
285 if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
286 startActivity(newIntent);
287 finish();
288 } else if(v == mCancel) {
289 // Cancel and finish
290 finish();
291 }
292 }
确认后,打开新的activity:InstallAppProgress,com/android/packageinstaller/InstallAppProgress.java的关键代码:
126 @Override
127 public void onCreate(Bundle icicle) {
128 super.onCreate(icicle);
129 Intent intent = getIntent();
130 mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
131 mPackageURI = intent.getData();
132 initView();
133 }
...
176 public void initView() {
177 requestWindowFeature(Window.FEATURE_NO_TITLE);
178 setContentView(R.layout.op_progress);
179 int installFlags = 0;
180 PackageManager pm = getPackageManager();
181 try {
182 PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
183 PackageManager.GET_UNINSTALLED_PACKAGES);
184 if(pi != null) {
185 installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
186 }
187 } catch (NameNotFoundException e) {
188 }
189 if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
190 Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
191 }
192 PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,
193 mPackageURI);
194 mLabel = as.label;
195 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
196 mStatusTextView = (TextView)findViewById(R.id.center_text);
197 mStatusTextView.setText(R.string.installing);
198 mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
199 mProgressBar.setIndeterminate(true);
200 // Hide button till progress is being displayed
201 mOkPanel = (View)findViewById(R.id.buttons_panel);
202 mDoneButton = (Button)findViewById(R.id.done_button);
203 mLaunchButton = (Button)findViewById(R.id.launch_button);
204 mOkPanel.setVisibility(View.INVISIBLE);
205
206 String installerPackageName = getIntent().getStringExtra(
207 Intent.EXTRA_INSTALLER_PACKAGE_NAME);
208 PackageInstallObserver observer = new PackageInstallObserver();
209 pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
210 }
如上所示,209行则是执行安装的地方,不难发现,这里是pm对象在180行获取,到这里,又回到和网络下载一样的地方了,后续步骤可以参见网络下载安装部分解析。
总结
- 安装和卸载都是通过PackageManager,实质上是实现了PackageManager的远程服务PackageManagerService来完成具体的操作,所有细节和逻辑均可以在PackageManagerService中跟踪查看;
- 所有安装方式殊途同归,最终就回到PackageManagerService中,然后调用底层本地代码的installd来完成。