浅谈framework之PackageManagerService

1. 前言

PackageManagerService在android系统中, 主要工作负责系统应用的安装与卸载工作,由于系统中还有一个名字叫PowerManagerService的系统服务,所以下面我将他的缩写命为PAMS,防止混淆。
顺便提一下,这篇文章理论基础是android 4.4.2。

2. PAMS启动过程

PAMS是一个系统服务,那它的启动必然是由系统所带动的。它的启动过程这里简单说一下,有兴趣的朋友可以根据这个思路跟一下代码。
话说在系统开机那一刻,init进程解析init.rc的时候会启动zygote进程,代码如下:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

位于“/system/bin/app_process”指向的是app_main.cpp,请注意init.rc里的传下来的参数,然后找到函数入口,定位到关键函数:

int main()
{    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = arg + 12;
        } else {
            className = arg;
            break;
        }
    }
 if (zygote) {
 //1
        runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");
    } else if (className) {
        // Remainder of args get passed to startup class main()
        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        runtime.start("com.android.internal.os.`RuntimeInit`",
                application ? "application" : "tool");
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
    }

上面代码,其实只需要看注释1下面两行代码,继续往下走,找到AndroidRuntime.cpp的“start”函数,下面已截取关键函数,让大家省心:

    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }

可以看到这里是利用了jni的原理反射调用ZygoteInit类的main函数,好的,那就继续找到它的main函数,代码有删减:

public static void main(String argv[]) {
            if (argv[1].equals("start-system-server")) {
                startSystemServer();
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }
}

很直观,直接看startSystemServer函数做了什么工作:

    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_KILL,
            OsConstants.CAP_NET_ADMIN,
            OsConstants.CAP_NET_BIND_SERVICE,
            OsConstants.CAP_NET_BROADCAST,
            OsConstants.CAP_NET_RAW,
            OsConstants.CAP_SYS_MODULE,
            OsConstants.CAP_SYS_NICE,
            OsConstants.CAP_SYS_RESOURCE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG
        );
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=****",
            "--setgid=****",
            "--setgroups=****",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
			
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

上面的代码核心思想是fork一个进程,当pid为0时候就执行handleSystemServerProcess函数,handleSystemServerProcess函数的核心代码如下:

RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);

继续往下就会调用SystemServer的main函数,中间会跳转几个函数,这些这里不再赘述。
到SystemServer的main函数里,PAMS就在这里启动。
关键代码如下:

            pm = PackageManagerService.main(context, installer,
                    factoryTest != SystemServer.FACTORY_TEST_OFF,
                    onlyCore);

好啦,最后在这一小节,简单说一下,接下来PAMS第一次开机的时候会扫描系统各个存放apk的目录,然后解析其的AndroidManifest.xml,校验签名,优化dex,安装应用等操作。

3. installd底层服务启动过程

在继续讲PAMS之前,插播一下installd服务的启动过程,为啥讲的好好的PAMS,提这个感觉不相关的服务干嘛?这肯定是有关,而且PAMS最终还是依靠installd这个大哥干活呢,废话不多说,进入主题。
installd这个服务第一次出现的地方是在init.rc,代码如下:

service installd /system/bin/installd
    class main
    socket installd stream 600 system system

可以看到这个服务启动时由socket进行连接的,什么时候建立通信过程的呢,这里先留一个疑问,下文将会说明。

4. 解析过程

接第2节内容,我们看PackageManagerService.java的main函数:

   public static final IPackageManager main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        ServiceManager.addService("package", m);
        return m;
    }

好的,其他不解释,直接看PackageManagerService的构造函数,这里就不再深入解释binder的东西了。

    public PackageManagerService(Context context, Installer installer,
         boolean factoryTest, boolean onlyCore){
        boolean optimize = false;
        optimize = SystemProperties.getBoolean("persist.sys.boot.optimize", false);
        if(optimize){
            PackageManagerService_Optimize(context,installer,factoryTest,onlyCore);
        }else{
            PackageManagerService_Orig(context,installer,factoryTest,onlyCore);
        }
    }

好的,首先我自己参与定制系统,可知optimize变量为true,走优化分支,下面那个分支是默认分支,那个这里不讨论,只说明如何优化的。

5. 安装过程

应用安装相对应用卸载来说要稍微复杂一点,这里我会 比较详细的说一下。
据我所知,应用安装他开机启动的时候PAMS会在他的构造函数里面进行安装,还有就是用户自己安装的应用是调用到系统api的installPackage函数进行安装,还有一种是使用adb命令进行安装操作这三种情况。

5.1 开机安装

开机的时候,SystemServer会拉起PackageManagerService,然后会在PackageManagerService的构造函数里实现对应用的的安装操作。我们直接进入到PackageManagerService_Optimize函数开始分析。函数比较长,我第一次看的也有点难受,多看几遍就差不多弄懂啥意思了,有点考验自己的耐心了。

    public void PackageManagerService_Optimize(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }

        mContext = context;  //获取上下文
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        mMetrics = new DisplayMetrics();
        mSettings = new Settings(context);     //在这里创建packages.xml等文件对象
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

        String separateProcesses = SystemProperties.get("debug.separate_processes");
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if ("*".equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(",");
                Slog.w(TAG, "Running with debug.separate_processes: "
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }

        mInstaller = installer;        //为当前对象赋值为installer

        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Display d = wm.getDefaultDisplay();
        d.getMetrics(mMetrics);

        File frameworkDir;
        int scanMode;
        long startTime;
        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),
                    WATCHDOG_TIMEOUT);

            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLibInstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            sUserManager = new UserManagerService(context, this,
                    mInstallLock, mPackages);

            readPermissions();        //解析etc/permissions/目录下的各种xml文件

            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
			/**
              *  下面这段代码也很重要,他会去读/data/system/packages.xml,解析之后将存起,第一次是没有这个文件的,所以会跳过,
              * packages.xml记录了应用包的各种重要信息,安装,更新,卸载都会更新这个文件
              * /
            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),   
                    mSdkVersion, mOnlyCore);

            String customResolverActivity = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
            if (TextUtils.isEmpty(customResolverActivity)) {
                customResolverActivity = null;
            } else {
                mCustomResolverComponentName = ComponentName.unflattenFromString(
                        customResolverActivity);
            }

            startTime = SystemClock.uptimeMillis();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
            if (mNoDexOpt) {
                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                scanMode |= SCAN_NO_DEX;
            }

            final HashSet<String> alreadyDexOpted = new HashSet<String>();

            /**
             * Add everything in the in the boot class path to the
             * list of process files because dexopt will have been run
             * if necessary during zygote startup.
             */
            String bootClassPath = System.getProperty("java.boot.class.path");
            if (bootClassPath != null) {
                String[] paths = splitString(bootClassPath, ':');
                for (int i=0; i<paths.length; i++) {
                    alreadyDexOpted.add(paths[i]);
                }
            } else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            boolean didDexOpt = false;

            /**
             * Ensure all external libraries have had dexopt run on them.
             */
            if (mSharedLibraries.size() > 0) {
                Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
                ExecutorService executorService = Executors.newFixedThreadPool(sNThreads);
                while (libs.hasNext()) {
                    final String lib = libs.next().path;
                    if (lib == null) {
                        continue;
                    }
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
                            alreadyDexOpted.add(lib);
                            didDexOpt = true;
                            executorService.submit(new Runnable() {
                                    @Override
                                    public void run() {
                                        mInstaller.dexopt(lib, Process.SYSTEM_UID, true);  //预优化操作
                                    }
                            });
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Library not found: " + lib);
                    } catch (IOException e) {
                        Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                + e.getMessage());
                    }
                }
                executorService.shutdown();
                try {
                    executorService.awaitTermination(1, TimeUnit.DAYS);
                } catch (InterruptedException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }

            frameworkDir = new File(Environment.getRootDirectory(), "framework");
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
            String[] frameworkFiles = frameworkDir.list();
            if (frameworkFiles != null) {
                ExecutorService executorService = Executors.newFixedThreadPool(sNThreads);
                for (int i=0; i<frameworkFiles.length; i++) {
                    File libPath = new File(frameworkDir, frameworkFiles[i]);
                    final String path = libPath.getPath();
                    // Skip the file if we alrady did it.
                    if (alreadyDexOpted.contains(path)) {
                        continue;
                    }
                    // Skip the file if it is not a type we want to dexopt.
                    if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                        continue;
                    }
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(path)) {
                            didDexOpt = true;
                            executorService.submit(new Runnable() {
                                    @Override
                                    public void run() {
                                        mInstaller.dexopt(path, Process.SYSTEM_UID, true);
                                    }
                            });
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Jar not found: " + path);
                    } catch (IOException e) {
                        Slog.w(TAG, "Exception reading jar: " + path, e);
                    }
                }
                executorService.shutdown();
                try {
                    executorService.awaitTermination(1, TimeUnit.DAYS);
                } catch (InterruptedException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }

            if (didDexOpt) {
                File dalvikCacheDir = new File(dataDir, "dalvik-cache");

                // If we had to do a dexopt of one of the previous
                // things, then something on the system has changed.
                // Consider this significant, and wipe away all other
                // existing dexopt files to ensure we don't leave any
                // dangling around.
                String[] files = dalvikCacheDir.list();
                if (files != null) {
                    for (int i=0; i<files.length; i++) {
                        String fn = files[i];
                        if (fn.startsWith("data@app@")
                                || fn.startsWith("data@app-private@")) {
                            Slog.i(TAG, "Pruning dalvik file: " + fn);
                            (new File(dalvikCacheDir, fn)).delete();
                        }
                    }
                }
            }
        }
    }

            // Find base frameworks (resource packages without code).
            mFrameworkInstallObserver = new AppDirObserver(
                frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
            mFrameworkInstallObserver.startWatching();
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanMode | SCAN_NO_DEX, 0);

            // Collected privileged system packages.
            File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            mPrivilegedInstallObserver = new AppDirObserver(
                    privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
            mPrivilegedInstallObserver.startWatching();
                scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR
                        | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);

            // Collect ordinary system packages.
            File systemAppDir = new File(Environment.getRootDirectory(), "app");
            mSystemInstallObserver = new AppDirObserver(
                systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
            mSystemInstallObserver.startWatching();
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/app");
            mVendorInstallObserver = new AppDirObserver(
                vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
            mVendorInstallObserver.startWatching();
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

            synchronized (mInstallLock) {
            synchronized (mPackages) {
            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

            // Prune any system packages that no longer exist.
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /*
                     * If the package is scanned, it's not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            Slog.i(TAG, "Expecting better updatd system app for " + ps.name
                                    + "; removing system app");
                            removePackageLI(ps, true);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        String msg = "System package " + ps.name
                                + " no longer exists; wiping its data";
                        reportSettingsProblem(Log.WARN, msg);
                        removeDataDirsLI(ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

            //look for any incomplete package installations
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //clean up list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                //clean up here
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            //delete tmp files
            deleteTempPackageFiles();

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();
            }
            }
            if(SystemProperties.get("persist.sys.qb.enable","false").equals("true"))
                mDataAppPackage.clear();
            if(SystemProperties.get("ro.laterscan.enable","false").equals("false")) {
                Slog.e(TAG, "isFirstBoot() = " + isFirstBoot());

                if (!mOnlyCore)
                {
                    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                            SystemClock.uptimeMillis());
                    mAppInstallObserver = new AppDirObserver(
                        mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
                    mAppInstallObserver.startWatching();
                     //这里会搜索data/app下的安装包,它的实现中会有调用scanPackageLI去解析安装包并实现安装过程
                    scanDirLI(mAppInstallDir, 0, scanMode, 0);           
                    mDrmAppInstallObserver = new AppDirObserver(
                        mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);
                    mDrmAppInstallObserver.startWatching();
                    scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                            scanMode, 0);
                }
                synchronized (mPackages) {
                    /**
                     * Remove disable package settings for any updated system
                     * apps that were removed via an OTA. If they're not a
                     * previously-updated app, remove them completely.
                     * Otherwise, just revoke their system-level permissions.
                     */
                    for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                        PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                        mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                        String msg;
                        if (deletedPkg == null) {
                            msg = "Updated system package " + deletedAppName
                                    + " no longer exists; wiping its data";
                            removeDataDirsLI(deletedAppName);
                        } else {
                            msg = "Updated system app + " + deletedAppName
                                    + " no longer present; removing system privileges for "
                                    + deletedAppName;

                            deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                            PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                            deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                        }
                        reportSettingsProblem(Log.WARN, msg);
                    }
                }
            }
            //later user
            if(SystemProperties.get("ro.laterscan.enable","false").equals("true"))
            {
                getLauncherFormFile();
                scanDataLauncher();
            }
            synchronized (mInstallLock) {
            synchronized (mPackages) {
            updateAllSharedLibrariesLPw();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");
            final boolean regrantPermissions = mSettings.mInternalSdkPlatform
                    != mSdkVersion;
            if (regrantPermissions) Slog.i(TAG, "Platform changed from "
                    + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
                    + "; regranting permissions for internal storage");
            mSettings.mInternalSdkPlatform = mSdkVersion;

            updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
                    | (regrantPermissions
                            ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                            : 0));

            // If this is the first boot, and it is a normal boot, then
            // we need to initialize the default preferred apps.
            if (!mRestoredSettings && !onlyCore) {
                mSettings.readDefaultPreferredAppsLPw(this, 0);
            }

            // can downgrade to reader
            mSettings.writeLPr();   //更新packages.xml文件

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            // Now after opening every single application zip, make sure they
            // are all flushed.  Not really needed, but keeps things nice and
            // tidy.
            Runtime.getRuntime().gc();

            mRequiredVerifierPackage = getRequiredVerifierLPr();
        } // synchronized (mPackages)
        } // synchronized (mInstallLock)
    }

上边代码,做了一些注释,但实现安装的关键函数是scanPackageLI,他通过调用parsePackage解析安装包中AndroidManifest.xml,并通过调用createDataDirsLI进行安装操作。
createDataDirsLI函数实现为:

    private int createDataDirsLI(String packageName, int uid, String seinfo) {
        int[] users = sUserManager.getUserIds();
        int res = mInstaller.install(packageName, uid, uid, seinfo);
        if (res < 0) {
            return res;
        }
        for (int user : users) {
            if (user != 0) {
                res = mInstaller.createUserData(packageName,
                        UserHandle.getUid(user, uid), user);
                if (res < 0) {
                    return res;
                }
            }
        }
        return res;
    }

经过socket连接调用到了native installd服务的do_install函数(这个连接过程下文卸载操作会说的详细一些)

static int do_install(char **arg, char reply[REPLY_MAX])
{	
	ALOGE("has do_install");
    return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */
}

install函数其实就是创建data/data/packagename目录下的各种数据文件,与之对应的卸载,即是删除这些文件,完成卸载操作。

5.2 应用层安装

除了系统自己安装之外,也可以开发者自己调用系统api安装,毕竟每次安装都重启之后让PAMS来安装是不太合理的,实际就是调用installPackage函数。如下:

    public void installPackage(
            final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
        installPackage(packageURI, observer, flags, null);
    }

然后:

    public void installPackage(
            final Uri packageURI, final IPackageInstallObserver observer, final int flags,
            final String installerPackageName) {
        installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
                null, null);
    }

再然后:

    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
            int flags, String installerPackageName, Uri verificationURI,
            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
        VerificationParams verificationParams = new VerificationParams(verificationURI, null, null,
                VerificationParams.NO_UID, manifestDigest);
        installPackageWithVerificationAndEncryption(packageURI, observer, flags,
                installerPackageName, verificationParams, encryptionParams);
    }

再然后:

    public void installPackageWithVerificationAndEncryption(Uri packageURI,
            IPackageInstallObserver observer, int flags, String installerPackageName,
            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
    .........//此处省略n行

        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
                verificationParams, encryptionParams, user);
        mHandler.sendMessage(msg);
    }

上面函数installPackageWithVerificationAndEncryption可以看到他发了一个消息,并传递了对象参数,找到处理消息的地方:

        void doHandleMessage(Message msg) {
            switch (msg.what) {
            ......//此处省去n行代码
               case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {
                        // If this is the only one pending we might
                        // have to bind to the service again.
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            return;
                        } else {
                            // Once we bind to the service, the first
                            // pending request will be processed.
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }
                    ......//此处省去n行代码
            }
            }

在接受到 INIT_COPY 消息后,将要安装的参数信息加入到 PendingInstalls 中去,如果是第一个安装,发送 MCS_BOUND 消息触发实际安装过程。

                case MCS_BOUND: {
                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                    }
                    if (mContainerService == null) {
                        // Something seriously wrong. Bail out
                        Slog.e(TAG, "Cannot bind to media container service");
                        for (HandlerParams params : mPendingInstalls) {
                            // Indicate service bind error
                            params.serviceError();
                        }
                        mPendingInstalls.clear();
                    } else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            if (params.startCopy()) {
                                // We are done...  look for more work or to
                                // go idle.
                                if (DEBUG_SD_INSTALL) Log.i(TAG,
                                        "Checking for more work or unbind...");
                                // Delete pending install
                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) {
                                    if (mBound) {
                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
                                                "Posting delayed MCS_UNBIND");
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                        // Unbind after a little delay, to avoid
                                        // continual thrashing.
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {
                                    // There are more pending requests in queue.
                                    // Just post MCS_BOUND message to trigger processing
                                    // of next pending install.
                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
                                            "Posting MCS_BOUND for next woek");
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }

上面函数取出第一个安装请求,并调用 startCopy 方法。

        final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

                if (++mRetries > MAX_RETRIES) {
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            handleReturnCode();
            return res;
        }

在 startCopy 中调用 handleStartCopy 方法,handleReturnCode方法
handleStartCopy的核心就是copyApk,其他的都是些存储空间检查,权限检查等等安全校验。

        void handleStartCopy() throws RemoteException {
            synchronized (mInstallLock) {
                mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
            }

            final boolean mounted;
            if (Environment.isExternalStorageEmulated()) {
                mounted = true;
            } else {
                final String status = Environment.getExternalStorageState();
                mounted = (Environment.MEDIA_MOUNTED.equals(status)
                        || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
            }

            if (mounted) {
                final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);

                mStats.externalCacheSize = calculateDirectorySize(mContainerService,
                        userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));

                mStats.externalDataSize = calculateDirectorySize(mContainerService,
                        userEnv.buildExternalStorageAppDataDirs(mStats.packageName));

                // Always subtract cache size, since it's a subdirectory
                mStats.externalDataSize -= mStats.externalCacheSize;

                mStats.externalMediaSize = calculateDirectorySize(mContainerService,
                        userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));

                mStats.externalObbSize = calculateDirectorySize(mContainerService,
                        userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
            }
        }

handleReturnCode函数调用processPendingInstall方法,

 private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                 // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.returnCode = currentStatus;
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = new PackageRemovedInfo();
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageLI(args, true, res);
                    }
                    args.doPostInstall(res.returnCode, res.uid);
                }

                // A restore should be performed at this point if (a) the install
                // succeeded, (b) the operation is not an update, and (c) the new
                // package has a backupAgent defined.
                final boolean update = res.removedInfo.removedPackage != null;
                boolean doRestore = (!update
                        && res.pkg != null
                        && res.pkg.applicationInfo.backupAgentName != null);

                // Set up the post-install work request bookkeeping.  This will be used
                // and cleaned up by the post-install event handling regardless of whether
                // there's a restore pass performed.  Token values are >= 1.
                int token;
                if (mNextInstallToken < 0) mNextInstallToken = 1;
                token = mNextInstallToken++;

                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);

                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
                    // Pass responsibility to the Backup Manager.  It will perform a
                    // restore if appropriate, then pass responsibility back to the
                    // Package Manager to run the post-install observer callbacks
                    // and broadcasts.
                    IBackupManager bm = IBackupManager.Stub.asInterface(
                            ServiceManager.getService(Context.BACKUP_SERVICE));
                    if (bm != null) {
                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                + " to BM for possible restore");
                        try {
                            bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                        } catch (RemoteException e) {
                            // can't happen; the backup manager is local
                        } catch (Exception e) {
                            Slog.e(TAG, "Exception trying to enqueue restore", e);
                            doRestore = false;
                        }
                    } else {
                        Slog.e(TAG, "Backup Manager not found!");
                        doRestore = false;
                    }
                }

                if (!doRestore) {
                    // No restore possible, or the Backup Manager was mysteriously not
                    // available -- just fire the post-install work request directly.
                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                    mHandler.sendMessage(msg);
                }
            }
        });
    }

上面的代码最终会通过installPackageLI完成对应用的安装。

        private void installPackageLI(InstallArgs args,
            boolean newInstall, PackageInstalledInfo res) {
            ........//此处省略n行
            	 if (replace) {
                 	 replacePackageLI(pkg, parseFlags, scanMode, args.user,
                     installerPackageName, res);
                 } else {
                     installNewPackageLI(pkg, parseFlags, scanMode, args.user,
                     installerPackageName, res);
                }
         }

这个方法先是解析了package包,然后做了大量签名和权限校验的工作,最终走到判断是安装新的apk还是覆盖安装的判断语句上。

private void installNewPackageLI(PackageParser.Package pkg,
            int parseFlags, int scanMode, UserHandle user,
            String installerPackageName, PackageInstalledInfo res) {
        // Remember this for later, in case we need to rollback this install
        String pkgName = pkg.packageName;

        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
        boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
        synchronized(mPackages) {
            if (mSettings.mRenamedPackages.containsKey(pkgName)) {
                // A package with the same name is already installed, though
                // it has been renamed to an older name.  The package we
                // are trying to install should be installed as an update to
                // the existing one, but that has not been requested, so bail.
                Slog.w(TAG, "Attempt to re-install " + pkgName
                        + " without first uninstalling package running as "
                        + mSettings.mRenamedPackages.get(pkgName));
                res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                return;
            }
            if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
                // Don't allow installation over an existing package with the same name.
                Slog.w(TAG, "Attempt to re-install " + pkgName
                        + " without first uninstalling.");
                res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                return;
            }
        }
        mLastScanError = PackageManager.INSTALL_SUCCEEDED;
        PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
                System.currentTimeMillis(), user);
        if (newPackage == null) {
            Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
            if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
            }
        } else {
            updateSettingsLI(newPackage,
                    installerPackageName,
                    null, null,
                    res);
            // delete the partially installed application. the data directory will have to be
            // restored if it was already existing
            if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                // remove package from internal structures.  Note that we want deletePackageX to
                // delete the package data and cache directories that it created in
                // scanPackageLocked, unless those directories existed before we even tried to
                // install.
                deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
                        dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
                                res.removedInfo, true);
            }
        }
    }

可以看到最终还是一样会走到scanPackageLI中进行安装,剩下的就不再此赘述。

5.3 adb安装

安装应用还可以使用adb命令安装,例如:adb install packagePath
原理:
system\core\adb\commandline.c
adb_commandline函数:

    if(!strcmp(argv[0], "install")) {
        if (argc < 2) return usage();
        return install_app(ttype, serial, argc, argv);
    }

找到这个位置,跳到install_app函数,它又会走下面这行代码:

pm_command(transport, serial, argc, argv);

我们找到pm_command函数的实现:

static int pm_command(transport_type transport, char* serial,
                      int argc, char** argv)
{
    char buf[4096];

    snprintf(buf, sizeof(buf), "shell:pm");

    while(argc-- > 0) {
        char *quoted;

        quoted = dupAndQuote(*argv++);

        strncat(buf, " ", sizeof(buf)-1);
        strncat(buf, quoted, sizeof(buf)-1);
        free(quoted);
    }

    send_shellcommand(transport, serial, buf);
    return 0;
}

上面代码关键点是send_shellcommand函数,并且此时buf为“shell:pm install ***”,send_shellcommand它的实现是:

static int send_shellcommand(transport_type transport, char* serial, char* buf)
{
    int fd, ret;

    for(;;) {
        fd = adb_connect(buf);
        if(fd >= 0)
            break;
        fprintf(stderr,"- waiting for device -\n");
        adb_sleep_ms(1000);
        do_cmd(transport, serial, "wait-for-device", 0);
    }

    read_and_dump(fd);
    ret = adb_close(fd);
    if (ret)
        perror("close");

    return ret;
}

上面代码可以看出,他的作用是连接shell服务,没连上的话就重新再来一次
连接过程其实就是连接Pm.java的main函数,因为这个会被打成一个jar包,可以通过命令pm ***来带参执行,此时参数为install
那么我们看一下Pm.java的main函数:

    public static void main(String[] args) {
        new Pm().run(args);
    }

再往下:

    public void run(String[] args) {
      .....此处省略n行代码
        mArgs = args;
        String op = args[0];
        mNextArg = 1;
        if ("install".equals(op)) {
            runInstall();
            return;
        }
    }

然后再看runInstall这个函数:

    private void runInstall() {
    .......//此处省略n行代码
            PackageInstallObserver obs = new PackageInstallObserver();
        try {
            VerificationParams verificationParams = new VerificationParams(verificationURI,
                    originatingURI, referrerURI, VerificationParams.NO_UID, null);

            mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
                    installerPackageName, verificationParams, encryptionParams);

            synchronized (obs) {
                while (!obs.finished) {
                    try {
                        obs.wait();
                    } catch (InterruptedException e) {
                    }
                }
                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
                    System.out.println("Success");
                } else {
                    System.err.println("Failure ["
                            + installFailureToString(obs.result)
                            + "]");
                }
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
        }
      }

可以看到最终是通过aidl调用到PAMS的installPackageWithVerificationAndEncryption函数,剩下过程就跟5.2安装过程一样了。

6. 卸载过程

PAMS除了安装,另一个重要功能就是卸载应用,下面跟一下,卸载的过程。
首先我们从deletePackageAsUser函数开始跟踪:

public void deletePackageAsUser(final String packageName,
                                    final IPackageDeleteObserver observer,
                                    final int userId, final int flags) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.DELETE_PACKAGES, null);
        final int uid = Binder.getCallingUid();
        if (UserHandle.getUserId(uid) != userId) {
            mContext.enforceCallingPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                    "deletePackage for user " + userId);
        }
        if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
            try {
                observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
            } catch (RemoteException re) {
            }
            return;
        }

        if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
        // Queue up an async operation since the package deletion may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                final int returnCode = deletePackageX(packageName, userId, flags); //7
                if (observer != null) {
                    try {
                        observer.packageDeleted(packageName, returnCode);//8
                    } catch (RemoteException e) {
                        Log.i(TAG, "Observer no longer exists.");
                    } //end catch
                } //end if
            } //end run
        });
    }

上面的代码需要关注的是注释7的代码,他调用了deletePackageX函数做卸载操作,根据名字可知他是删除应用包的功能,还有就是注释8那里会有注册一个观察者,当卸载完成的时候会通知它。
继续往下的看:

    private int deletePackageX(String packageName, int userId, int flags) {
        final PackageRemovedInfo info = new PackageRemovedInfo();
        final boolean res;

        if (isPackageDeviceAdmin(packageName, userId)) {
            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
            return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
        }

        boolean removedForAllUsers = false;
        boolean systemUpdate = false;

        // for the uninstall-updates case and restricted profiles, remember the per-
        // userhandle installed state
        int[] allUsers;
        boolean[] perUserInstalled;
        synchronized (mPackages) {
            PackageSetting ps = mSettings.mPackages.get(packageName);
            allUsers = sUserManager.getUserIds();
            perUserInstalled = new boolean[allUsers.length];
            for (int i = 0; i < allUsers.length; i++) {
                perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
            }
        }

        synchronized (mInstallLock) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
            res = deletePackageLI(packageName,                 //9
                    (flags & PackageManager.DELETE_ALL_USERS) != 0
                            ? UserHandle.ALL : new UserHandle(userId),
                    true, allUsers, perUserInstalled,
                    flags | REMOVE_CHATTY, info, true);
            systemUpdate = info.isRemovedPackageSystemUpdate;
            if (res && !systemUpdate && mPackages.get(packageName) == null) {
                removedForAllUsers = true;
            }
            if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
                    + " removedForAllUsers=" + removedForAllUsers);
        }

        if (res) {
            info.sendBroadcast(true, systemUpdate, removedForAllUsers);

            // If the removed package was a system update, the old system package
            // was re-enabled; we need to broadcast this information
            if (systemUpdate) {
                Bundle extras = new Bundle(1);
                extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
                        ? info.removedAppId : info.uid);
                extras.putBoolean(Intent.EXTRA_REPLACING, true);

                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
                        null, packageName, null, null);
            }
        }
        // Force a gc here.
        Runtime.getRuntime().gc();
        // Delete the resources here after sending the broadcast to let
        // other processes clean up before deleting resources.
        if (info.args != null) {
            synchronized (mInstallLock) {
                info.args.doPostDeleteLI(true);
            }
        }

        return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
    }

上面的代码看关键的注释9所标注的函数deletePackageLI,跟踪这个函数的实现:

    private boolean deletePackageLI(String packageName, UserHandle user,
            boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
            int flags, PackageRemovedInfo outInfo,
            boolean writeSettings) {
        if (packageName == null) {
            Slog.w(TAG, "Attempt to delete null packageName.");
            return false;
        }
        if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
        PackageSetting ps;
        boolean dataOnly = false;
        int removeUser = -1;
        int appId = -1;
        synchronized (mPackages) {
            ps = mSettings.mPackages.get(packageName);
            if (ps == null) {
                Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                return false;
            }
            if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
                    && user.getIdentifier() != UserHandle.USER_ALL) {
                // The caller is asking that the package only be deleted for a single
                // user.  To do this, we just mark its uninstalled state and delete
                // its data.  If this is a system app, we only allow this to happen if
                // they have set the special DELETE_SYSTEM_APP which requests different
                // semantics than normal for uninstalling system apps.
                if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user");
                ps.setUserState(user.getIdentifier(),
                        COMPONENT_ENABLED_STATE_DEFAULT,
                        false, //installed
                        true,  //stopped
                        true,  //notLaunched
                        false, //blocked
                        null, null, null);
                if (!isSystemApp(ps)) {
                    if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                        // Other user still have this package installed, so all
                        // we need to do is clear this user's data and save that
                        // it is uninstalled.
                        if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
                        removeUser = user.getIdentifier();
                        appId = ps.appId;
                        mSettings.writePackageRestrictionsLPr(removeUser);
                    } else {
                        // We need to set it back to 'installed' so the uninstall
                        // broadcasts will be sent correctly.
                        if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
                        ps.setInstalled(true, user.getIdentifier());
                    }
                } else {
                    // This is a system app, so we assume that the
                    // other users still have this package installed, so all
                    // we need to do is clear this user's data and save that
                    // it is uninstalled.
                    if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
                    removeUser = user.getIdentifier();
                    appId = ps.appId;
                    mSettings.writePackageRestrictionsLPr(removeUser);
                }
            }
        }

        if (removeUser >= 0) {
            // From above, we determined that we are deleting this only
            // for a single user.  Continue the work here.
            if (DEBUG_REMOVE) Slog.d(TAG, "Updating install state for user: " + removeUser);
            if (outInfo != null) {
                outInfo.removedPackage = packageName;
                outInfo.removedAppId = appId;
                outInfo.removedUsers = new int[] {removeUser};
            }
            mInstaller.clearUserData(packageName, removeUser);
            removeKeystoreDataIfNeeded(removeUser, appId);
            schedulePackageCleaning(packageName, removeUser, false);
            return true;
        }

        if (dataOnly) {
            // Delete application data first
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
            removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
            return true;
        }

        boolean ret = false;
        mSettings.mKeySetManager.removeAppKeySetData(packageName);
        if (isSystemApp(ps)) {
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
            // When an updated system application is deleted we delete the existing resources as well and
            // fall back to existing code in system partition
            ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,   //10
                    flags, outInfo, writeSettings);
        } else {
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
            // Kill application pre-emptively especially for apps on sd.
            killApplication(packageName, ps.appId, "uninstall pkg");
            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
                    allUserHandles, perUserInstalled,
                    outInfo, writeSettings);
        }

        return ret;
    }

再然后卸载系统app会跳到deleteSystemPackageLI函数,普通app会走下面的deleteInstalledPackageLI函数,那我讲一下普通app卸载的过程:

    private boolean deleteInstalledPackageLI(PackageSetting ps,
            boolean deleteCodeAndResources, int flags,
            int[] allUserHandles, boolean[] perUserInstalled,
            PackageRemovedInfo outInfo, boolean writeSettings) {
        if (outInfo != null) {
            outInfo.uid = ps.appId;
        }

        // Delete package data from internal structures and also remove data if flag is set
        removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings);  //11

        // Delete application code and resources
        if (deleteCodeAndResources && (outInfo != null)) {
            outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
                    ps.resourcePathString, ps.nativeLibraryPathString);
        }
        return true;
    }

好的,继续看上面注释11的函数实现:

    private void removePackageDataLI(PackageSetting ps,
            int[] allUserHandles, boolean[] perUserInstalled,
            PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
        String packageName = ps.name;
        if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
        removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);   //12
        // Retrieve object to delete permissions for shared user later on
        final PackageSetting deletedPs;
        // reader
        synchronized (mPackages) {
            deletedPs = mSettings.mPackages.get(packageName);
            if (outInfo != null) {
                outInfo.removedPackage = packageName;
                outInfo.removedUsers = deletedPs != null
                        ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
                        : null;
            }
        }
        if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
            removeDataDirsLI(packageName);     //13
            schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
        }
        // writer
        synchronized (mPackages) {
            if (deletedPs != null) {
                if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
                    if (outInfo != null) {
                        outInfo.removedAppId = mSettings.removePackageLPw(packageName);
                    }
                    if (deletedPs != null) {
                        updatePermissionsLPw(deletedPs.name, null, 0);
                        if (deletedPs.sharedUser != null) {
                            // remove permissions associated with package
                            mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
                        }
                    }
                    clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
                }
                // make sure to preserve per-user disabled state if this removal was just
                // a downgrade of a system app to the factory package
                if (allUserHandles != null && perUserInstalled != null) {
                    if (DEBUG_REMOVE) {
                        Slog.d(TAG, "Propagating install state across downgrade");
                    }
                    for (int i = 0; i < allUserHandles.length; i++) {
                        if (DEBUG_REMOVE) {
                            Slog.d(TAG, "    user " + allUserHandles[i]
                                    + " => " + perUserInstalled[i]);
                        }
                        ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
                    }
                }
            }
            // can downgrade to reader
            if (writeSettings) {
                // Save settings now
                mSettings.writeLPr();
            }
        }
        if (outInfo != null) {
            // A user ID was deleted here. Go through all users and remove it
            // from KeyStore.
            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
        }
    }

在注释12的函数是删除组件信息,注释13函数继续往下是删除data/data下与包名相对应的目录。

先看注释12:在mPackages总安装应用列表中删除对应实例,清除所有应用组件,如activity, provider, service, contentresolver, receiver等结构

    void removePackageLI(PackageSetting ps, boolean chatty) {
        if (DEBUG_INSTALL) {
            if (chatty)
                Log.d(TAG, "Removing package " + ps.name);
        }

        // writer
        synchronized (mPackages) {
            mPackages.remove(ps.name);
            if (ps.codePathString != null) {
                mAppDirs.remove(ps.codePathString);
            }

            final PackageParser.Package pkg = ps.pkg;
            if (pkg != null) {
                cleanPackageDataStructuresLILPw(pkg, chatty);
            }
        }
    }

注释13的话,内容会比多,休息一下继续吧,哈哈
在这里插入图片描述
好了,意思意思继续了,哈哈哈~
removeDataDirsLI函数实现如下:

    private int removeDataDirsLI(String packageName) {
        int[] users = sUserManager.getUserIds();
        int res = 0;
        for (int user : users) {
            int resInner = mInstaller.remove(packageName, user);   //14
            if (resInner < 0) {
                res = resInner;
            }
        }

        final File nativeLibraryFile = new File(mAppLibInstallDir, packageName);
        NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
        if (!nativeLibraryFile.delete()) {
            Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath());
        }

        return res;
    }

注释14可以看到他调用了Installer类的remove函数:

    public int remove(String name, int userId) {
        StringBuilder builder = new StringBuilder("remove");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

上面代码是将包名与用户id拼接在一起,然后调用execute,通过socket发送给natvie层的installd服务处理:

    private int execute(String cmd) {
        String res = transaction(cmd);
        try {
            return Integer.parseInt(res);
        } catch (NumberFormatException ex) {
            return -1;
        }
    }
private String transaction(String cmd){
    optimize = SystemProperties.getBoolean("persist.sys.boot.optimize", false);
    if(optimize){
        return transaction_Optimize(cmd);
    }else{
        return transaction_Orig(cmd);
    }
}
    private String transaction_Optimize(String cmd) {
        int transactionId;
        synchronized (mTransactionIdLock) {
            transactionId = mLastTransactionId++;
            if (mLastTransactionId < 0) {
                mLastTransactionId = 0;
            }
        }

        try {
            synchronized (mResponses) {
                long startWaitTime = System.nanoTime();
                while(mResponses.get(transactionId) == null) {
                    synchronized (mPendingRequests) {
                        if (!mPendingRequests.contains(transactionId)) {
                            if (!connect()) {
                                Slog.e(TAG, "connection failed");
                                return "-1";
                            }

                            if (!writeCommand(cmd, transactionId)) {
                                /*
                                 * If installd died and restarted in the background (unlikely but
                                 * possible) we'll fail on the next write (this one). Try to
                                 * reconnect and write the command one more time before giving up.
                                 */
                                Slog.e(TAG, "write command failed? reconnect!");
                                if (!connect() || !writeCommand(cmd, transactionId)) {
                                    return "-1";
                                }
                            }
                            if (LOCAL_DEBUG) {
                                Slog.i(TAG, "send ["+transactionId+"]: '" + cmd + "'");
                            }
                            mPendingRequests.add(transactionId);
                            checkPoller();
                        }
                    }
                    final long timeToWait = startWaitTime - System.nanoTime() + *****;
                    if (timeToWait > 0) {
                        mResponses.wait(100000);
                    } else {
                        Slog.e(TAG, "timeout wating for response");
                        break;
                    }
                }
            }
        } catch (InterruptedException e) {
            return "-1";
        }

        synchronized (mPendingRequests) {
            mPendingRequests.remove(new Integer(transactionId));
        }
        checkPoller();

        String s;
        synchronized (mResponses) {
            s = mResponses.get(transactionId);
            mResponses.remove(transactionId);
        }
        if (LOCAL_DEBUG) {
            Slog.i(TAG, "recv: ["+transactionId+"]'" + s + "'");
        }
        return s == null ? "-1" : s;
    }

好的,我们到native服务看一下:

int main(const int argc, const char *argv[]) {
    char buf[BUFFER_MAX];
    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s, count;

    char value[PROPERTY_VALUE_MAX];
    property_get("persist.sys.boot.optimize", value, "false");
    pthread_t worker_threads, signal_thread;
    pthread_attr_t pthread_custom_attr;
    sigset_t sigs_to_block;

    if(0 == strcmp(value, "true")){
        pthread_mutex_init(&io_mutex, NULL);
        pthread_cond_init(&io_wait, NULL);
        pthread_attr_init(&pthread_custom_attr);
        sigemptyset(&sigs_to_block);
        sigaddset(&sigs_to_block, SIGIO);
        pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
        pthread_create(&signal_thread, &pthread_custom_attr, io_signal_handler, NULL);
    }
    ALOGI("installd firing up\n");

    if (initialize_globals() < 0) {
        ALOGE("Could not initialize globals; exiting.\n");
        exit(1);
    }

    if (initialize_directories() < 0) {
        ALOGE("Could not create directories; exiting.\n");
        exit(1);
    }

    drop_privileges();

    lsocket = android_get_control_socket(SOCKET_PATH);
    if (lsocket < 0) {
        ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
        exit(1);
    }
    if (listen(lsocket, 5)) {
        ALOGE("Listen on socket failed: %s\n", strerror(errno));
        exit(1);
    }
    fcntl(lsocket, F_SETFD, FD_CLOEXEC);

    for (;;) {
        alen = sizeof(addr);
        s = accept(lsocket, &addr, &alen);
        if (s < 0) {
            ALOGE("Accept failed: %s\n", strerror(errno));
            continue;
        }
        fcntl(s, F_SETFD, FD_CLOEXEC);
        if(0 == strcmp(value, "true")){
            fcntl(s, F_SETFL, O_ASYNC | O_NONBLOCK);
            fcntl(s, F_SETSIG, 0);
            fcntl(s, F_SETOWN, getpid());
            write_error = 0;
        }
        ALOGI("new connection\n");
        int id;
        for (;;) {
            unsigned short count;
            if(0 == strcmp(value, "true")){
                if (readx(s, &id, sizeof(id))) {
                    ALOGE("failed to read transaction id\n");
                    break;
                }
            }
            if (readx(s, &count, sizeof(count))) {
                ALOGE("failed to read size\n");
                break;
            }
            if ((count < 1) || (count >= BUFFER_MAX)) {
                ALOGE("invalid size %d\n", count);
                break;
            }
            if (readx(s, buf, count)) {
                ALOGE("failed to read command\n");
                break;
            }
            buf[count] = 0;
            if(0 == strcmp(value, "true")){
                thread_parm *args = (thread_parm*) malloc(sizeof(thread_parm));
                args->s = s;
                strncpy(args->cmd, buf, count + 1);
                args->id = id;
                pthread_create(&worker_threads, &pthread_custom_attr, executeAsync, (void*) args);
            }else{
                if (execute(s, buf,id)) break;   //15
            }
        }
        ALOGI("closing connection\n");
        close(s);
    }
    if(0 == strcmp(value, "true")){
        pthread_kill(&signal_thread, SIGKILL);
        pthread_join(&signal_thread, NULL);
    }
    return 0;
}

installd.c的main函数实现如上所示,其他不用多解释了,比较好看懂,直接到注释15吧,核心execute函数,处理socket收到的数据:

static int execute(int s, char cmd[BUFFER_MAX], int id)
{
    char reply[REPLY_MAX];
    char *arg[TOKEN_MAX+1];
    unsigned i;
    unsigned n = 0;
    unsigned short count;
    int ret = -1;
    char buf[16] = "";

    char value[PROPERTY_VALUE_MAX];
    property_get("persist.sys.boot.optimize", value, "false");

    // ALOGI("execute('%s')\n", cmd);

        /* default reply is "" */
    reply[0] = 0;

        /* n is number of args (not counting arg[0]) */
    arg[0] = cmd;
    while (*cmd) {
        if (isspace(*cmd)) {
            *cmd++ = 0;
            n++;
            arg[n] = cmd;
            if (n == TOKEN_MAX) {
                ALOGE("too many arguments\n");
                goto done;
            }
        }
        cmd++;
    }

    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
        if (!strcmp(cmds[i].name,arg[0])) {
            if (n != cmds[i].numargs) {
                ALOGE("%s requires %d arguments (%d given)\n",
                     cmds[i].name, cmds[i].numargs, n);
            } else {
                ret = cmds[i].func(arg + 1, reply);   //16
            }
            goto done;
        }
    }
    ALOGE("unsupported command '%s'\n", arg[0]);

done:
    if (reply[0]) {
        n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
    } else {
        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
    }
    if (n > BUFFER_MAX) n = BUFFER_MAX;
    count = n;

    // ALOGI("reply [%d]: '%s'\n", id, cmd);
    if(0 == strcmp(value, "true")){
        pthread_mutex_lock(&io_mutex);
        if (write_error) {
            goto exec_error;
        }
        memcpy(buf, &id, sizeof(id));
        memcpy(buf+sizeof(id), &count, sizeof(count));
        if (writex(s, buf, sizeof(id)+sizeof(count))) {
            write_error = 1;
            goto exec_error;
        }
        if (writex(s, cmd, count)) {
            write_error = 1;
            goto exec_error;
        }
        pthread_mutex_unlock(&io_mutex);
        return 0;

    exec_error:
        pthread_cond_broadcast(&io_wait);
        pthread_mutex_unlock(&io_mutex);
        return -1;
    }else{
        if (writex(s, &count, sizeof(count))) return -1;
        if (writex(s, cmd, count)) return -1;
        return 0;
    }
}

先看一下这个结构体:

struct cmdinfo cmds[] = {
    { "ping",                 0, do_ping },
    { "install",              4, do_install },
    { "dexopt",               3, do_dexopt },
    { "movedex",              2, do_move_dex },
    { "rmdex",                1, do_rm_dex },
    { "remove",               2, do_remove },
    { "rename",               2, do_rename },
    { "fixuid",               3, do_fixuid },
    { "freecache",            1, do_free_cache },
    { "rmcache",              2, do_rm_cache },
    { "getsize",              6, do_get_size },
    { "rmuserdata",           2, do_rm_user_data },
    { "movefiles",            0, do_movefiles },
    { "linklib",              3, do_linklib },
    { "mkuserdata",           3, do_mk_user_data },
    { "rmuser",               1, do_rm_user },
    { "backupdata",           3,  do_backupdata},
    { "restoredata",           3,  do_restoredata},
};

所以注释16调用do_remove 函数,好的,继续看do_remove 函数实现:

static int do_remove(char **arg, char reply[REPLY_MAX])
{
	ALOGE("has do_remove");

    return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */
}

上面函数就做了调用uninstall函数,那么继续:

int uninstall(const char *pkgname, userid_t userid)
{
    char pkgdir[PKG_PATH_MAX];

    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))     //17
        return -1;
    /* delete contents AND directory, no exceptions */
    return delete_dir_contents(pkgdir, 1, NULL);    //18
}

注释17最后拼接了一个data/data/packagename的路径变量pkgdir,给到了注释18的函数,delete_dir_contents函数的实现:

int delete_dir_contents(const char *pathname,
                        int also_delete_dir,
                        const char *ignore)
{
    int res = 0;
    DIR *d;

    d = opendir(pathname);
    if (d == NULL) {
        ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
        return -errno;
    }
    res = _delete_dir_contents(d, ignore);
    closedir(d);
    if (also_delete_dir) {
        if (rmdir(pathname)) {
            ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
            res = -1;
        }
    }
    return res;
}

上面函数实现大概意思就是打开那个路径,然后递归查找删除里面所有的内容,完成卸载操作重要的一步,为什么说是重要的一步,因为卸载不仅仅是要删除package的组件信息和删除data/data下安装包的数据文件,还有一个就是删除应用的dex文件。
上面我没有提到,那我们回过头去找一下是在哪里做的:

    private int deletePackageX(String packageName, int userId, int flags) {
        final PackageRemovedInfo info = new PackageRemovedInfo();
        final boolean res;

        if (isPackageDeviceAdmin(packageName, userId)) {
            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
            return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
        }

        boolean removedForAllUsers = false;
        boolean systemUpdate = false;

        // for the uninstall-updates case and restricted profiles, remember the per-
        // userhandle installed state
        int[] allUsers;
        boolean[] perUserInstalled;
        synchronized (mPackages) {
            PackageSetting ps = mSettings.mPackages.get(packageName);
            allUsers = sUserManager.getUserIds();
            perUserInstalled = new boolean[allUsers.length];
            for (int i = 0; i < allUsers.length; i++) {
                perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
            }
        }

        synchronized (mInstallLock) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
            res = deletePackageLI(packageName,               
                    (flags & PackageManager.DELETE_ALL_USERS) != 0
                            ? UserHandle.ALL : new UserHandle(userId),
                    true, allUsers, perUserInstalled,
                    flags | REMOVE_CHATTY, info, true);
            systemUpdate = info.isRemovedPackageSystemUpdate;
            if (res && !systemUpdate && mPackages.get(packageName) == null) {
                removedForAllUsers = true;
            }
            if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
                    + " removedForAllUsers=" + removedForAllUsers);
        }

        if (res) {
            info.sendBroadcast(true, systemUpdate, removedForAllUsers);

            // If the removed package was a system update, the old system package
            // was re-enabled; we need to broadcast this information
            if (systemUpdate) {
                Bundle extras = new Bundle(1);
                extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
                        ? info.removedAppId : info.uid);
                extras.putBoolean(Intent.EXTRA_REPLACING, true);

                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
                        extras, null, null, null);
                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
                        null, packageName, null, null);
            }
        }
        // Force a gc here.
        Runtime.getRuntime().gc();
        // Delete the resources here after sending the broadcast to let
        // other processes clean up before deleting resources.
        if (info.args != null) {
            synchronized (mInstallLock) {
                info.args.doPostDeleteLI(true);    //18
            }
        }

        return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
    }

我们接着deletePackageX函数那里开始,注释18那行代码就是删除dex文件的关键函数,我们可以跟踪一下删除dex文件流程:

        boolean doPostDeleteLI(boolean delete) {
            // XXX err, shouldn't we respect the delete flag?
            cleanUpResourcesLI();
            return true;
        }

下面会有一些列的函数跳转:

        void cleanUpResourcesLI() {
            String sourceDir = getCodePath();
            if (cleanUp()) {
                int retCode = mInstaller.rmdex(sourceDir);
                if (retCode < 0) {
                    Slog.w(TAG, "Couldn't remove dex file for package: "
                            +  " at location "
                            + sourceDir + ", retcode=" + retCode);
                    // we don't consider this to be a failure of the core package deletion
                }
            }
        }

这里是不是似曾相识的味道,没错,经过类似的操作,最终会调到native installd服务的do_rm_dex函数:

static int do_rm_dex(char **arg, char reply[REPLY_MAX])
{
	ALOGE("has do_rm_dex");

    return rm_dex(arg[0]); /* pkgname */
}

再然后拼接了dex文件的路径,然后删除了这个dex文件,完事儿了。

int rm_dex(const char *path)
{
    char dex_path[PKG_PATH_MAX];

    if (validate_apk_path(path)) return -1;
    if (create_cache_path(dex_path, path)) return -1;

    ALOGV("unlink %s\n", dex_path);
    if (unlink(dex_path) < 0) {
        ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
        return -1;
    } else {
        return 0;
    }
}

总结一下,卸载过程总的来说是删除了应用的组件信息。data/data下的数据文件,以及data/dalvik-cache下的dex文件。

7. 总结

大体过程说一下,就是PAMS先解析apk,然后呢,再通过socket连接installed服务,进行安装与卸载操作。写的不够详细后面再重新组织补充语言。

发布了70 篇原创文章 · 获赞 24 · 访问量 8242

猜你喜欢

转载自blog.csdn.net/angelsmiling/article/details/98030565