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结构图
    /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        @Override482        public PackageManager getPackageManager() {483            if (mPackageManager != null) {484                return mPackageManager;485            }486487            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            }492493            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        @Override935        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        }943944        @Override945        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        }955956        @Override957        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 an116     * application process, scheduling and executing activities,117     * broadcasts, and other operations on it as the activity118     * 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 unit144         * tests whenever making modifications here:145         * 146        mmm frameworks/base/tests/AndroidTests147        adb install -r -f out/target/product/passion/data/app/AndroidTests.apk148        adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner149         * 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>();443444                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                }458459                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                }466467                PackageHandler(Looper looper) {468                    super(looper);469                }470471                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 really487                            // need to do anything. The pending install488                            // will be processed later on.489                            if (!mBound) {490                                // If this is the only one pending we might491                                // 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 first498                                    // 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 make504                                // 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 out518                                Slog.e(TAG, "Cannot bind to media container service");519                                for (HandlerParams params : mPendingInstalls) {520                                    mPendingInstalls.remove(0);521                                    // Indicate service bind error522                                    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 to530                                        // go idle.531                                        if (DEBUG_SD_INSTALL) Log.i(TAG,532                                                "Checking for more work or unbind...");533                                        // Delete pending install534                                        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 avoid544                                                // 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 processing550                                            // 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 error574                                        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");584585                            if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {586                                if (mBound) {587                                    if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");588589                                    disconnectService();590                                }591                            } else if (mPendingInstalls.size() > 0) {592                                // There are more pending requests in queue.593                                // Just post MCS_BOUND message to trigger processing594                                // of next pending install.595                                mHandler.sendEmptyMessage(MCS_BOUND);596                            }597598                            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 return618                                    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 broadcasts638                            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;660661                            if (data != null) {662                                InstallArgs args = data.args;663                                PackageInstalledInfo res = data.res;664665                                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 now686                                        deleteOld = true;687                                    }688                                }689                                // Force a gc to clear up things690                                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 containers722                                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);753754                            if (state != null) {755                                final InstallArgs args = state.getInstallArgs();756                                Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());757                                mPendingVerification.remove(verificationId);758759                                int ret = PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT;760                                processPendingInstall(args, ret);761762                                mHandler.sendEmptyMessage(MCS_UNBIND);763                            }764765                            break;766                        }767                        case PACKAGE_VERIFIED: {768                            final int verificationId = msg.arg1;769770                            final PackageVerificationState state = mPendingVerification.get(verificationId);771                            if (state == null) {772                                Slog.w(TAG, "Invalid verification token " + verificationId + " received");773                                break;774                            }775776                            final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;777778                            state.setVerifierResponse(response.callerUid, response.code);779780                            if (state.isVerificationComplete()) {781                                mPendingVerification.remove(verificationId);782783                                final InstallArgs args = state.getInstallArgs();784785                                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                                }796797                                processPendingInstall(args, ret);798799                                mHandler.sendEmptyMessage(MCS_UNBIND);800                            }801802                            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_UIDS878                             ? RADIO_UID : FIRST_APPLICATION_UID,879                     ApplicationInfo.FLAG_SYSTEM);880             mSettings.addSharedUserLPw("android.uid.log",881                     MULTIPLE_APPLICATION_UIDS882                             ? LOG_UID : FIRST_APPLICATION_UID,883                     ApplicationInfo.FLAG_SYSTEM);884             mSettings.addSharedUserLPw("android.uid.nfc",885                     MULTIPLE_APPLICATION_UIDS886                             ? 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             // writer914             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 when934                 // 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 class950                  * 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 any996                 // 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, which1001                 * we currently need to do the dexopt on so that they can be1002                 * 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                }10291030                if (didDexOpt) {1031                    // If we had to do a dexopt of one of the previous1032                    // things, then something on the system has changed.1033                    // Consider this significant, and wipe away all other1034                    // existing dexopt files to ensure we don't leave any1035                    // 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                }10481049                // 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_SYSTEM1054                        | 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_SYSTEM1063                        | 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_SYSTEM1071                        | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);10721073                if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");1074                mInstaller.moveFiles();10751076                // 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) != 01082                                && !mPackages.containsKey(ps.name)1083                                && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {1084                            psit.remove();1085                            String msg = "System package " + ps.name1086                                    + " 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 installations1096                ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();1097                //clean up list1098                for(int i = 0; i < deletePkgsList.size(); i++) {1099                    //clean up here1100                    cleanupInstallFailedPackage(deletePkgsList.get(i));1101                }1102                //delete tmp files1103                deleteTempPackageFiles();11041105                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                }11221123                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");11281129                // 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 that1131                // appear.  This is really a hack, and means that apps can in some1132                // cases get permissions that the user didn't initially explicitly1133                // allow...  it would be nice to have some better way to handle1134                // this situation.1135                final boolean regrantPermissions = mSettings.mInternalSdkPlatform1136                        != mSdkVersion;1137                if (regrantPermissions) Slog.i(TAG, "Platform changed from "1138                        + mSettings.mInternalSdkPlatform + " to " + mSdkVersion1139                        + "; regranting permissions for internal storage");1140                mSettings.mInternalSdkPlatform = mSdkVersion;1141                1142                updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);11431144                // can downgrade to reader1145                mSettings.writeLPr();11461147                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,1148                        SystemClock.uptimeMillis());11491150                // Now after opening every single application zip, make sure they1151                // are all flushed.  Not really needed, but keeps things nice and1152                // tidy.1153                Runtime.getRuntime().gc();11541155                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

以下是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            }27382739            if (DEBUG_PACKAGE_SCANNING) {2740                Log.d(TAG, "Scanning app dir " + dir);2741            }27422743            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's2748                    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 apk2756                    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 installation3496        int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,3497                pkg.applicationInfo.uid);3498        if (ret < 0) {3499            // Error from installer3500            mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;3501            return null;3502        }3503        // Create data directories for all users3504        mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);

    不难看出,mInstaller.install是真正执行安装之处。而看看mInstaller的定义:

    258  // Used for priviledge escalation.  MUST NOT BE CALLED WITH mPackages259  // 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        }153154        if (!writeCommand(cmd)) {155            /*156             * If installd died and restarted in the background (unlikely but157             * possible) we'll fail on the next write (this one). Try to158             * 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();5051                LocalSocketAddress address = new LocalSocketAddress("installd",52                        LocalSocketAddress.Namespace.RESERVED);5354                mSocket.connect(address);5556                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        }48874888        /* 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        }48954896        @Override4897        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);49014902            final int uid = Binder.getCallingUid();49034904            final int filteredFlags;49054906            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            }49144915            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;52045205        /**5206         * Number of times startCopy() has been attempted and had a non-fatal5207         * error.5208         */5209        private int mRetries = 0;52105211        final boolean startCopy() {5212            boolean res;5213            try {5214                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy");52155216                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        }52335234        final void serviceError() {5235            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");5236            handleServiceError();5237            handleReturnCode();5238        }52395240        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 start5560         * 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    @Override5570    void handleReturnCode() {5571        // If mArgs is null, then MCS couldn't be reached. When it5572        // reconnects, it will try again to install. At that point, this5573        // 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 returned5135                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                }51475148                // A restore should be performed at this point if (a) the install5149                // succeeded, (b) the operation is not an update, and (c) the new5150                // package has a backupAgent defined.5151                final boolean update = res.removedInfo.removedPackage != null;5152                boolean doRestore = (!update5153                        && res.pkg != null5154                        && res.pkg.applicationInfo.backupAgentName != null);51555156                // Set up the post-install work request bookkeeping.  This will be used5157                // and cleaned up by the post-install event handling regardless of whether5158                // there's a restore pass performed.  Token values are >= 1.5159                int token;5160                if (mNextInstallToken < 0) mNextInstallToken = 1;5161                token = mNextInstallToken++;51625163                PostInstallData data = new PostInstallData(args, res);5164                mRunningInstalls.put(token, data);5165                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);51665167                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {5168                    // Pass responsibility to the Backup Manager.  It will perform a5169                    // restore if appropriate, then pass responsibility back to the5170                    // Package Manager to run the post-install observer callbacks5171                    // 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 " + token5176                                + " 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 local5181                        } 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                }51905191                if (!doRestore) {5192                    // No restore possible, or the Backup Manager was mysteriously not5193                    // 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_SIGNATURE5582                | (newInstall ? SCAN_NEW_INSTALL : 0);5583        // Result object to be returned5584        res.returnCode = PackageManager.INSTALL_SUCCEEDED;55855586        // Retrieve PackageSettings and parse package5587        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        }56105611        /* 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            }56195620            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 == null5626                    ? "null" : pkg.manifestDigest.toString();5627            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);5628        }56295630        // 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 package5636            if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {5637                String oldName = mSettings.mRenamedPackages.get(pkgName);5638                if (pkg.mOriginalPackages != null5639                        && 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 original5643                    // name.  We must continue using the original name, so5644                    // 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 exists5650                    // 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        }56635664        if (systemApp && onSd) {5665            // Disable updates to system apps on sdcard5666            Slog.w(TAG, "Cannot install updates to system apps on sdcard");5667            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;5668            return;5669        }56705671        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 rename5676        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 install6267        String pkgName = pkg.packageName;62686269        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, though6274                // it has been renamed to an older name.  The package we6275                // are trying to install should be installed as an update to6276                // the existing one, but that has not been requested, so bail.6277                Slog.w(TAG, "Attempt to re-install " + pkgName6278                        + " 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 " + pkgName6286                        + " 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 be6304            // restored if it was already existing6305            if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {6306                // remove package from internal structures.  Note that we want deletePackageX to6307                // delete the package data and cache directories that it created in6308                // scanPackageLocked, unless those directories existed before we even tried to6309                // 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);802803            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;5556            private WeakHashMap<String, Resources> mResourceCache57                    = new WeakHashMap<String, Resources>();5859            private String[] mArgs;60            private int mNextArg;61            private String mCurArgData;6263            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;6667            public static void main(String[] args) {68                new Pm().run(args);69            }7071            public void run(String[] args) {72                boolean validCommand = false;73                if (args.length < 1) {74                    showUsage();75                    return;76                }7778                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        @Override236        protected void onCreate(Bundle icicle) {237            super.onCreate(icicle);238            //get intent information239            final Intent intent = getIntent();240            mPackageURI = intent.getData();241            mPm = getPackageManager();242            mPkgInfo = PackageUtil.getPackageInfo(mPackageURI);243            244            // Check for parse errors245            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 view252            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 setting260            if(!isInstallingUnknownAppsAllowed()) {261                //ask user to enable setting first262                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 application276            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 finish290            finish();291        }292    }

确认后,打开新的activity:InstallAppProgress,com/android/packageinstaller/InstallAppProgress.java的关键代码:

126        @Override127        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 displayed201            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);205206            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来完成。