引言

众所周知,Android应用最终是打包成.apk格式(其实就是一个压缩包),然后安装至手机并运行的。APK即Android Package的缩写,那么,Android安装应用APK的具体方式及其详细过程是怎样的呢?下面,我们逐一揭开里面的层层面纱。

Android应用APK安装的方式

一般而言,Android应用安装有如下四种方式:

  1. 系统应用安装:开机时加载系统的APK和应用,没有安装界面;
  2. 网络下载应用安装:通过各种market应用完成,没有安装界面;
  3. ADB工具安装:即通过Android的SDK开发tools里面的adb.exe程序安装,没有安装界面;
  4. 第三方应用安装:通过SD卡里的APK文件安装(比如双击APK文件触发),有安装界面,系统默认已经安装了一个安装卸载应用的程序,即由packageinstaller.apk应用处理安装及卸载过程的界面。

    Android APK安装概述

    应用安装涉及到的目录

  1. /system/app :系统自带的应用程序,获得adb root权限才能删除
  2. /data/app :用户程序安装的目录。安装时把apk文件复制到此目录
  3. /data/data :存放应用程序的数据
  4. /data/dalvik-cache:将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,当然,ART–Android Runtime的可执行文件格式为oat,启用ART时,系统会执行dex文件转换至oat文件)
  5. /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。
    

安装过程总述

安卓系统安装一个应用时,系统大致会进行如下操作:

  1. 复制APK安装包到data/app目录下,文件名会以应用的package命名;
  2. 解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录(一般情况下,会先执行dexopt即dex文件的优化,将优化后的dex文件保存至该目录下),并data/data目录下创建对应的应用数据目录(data/data目录可读可写);
  3. 更新/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 init

以下是PackageManagerService主要的工作内容:

  1. 建立java层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现;
  2. 建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息;
  3. 解析/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等几个集合中供系统查询和权限配置使用

  4. 检查/data/system/packages.xml是否存在,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
  5. 检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要的则通过dexopt进行优化;
  6. 启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。当有add event时调用scanPackageLI(File , int , int)处理;当有remove event时调用removePackageLI()处理;
  7. 对于以上几个目录下的apk逐个解析,主要是解析每个apk的AndroidMa-nifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息,并将每个apk的配置信息添加到全局列表进行管理。调用installer.install()进行安装工作,检查apk里的dex文件是否需要再优化,如果需要优化则通过辅助工具dexopt进行优化处理;将解析出的componet添加到pkg的对应列表里;对apk进行签名和证书校验,进行完整性验证。
  8. 将解析的每个apk的信息保存到packages.xml和packages.list文件里,packages.list记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)。

    开机安装过程代码解析

    有了上面的认识,接下来分析安装的过程就比较轻松了(均围绕PackageManagerService.java展开)。开机安装过程的代码流程如下:

  9. 扫描各目录(/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行)。

  10. 扫描目录关键方法的代码清单:

    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        }
    
  11. 从上面扫描方法的代码中可以看出实质是调用了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行获取,到这里,又回到和网络下载一样的地方了,后续步骤可以参见网络下载安装部分解析。

总结

  1. 安装和卸载都是通过PackageManager,实质上是实现了PackageManager的远程服务PackageManagerService来完成具体的操作,所有细节和逻辑均可以在PackageManagerService中跟踪查看;
  2. 所有安装方式殊途同归,最终就回到PackageManagerService中,然后调用底层本地代码的installd来完成。