Android apk安装过程分析

一、何谓apk成功安装到系统

1.1、一个apk怎样才可以称作成功安装到了Android系统?

可以类比一下新生儿。一个刚出生的孩子怎么样才能算是一个完整的社会人呢?

婴儿刚从母亲体内分娩出来,他实际还不能称为一个"社会人",他需要向户籍管理单位进行注册,添加户口页,分配社保ID,完成一些列注册手续之后,才能称为一个完全意义上的“社会人”,并且可以享受国家社会的相关福利。

apk的安装也是类似的,不仅仅需要将apk的实体放到系统的特定目录(/data/app/),而且需要向PackageManagerService注册包名、以及apk声明的四大组件(Activity、Service、ContentProvider、BroadcastReceiver),该apk才能算是成功安装到了Android系统。

大概可分为两个方面:

  • 1、安装apk到特定的目录
  • 2、注册包名、四大组件到PackageManagerService

只有完成了第2步(向系统注册),Android系统才知道有这么一个apk存在,才可以管理(或者说启动)该apk

1.2、apk安装相关的目录

apk安装目录:

  • 1、 /system/app: 系统自带的应用程序,获得adb root权限才能删除
  • 2、 /data/app :用户程序安装的目录。安装时把apk文件复制到此目录

dex、odex保存目录:

  • 3、/data/dalvik-cache:将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,当然,ART–Android Runtime的可执行文件格式为oat,启用ART时,系统会执行dex文件转换至oat文件)

用户数据目录:

  • 4、/data/data :存放应用程序的数据,无论是系统app还是普通app,app产生的用户数据都存放在/data/data/包名/目录下。

packages.xml注册表目录

  • 5、/data/system :该目录下的packages.xml文件,类似于Windows的注册表。这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。

二、PackageManagerService概述

2.1、PackageManagerService 有三大职责

PackageManagerService 是Android系统中所有包的大管家,其最简化的类结构如下:

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender{

    //保存所有已安装的apckage信息
    final Settings mSettings;

    //保存 包名-Package的键值对
    final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();

     //保存所有已安装包中注册的Activity信息
    // All available activities, for your resolving pleasure.
    final ActivityIntentResolver mActivities =
            new ActivityIntentResolver();
    //保存所有已安装apk中注册的Receiver信息
    // All available receivers, for your resolving pleasure.
    final ActivityIntentResolver mReceivers =
            new ActivityIntentResolver();

    //保存所有已安装apk中注册的Service信息
    // All available services, for your resolving pleasure.
    final ServiceIntentResolver mServices = new ServiceIntentResolver();

    //保存所有已安装apk中注册ContentProvider信息
    // All available providers, for your resolving pleasure.
    final ProviderIntentResolver mProviders = new ProviderIntentResolver();
    
    //安装一个apk
    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

    }

 }


PackageManagerService 有三大职责:

(1)开机扫描过程

开机后,加载/data/system/packages.xml文件,然后扫描特定安装目录:/system/app、/system/priv-app、/system/vendor/app、/data/app
解析里面的apk文件,将静态信息提取到PackageManagerService中的主要数据结构中。

(2)安装apk

将一个新的apk 安装到Android系统当中

(3)解析Intent

解析Intent意图,通过Intent获取到目的Activity、Provider、BroadCastReceiver 或Service。

2.2、Settings

上文提到 /data/system/package.xml 记录所有已安装的包信息,package.xml的内容如下:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
     <permission-trees />
     <permissions>
        <item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />
        <item name="android.permission.ACCESS_CACHE_FILESYSTEM" package="android" protection="18" />
        <item name="android.permission.REMOTE_AUDIO_PLAYBACK" package="android" protection="2" />
        <item name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" package="com.android.providers.downloads" />
        <item name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" package="android" protection="2" />
        <item name="android.permission.INTENT_FILTER_VERIFICATION_AGENT" package="android" protection="18" />
        <item name="android.permission.BIND_INCALL_SERVICE" package="android" protection="18" />
        <item name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" package="android" protection="18" />
        <item name="android.permission.WRITE_SETTINGS" package="android" protection="1218" />
        <item name="sprd.permission.USE_FACE" package="android" />
        </permissions>

      <package name="com.sogou.iot.w3" codePath="/data/app/com.sogou.iot.w3-5DPtBZkfj2SzwPwTxissow==" nativeLibraryPath="/data/app/com.sogou.iot.w3-5DPtBZkfj2SzwPwTxissow==/lib" primaryCpuAbi="arm64-v8a" publicFlags="944291398" privateFlags="0" ft="176ff6c7290" it="176f63b830d" ut="176ff6c75f6" version="1" sharedUserId="1000">
            <sigs count="1">
                <cert index="0" key="308203e1308202c9a003020102020900d43b53a119e97dfa300d06092a864886f70d01010b0500308186310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310e300c060355040a0c05536f676f75310e300c060355040b0c05536f676f75310e300c06035504030c05536f676f753123302106092a864886f70d010" />
            </sigs>
            <perms>
                <item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />
                <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
                <item name="android.permission.CONFIGURE_WIFI_DISPLAY" granted="true" flags="0" />
                <item name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" granted="true" flags="0" />
            </perms>
        </package>

        ....
        省略若干个package 声明
 </packages>
(1)<package>记录了一个应用的基本信息,签名和声明的权限。
- name表示应用的包名
- codePath表示的是apk文件的路径
- nativeLibraryPath表示应用的native库的存储路径
- flags是指应用的属性,如FLAG_SYSTEM、FLAG_PERSISTENT等
- it表示应用安装的时间
- ut表示应用最后一次修改的时间
- version表示应用的版本号
- userId表示所属于的id
(2)<sign>表示应用的签名
- count表示标签中包含有多少个证书
- cert表示具体的证书的值
(3)<perms>表示应用声明使用的权限,每一个子标签代表一项权限

/data/system/package.xml,被PackageManagerService解析后会存储到mSettings 属性中。

 public final class Settings {
    /** Map from package name to settings */
    final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
 }

Settings中持有一个以package为键,以PackageSetting为值的ArrayMap,一个PackageSetting 就对应packages.xml中的一个package。

public final class PackageSetting extends PackageSettingBase {
    PackageParser.Package pkg;
    SharedUserSetting sharedUser;
    private int sharedUserId;
 }

PackageSetting 继承自PackageSettingBase。

  public final class PackageSetting extends PackageSettingBase {
    PackageParser.Package pkg;
    SharedUserSetting sharedUser;
    private int sharedUserId;
 }

2.3、mPackages

mPackages 维护了所有已安装apk的详细解析信息,包名为key,PackageParser.Package 为value

final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();

2.4、四大组件解析器

  • ActivityIntentResolver mActivities 持有所有注册的activity信息,用于通过intent解析成合理的Activity
final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {

        // Keys are String (activity class name), values are Activity.
        private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
                = new ArrayMap<ComponentName, PackageParser.Activity>();

       public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                int userId) {}

     }
  • ActivityIntentResolver mReceivers 用于解析BroadCastReceiver
  • ServiceIntentResolver mServices 维护所有注册的Service,用于通过Intent解成目标Service
  • ProviderIntentResolver mProviders 维护所有注册的ContentPrivider 用于将Intent解析成目标ContentProvider

三、apk安装具体安装过程:

3.1、apk安装的主要流程描述

本文主要阐述普通apk的安装流程,大概分为以下几个步骤:

image
  • (1) 拷贝apk文件到指定目录

在Android系统中,apk安装有固定的目录,默认情况下,用户安装的apk首先会被拷贝到 /data/app 目录下,同时会创建/data/app/pkg/lib目录,将apk中的so文件解压到此目录

/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件。而系统出厂的apk文件则被放到了 /system 分区下,包括:/system/app,/system/vendor/app,以及 /system/priv-app 等等,该分区只有Root权限的用户才能访问。这也就是为什么在没有Root手机之前,我们无法删除系统出厂的app的原因了。

  • (2) 扫描apk,解析AndroidManifest.xml文件,向PackagManagerService中注册该package、以及apk声明的四大组件。
  • (3)创建apk的用户数据目录,即/data/data/pkg/目录
/data/data/pkg为应用程序的数据目录(以应用的包名命名),存放应用的相关数据,如数据库、xml文件、cache
  • (4)为apk执行dexopt优化。
对于普通apk,dexopt优化后的文件保存在/data/app/oat目录
  • (5)安装完成发送ACTION_PACKAGE_ADDED广播。

3.2、apk安装代码分析

网络上有很多apk安装流程分析,但是版本都比较老了(Android 6.0左右),和最新的代码有些地方对不上,本文以Android 9.0 代码为基准,分析一下apk的安装流程:

PagkageManagerService的安装apk的入口是installStage

void installStage(String packageName, File stagedDir,
            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
            String installerPackageName, int installerUid, UserHandle user,
            PackageParser.SigningDetails signingDetails) {
   
        final VerificationInfo verificationInfo = new VerificationInfo(
                sessionParams.originatingUri, sessionParams.referrerUri,
                sessionParams.originatingUid, installerUid);

        final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);

       
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
                sessionParams.installReason);
        //(1)创建一个InstallParams对象,封装到INIT_COPY消息中
        final InstallParams params = new InstallParams(origin, null, observer,
                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                verificationInfo, user, sessionParams.abiOverride,
                sessionParams.grantedRuntimePermissions, signingDetails, installReason);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;
        //(2)发送INIT_COPY 消息
        mHandler.sendMessage(msg);
    }

installStage()方法主要目的是发送一个INIT_COPY Handler消息。

我们看下Handler的处理函数,比较重要的是INIT_COPY和MCS_BOUND 两个消息。

void doHandleMessage(Message msg) {
            switch (msg.what) {
               
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                  
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {
                    
                        //连接DefaultContainerService,它负责具体的copy操作
                        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;
                }
                case MCS_BOUND: {
              
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                    
                    }
                    if (mContainerService == null) {
                       //... 省略不重要的代码
                    } else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            
                            //(2)执行copy操作
                            if (params.startCopy()) {
                            

                                if (mPendingInstalls.size() > 0) {
                                    mPendingInstalls.remove(0);
                                }
                                if (mPendingInstalls.size() == 0) { //空闲时,解绑mContainerService
                                    if (mBound) {
                                        
                                        removeMessages(MCS_UNBIND);
                                        Message ubmsg = obtainMessage(MCS_UNBIND);
                                    
                                        sendMessageDelayed(ubmsg, 10000);
                                    }
                                } else {
                                  
                                    mHandler.sendEmptyMessage(MCS_BOUND);
                                }
                            }
             
                        }
                    } 
                    break;
                }

  • INIT_COPY 的主要作用是connectToService()连接DefaultContainerService,copyapk的操作是借助DefaultContainerService来完成的。connectToService成功之后,会发送MCS_BOUND消息
  • MCS_BOUND 消息主要负责完成apk的拷贝 以及apk中so文件的提取
private abstract class HandlerParams {

    final boolean startCopy() {
        boolean res;
        try {
            //...省略不重要的信息

            //(1)开始copy
            handleStartCopy();
            res = true;
            
        } catch (RemoteException e) {
            if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
            mHandler.sendEmptyMessage(MCS_RECONNECT);
            res = false;
        }
        //(2) copy完成后的操作
        handleReturnCode();
        return res;
    }
}

startCopy 主要做了两件事情:

  • handleStartCopy() 完成拷贝apk的过程
  • handleReturnCode() 拷贝之后的后续操作

handleStartCopy 主要生成了一个InstallArgs对象,然后调用copyApk方法

 public void handleStartCopy(){
    final InstallArgs args = createInstallArgs(this);
    ret = args.copyApk(mContainerService, false);
 }

copyApk->doCopyApk


 private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {


        //(1) copy文件到安装目录:系统app 安装到/system/app/ 普通app安装到/data/app
        int ret = PackageManager.INSTALL_SUCCEEDED;
        ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
        if (ret != PackageManager.INSTALL_SUCCEEDED) {
            Slog.e(TAG, "Failed to copy package");
            return ret;
        }


        //(2) 将apk中的so文件复制出来,保存到安装目录。如:/datap/app/lib/
         final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
            NativeLibraryHelper.Handle handle = null;
            try {
                handle = NativeLibraryHelper.Handle.create(codeFile);
                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                        abiOverride);
            } catch (IOException e) {
                Slog.e(TAG, "Copying native libraries failed", e);
                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
            } finally {
                IoUtils.closeQuietly(handle);
            }
 }

我们再看看拷贝完apk之后调用的handleReturnCode()

void handleReturnCode() {
            // If mArgs is null, then MCS couldn't be reached. When it
            // reconnects, it will try again to install. At that point, this
            // will succeed.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
}   

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() {
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.setReturnCode(currentStatus);
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                            args.doPreInstall(res.returnCode);
                            synchronized (mInstallLock) {
                                installPackageTracedLI(args, res);
                            }
                            args.doPostInstall(res.returnCode, res.uid);
                }
                //...省略不重要的代码
            }
    }

processPendingInstall->installPackageTracedLI->installPackageLI

installPackageLI 是安装的核心操作

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

                    //(1)利用PackageParser解析apk
                    final PackageParser.Package pkg;
                    try {
                        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
                        DexMetadataHelper.validatePackageDexMetadata(pkg);
                    } catch (PackageParserException e) {
                        res.setError("Failed parse during installPackageLI", e);
                        return;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }

                    //(2) 执行installNewPackageLIF 或者replacePackageLIF() 
                    try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                            "installPackageLI")) {
                        if (replace) {
                            if (pkg.applicationInfo.isStaticSharedLibrary()) {
                                // Static libs have a synthetic package name containing the version
                                // and cannot be updated as an update would get a new package name,
                                // unless this is the exact same version code which is useful for
                                // development.
                                PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                                if (existingPkg != null &&
                                        existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
                                    res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
                                            + "static-shared libs cannot be updated");
                                    return;
                                }
                            }
                            replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
                                    installerPackageName, res, args.installReason);
                        } else {
                            installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                                    args.user, installerPackageName, volumeUuid, res, args.installReason);
                        }
                    }


                    //(3) 对apk就行dexopt优化
                    mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,null /* instructionSets */,getOrCreateCompilerPackageStats(pkg),

      }  
  • (1) 利用PackageParser解析该apk
  • (2) 如果apk第一安装,则执行installNewPackageLIF 否则执行替换操作replacePackageLIF() ,我们主要分析首次安装的操作。
  • (3) 对apk就行dexopt优化

我们重点看下installNewPackageLIF 做了哪些事情:


      private void installNewPackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
        final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
        String volumeUuid, PackageInstalledInfo res, int installReason) {

            try {

                //此处仅保留了核心的代码,省略了不重要的代码

                //(1)扫描package,向PackageManagerService中注册该package
                PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
                        System.currentTimeMillis(), user);

          
                updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);

                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {

                    //(2)创建/data/data/包名  app数据目录
                    prepareAppDataAfterInstallLIF(newPackage);

                } else {
                    // Remove package from internal structures, but keep around any
                    // data that might have already existed
                    deletePackageLIF(pkgName, UserHandle.ALL, false, null,
                            PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
                }
            } catch (PackageManagerException e) {
                res.setError("Package couldn't be installed in " + pkg.codePath, e);
            }



        }

重要的操作由两个:scanPackageTracedLI 和prepareAppDataAfterInstallLIF()

  • scanPackageTracedLI

scanPackageTracedLI()最终会调用commitPackageSettings()

scanPackageTracedLI->scanPackageNewLI->commitScanResultsLocked-> commitPackageSettings

commitPackageSettings 是真正完成向PackageManagerService注册pkg和四大组件的方法,调用此方法之后,Android系统就可以查询该apk的信息了。


 /**    
     * 该方法是 将pkg和四大组件 注册到PackageManagerService的地方
     * Adds a scanned package to the system. When this method is finished, the package will
     * be available for query, resolution, etc...
     */
private void commitPackageSettings(PackageParser.Package pkg,
            @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, UserHandle user,
            final @ScanFlags int scanFlags, boolean chatty) {


        synchronized (mPackages) {


            // Add the new setting to mSettings
            //将pkg 插入到mSettings
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);
            // Add the new setting to mPackages
            //将当前包pkg 插入到mPackages
            mPackages.put(pkg.applicationInfo.packageName, pkg);
            // Make sure we don't accidentally delete its data.
            final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
            while (iter.hasNext()) {
                PackageCleanItem item = iter.next();
                if (pkgName.equals(item.packageName)) {
                    iter.remove();
                }
            }

      

            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
            for (i=0; i<N; i++) {
                PackageParser.Provider p = pkg.providers.get(i);
                p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        p.info.processName);
                mProviders.addProvider(p);
                //...省略不重要的代码
               
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
            }

            // 注册pkg中的service到mServices
            N = pkg.services.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Service s = pkg.services.get(i);
                s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        s.info.processName);
                mServices.addService(s);
                 //...省略不重要的代码
               
            }
         

            //注册pkg.receivers到mReceivers
            N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName);
                mReceivers.addActivity(a, "receiver");
                 //...省略不重要的代码
            }
       


            //注册pkg.activities 到 mActivities
            N = pkg.activities.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName);
                mActivities.addActivity(a, "activity");
                 //...省略不重要的代码
            }
          

           //...省略不重要的代码

        }
 }

  • prepareAppDataAfterInstallLIF

我们再看prepareAppDataAfterInstallLIF,经过多次调用,最终进入到prepareAppDataLeafLIF

prepareAppDataAfterInstallLIF->prepareAppDataLIF->prepareAppDataLeafLIF

prepareAppDataLeafLIF方法内,利用mInstaller完成了app用户数据目录的创建.

private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {

    //...省略不重要的代码

    try {
        ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
                appId, seInfo, app.targetSdkVersion);
    } catch (InstallerException e) {

    }
}
  • handlePackagePostInstall

执行完上述安装操作之后,会发送POST_INSTALL 消息,进入到handlePackagePostInstall方法

handlePackagePostInstall 会发送ACTION_PACKAGE_ADDED广播给监听者。

 private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload, String[] grantedPermissions,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver) {

            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/,
                        updateUserIds, instantUserIds);

}

至此一个新apk的安装完成。

3.3、Android 6.0 下的完整调用流程

下面 Android 6.0 源码 apk安装的完成调用过程,虽然最新的android sdk一些方法已经发生了变化,但是多少也可以做一些参考。

├── PMS.installPackage()
    └── PMS.installPackageAsUser()
         |传递 InstallParams 参数
        PackageHandler.doHandleMessage().INIT_COPY
         |
        PackageHandler.doHandleMessage().MCS_BOUND
         ├── HandlerParams.startCopy()
         │    ├── InstallParams.handleStartCopy()
         │    │    └──InstallArgs.copyApk()
         │    └── InstallParams.handleReturnCode()
         │         └── PMS.processPendingInstall()
         │              ├── InstallArgs.doPreInstall()
         │              ├── PMS.installPackageLI()
         │              │    ├── PackageParser.parsePackage()
         │              │    ├── PackageParser.collectCertificates()
         │              │    ├── PackageParser.collectManifestDigest()
         │              │    ├── PackageDexOptimizer.performDexOpt()
         │              │    ├── InstallArgs.doRename()
         │              │    │    └── InstallArgs.getNextCodePath()
         │              │    ├── replacePackageLI()
         │              │    │    ├── shouldCheckUpgradeKeySetLP()
         │              │    │    ├── compareSignatures()
         │              │    │    ├── replaceSystemPackageLI()
         │              │    │    │    ├── killApplication()
         │              │    │    │    ├── removePackageLI()
         │              │    │    │    ├── Settings.disableSystemPackageLPw()
         │              │    │    │    ├── createInstallArgsForExisting()
         │              │    │    │    ├── deleteCodeCacheDirsLI()
         │              │    │    │    ├── scanPackageLI()
         │              │    │    │    └── updateSettingsLI()
         │              │    │    └── replaceNonSystemPackageLI()
         │              │    │         ├── deletePackageLI()
         │              │    │         ├── deleteCodeCacheDirsLI()
         │              │    │         ├── scanPackageLI()
         │              │    │         └── updateSettingsLI()
         │              │    └── installNewPackageLI()
         │              │         ├── scanPackageLI()
         │              │         └── updateSettingsLI()
         │              ├── InstallArgs.doPostInstall()
         │              ├── BackupManager.restoreAtInstall()
         │              └── sendMessage(POST_INSTALL)
         │                   |
         │                  PackageHandler.doHandleMessage().POST_INSTALL
         │                   ├── grantRequestedRuntimePermissions()
         │                   ├── sendPackageBroadcast()
         │                   └── IPackageInstallObserver.onPackageInstalled()
         └── PackageHandler.doHandleMessage().MCS_UNBIND
              └── PackageHandler.disconnectService()![image](https://upload-images.jianshu.io/upload_images/5713484-36bddaa4264c58d4.png)

四、参考文章

https://www.jianshu.com/p/f47e45602ad2

https://www.jianshu.com/p/953475cea991

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android Apk安装过程分析 本文以android 8.0(API Level:26) 源码讲解apk安装过...
    北疆小兵阅读 678评论 0 0
  • 这两天在看Android65535方法数的解决方法,遇到了些Apk安装过程的疑惑,于是决定好好学习下Android...
    朔野阅读 18,298评论 12 75
  • 夜莺2517阅读 127,711评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,876评论 1 6
  • 我是一名过去式的高三狗,很可悲,在这三年里我没有恋爱,看着同龄的小伙伴们一对儿一对儿的,我的心不好受。怎么说呢,高...
    小娘纸阅读 3,375评论 4 7