zoukankan      html  css  js  c++  java
  • APK安装流程概述



    . APK安装简介


    APKAndroid Package的缩写。


    Android应用安装有如下四种方式:

    1.系统应用安装――开机时完成,没有安装界面;

    2.网络下载应用安装――通过market应用完成,没有安装界面;

    3.ADB工具安装――没有安装界面;

    4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。

     


    应用安装涉及到如下几个目录:

    • system/app----------------系统自带的应用程序,获得adb root权限才能删除;
    • data/app-------------------用户程序安装的目录,安装时把apk 文件复制到此目录;
    • data/data-------------------存放应用程序的数据;
    • data/dalvik-cache---------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)。



    . 系统应用安装

     

    1. 了解须知:

    1. 对于在/system/app/data/app目录下的APK文件,在PackageManagerService的启动过程中,会扫描安装

    2.PackageManagerServicesystem_server启动,它全面负责应用包的安装,卸载,权限检查等工作。

    3.在每次开机的时 候,PackageManagerService都会在其构造函数中,对指定的目录的APK进行扫描。对于没有安装的APK文件会触发安装过程。



    2. 实现原理:

    (1). 开机启动PackageManagerService,通过SystemServer.startBootstrapServices()启动。

    1 public static PackageManagerService main(Context context, Installer installer,
    2             boolean factoryTest, boolean onlyCore) {
    3         PackageManagerService m = HwServiceFactory.getHuaweiPackageManagerService(context, installer,
    4                 factoryTest, onlyCore);
    5         ServiceManager.addService("package", m);
    6         return m;
    7     }

     

    (2). PackageManagerService初始化,执行构造方法,分为六个重要步骤。

     

    第一步:创建Settings对象,添加shareUserId

     1         mSettings = new Settings(mPackages);
     2         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
     3                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
     4         mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
     5                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
     6         mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
     7                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
     8         mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
     9                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    10         mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
    11                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    12         mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
    13                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);


    第二步:创建应用安装器Installer,来源是PackageManagerService参数之一。

     

    第三步:构造SystemConfig,读取/system/etc/permissions/*.xml” 资源,获取mSystemPermissions(系统权限),mGlobalGidsGroup-ids),mAvailableFeatures(系统支持的features)属性。

    执行顺序:

    com.android.server.pm.PackageManagerService#PackageManagerService

    --> com.android.server.SystemConfig#getInstance

    --> com.android.server.SystemConfig#SystemConfig

    --> com.android.server.SystemConfig#readPermissions

    1    SystemConfig systemConfig = SystemConfig.getInstance();
    2    mGlobalGids = systemConfig.getGlobalGids();
    3    mSystemPermissions = systemConfig.getSystemPermissions();
    4    mAvailableFeatures = systemConfig.getAvailableFeatures();

    第四步:创建系统消息处理线程。

    1   mHandlerThread = new ServiceThread(TAG,
    2             Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
    3   mHandlerThread.start();
    4   mHandler = new PackageHandler(mHandlerThread.getLooper());
    5   Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

    第五步:执行com.android.server.pm.Settings#readLPw, 读取安装包信息,并解析成对应的数据结构,包括以下重要文件:

    • packages.xml:记录系统中所有安装的应用信息,包括基本信息、签名和权限。

    • packages-backup.xmlpackages.xml文件的备份。

    • packages.list:保存普通应用的数据目录和uid等信息。

    • packages-stopped.xml:记录系统中被强制停止运行的应用信息。系统在强制停止某个应用时,会讲应用的信息记录到该文件中。

    • packages-stopped-backup.xmlpacakges-stopped.xml文件的备份。

    这几个目录在创建Settings对象的时候,就已经被封装成对应的File文件。

    packages-backup.xmlpackages.xml的备份文件。在每次写packages.xml文件的时候,都会将旧的 packages.xml文件先备份,这样做是为了防止写文件过程中文件以外损坏,还能从旧的文件中恢复。

    package- restrictions.xml保存着受限制的APP的状态,比如某个APP处于disable状态,或者某个APP具有更高的优先级等。



    第六步:执行PackageManagerService#scanDirLI

    监控和扫描系统包安装目录:

    • /system/framework 系统库
    • /system/app 默认的系统应用
    • /vendor/app 厂商定制的应用

    扫描非系统apk信息:

    • /data/app/
    • /system/preloadapp/
    • /data/app-private/

    跟踪扫描安装过程

    构建PackageParser对象

          调用PackageManagerService#scanPackageLI(xxx) 方法。

     

    构建一个PackageParser.Package对象并返回

      调用PackageParser#parsePackage(java.io.File, int) 方法,扫描APK安装包的AndroidManifest.xml文件和提取证书信息,以此信息构建一个PackageParser.Package对象,并将其返回;


    PackageParser.Package对象的信息保存到PackageManagerService

    其中包括ContentProvider,Activity,Service,BroadcastReceiver


    构建PackageSetting 对象

    执行以下代码:

    .PackageManagerService#scanPackageLI(xxx)

    --> .PackageManagerService#scanPackageDirtyLI

    构建PackageSetting 对象,这个对象中保存的信息最后会通过writeLPr写入到/data/system/packages.xml文件中去。



    以上几个步骤可以用两个图代替:

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------



    ----------------------------------------------------------------------------------------------------------------------------------------------------------------





    调用mInstaller.createUserData()函数创建数据目录

    调用PackageManagerService#createDataDirsLI方法,installd发送消息,为应用程序创建对应的数据目录,如果已经存在,也会重新创建一遍。

     

     

    调用mInstaller.install()函数完成APK安装

     1  private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
     2         int[] users = sUserManager.getUserIds();
     3         int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
     4         if (res < 0) {
     5             return res;
     6         }
     7         for (int user : users) {
     8             if (user != 0) {
     9                 res = mInstaller.createUserData(volumeUuid, packageName,
    10                         UserHandle.getUid(user, uid), user, seinfo);
    11                 if (res < 0) {
    12                     return res;
    13                 }
    14             }
    15         }
    16         return res;
    17     }

    Installer.install()函数和createUserData()进行完成了命令组装工作,在组装完命令之后,将命令传递给InstallerConnectio.java处理。

     1 public int install(String uuid, String name, int uid, int gid, String seinfo) {
     2         StringBuilder builder = new StringBuilder("install");
     3         builder.append(' ');
     4         builder.append(escapeNull(uuid));
     5         builder.append(' ');
     6         builder.append(name);
     7         builder.append(' ');
     8         builder.append(uid);
     9         builder.append(' ');
    10         builder.append(gid);
    11         builder.append(' ');
    12         builder.append(seinfo != null ? seinfo : "!");
    13         return mInstaller.execute(builder.toString());
    14     }

    通过分析InstallerConnection.java得到以下结论:

    1. InstallerConnection连接一个名为Installd的服务

    2. Install具体的命令有Installd完成



    以下是InstallerConnection连接Installd服务的代码

     1 private boolean connect() {
     2         if (mSocket != null) {
     3             return true;
     4         }
     5         Slog.i(TAG, "connecting...");
     6         try {
     7             mSocket = new LocalSocket();
     8 
     9             LocalSocketAddress address = new LocalSocketAddress("installd",
    10                     LocalSocketAddress.Namespace.RESERVED);
    11 
    12             mSocket.connect(address);
    13 
    14             mIn = mSocket.getInputStream();
    15             mOut = mSocket.getOutputStream();
    16         } catch (IOException ex) {
    17             disconnect();
    18             return false;
    19         }
    20         return true;
    21     }


    Installed介绍

    Installd是一个native进程,该进程启动一个socket,然后处理来自Installer的命令。



    PackageManagerService通过套接字的方式访问installd服务进程,在Android启动脚本init.rc中通过服务配置启动了installd服务进程。

    1     service installd /system/bin/installd
    2     class main
    3     socket installd stream 600 system system

    通过以上配置,init进程就会启动installd服务进程了。


    Installed 进程的入口是main函数,该函数首先初始化一些变量就安装目录,然后从环境变量中取得installd套件字的句柄值,然后进入监听此socket,当客户端发送过来请求时,接收客户端的请求,并读取客户端发送过来的命令数据,并根据读取的客户端命令来执行命令操作。

    1 int main(const int argc __unused, char *argv[]) {
     2     char buf[BUFFER_MAX];
     3     struct sockaddr addr;
     4     socklen_t alen;
     5     int lsocket, s;
     6     int selinux_enabled = (is_selinux_enabled() > 0);
     7 
     8     setenv("ANDROID_LOG_TAGS", "*:v", 1);
     9     android::base::InitLogging(argv);
    10 
    11     ALOGI("installd firing up
    ");
    12 
    13     union selinux_callback cb;
    14     cb.func_log = log_callback;
    15     selinux_set_callback(SELINUX_CB_LOG, cb);
    16 
    17     if (initialize_globals() < 0) {
    18         ALOGE("Could not initialize globals; exiting.
    ");
    19         exit(1);
    20     }
    21 
    22     if (initialize_directories() < 0) {
    23         ALOGE("Could not create directories; exiting.
    ");
    24         exit(1);
    25     }
    26 
    27     if (selinux_enabled && selinux_status_open(true) < 0) {
    28         ALOGE("Could not open selinux status; exiting.
    ");
    29         exit(1);
    30     }
    31 
    32     lsocket = android_get_control_socket(SOCKET_PATH);
    33     if (lsocket < 0) {
    34         ALOGE("Failed to get socket from environment: %s
    ", strerror(errno));
    35         exit(1);
    36     }
    37     if (listen(lsocket, 5)) {
    38         ALOGE("Listen on socket failed: %s
    ", strerror(errno));
    39         exit(1);
    40     }
    41     fcntl(lsocket, F_SETFD, FD_CLOEXEC);
    42 
    43     for (;;) {
    44         alen = sizeof(addr);
    45         s = accept(lsocket, &addr, &alen);
    46         if (s < 0) {
    47             ALOGE("Accept failed: %s
    ", strerror(errno));
    48             continue;
    49         }
    50         fcntl(s, F_SETFD, FD_CLOEXEC);
    51 
    52         ALOGI("new connection
    ");
    53         for (;;) {
    54             unsigned short count;
    55             if (readx(s, &count, sizeof(count))) {
    56                 ALOGE("failed to read size
    ");
    57                 break;
    58             }
    59             if ((count < 1) || (count >= BUFFER_MAX)) {
    60                 ALOGE("invalid size %d
    ", count);
    61                 break;
    62             }
    63             if (readx(s, buf, count)) {
    64                 ALOGE("failed to read command
    ");
    65                 break;
    66             }
    67             buf[count] = 0;
    68             if (selinux_enabled && selinux_status_updated() > 0) {
    69                 selinux_android_seapp_context_reload();
    70             }
    71             if (execute(s, buf)) break;
    72         }
    73         ALOGI("closing connection
    ");
    74         close(s);
    75     }
    76 
    77     return 0;
    78 }


    main函数调用execute函数,执行客户发送过来的请求命令。

     1 static int execute(int s, char cmd[BUFFER_MAX])
     2 {
     3     char reply[REPLY_MAX];
     4     char *arg[TOKEN_MAX+1];
     5     unsigned i;
     6     unsigned n = 0;
     7     unsigned short count;
     8     int ret = -1;
     9 
    10     // ALOGI("execute('%s')
    ", cmd);
    11 
    12         /* default reply is "" */
    13     reply[0] = 0;
    14 
    15         /* n is number of args (not counting arg[0]) */
    16     arg[0] = cmd;
    17     while (*cmd) {
    18         if (isspace(*cmd)) {
    19             *cmd++ = 0;
    20             n++;
    21             arg[n] = cmd;
    22             if (n == TOKEN_MAX) {
    23                 ALOGE("too many arguments
    ");
    24                 goto done;
    25             }
    26         }
    27         if (*cmd) {
    28           cmd++;
    29         }
    30     }
    31 
    32     for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
    33         if (!strcmp(cmds[i].name,arg[0])) {
    34             if (n != cmds[i].numargs) {
    35                 ALOGE("%s requires %d arguments (%d given)
    ",
    36                      cmds[i].name, cmds[i].numargs, n);
    37             } else {
    38                 ret = cmds[i].func(arg + 1, reply);
    39             }
    40             goto done;
    41         }
    42     }
    43     ALOGE("unsupported command '%s'
    ", arg[0]);
    44 
    45 done:
    46     if (reply[0]) {
    47         n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
    48     } else {
    49         n = snprintf(cmd, BUFFER_MAX, "%d", ret);
    50     }
    51     if (n > BUFFER_MAX) n = BUFFER_MAX;
    52     count = n;
    53 
    54     // ALOGI("reply: '%s'
    ", cmd);
    55     if (writex(s, &count, sizeof(count))) return -1;
    56     if (writex(s, cmd, count)) return -1;
    57     return 0;
    58 }

    installd服务可执行的命令:

    1 struct cmdinfo cmds[] = {
     2     { "ping",                 0, do_ping },
     3     { "install",              5, do_install },
     4     { "dexopt",               9, do_dexopt },
     5     { "markbootcomplete",     1, do_mark_boot_complete },
     6     { "movedex",              3, do_move_dex },
     7     { "rmdex",                2, do_rm_dex },
     8     { "remove",               3, do_remove },
     9     { "rename",               2, do_rename },
    10     { "fixuid",               4, do_fixuid },
    11     { "freecache",            2, do_free_cache },
    12     { "rmcache",              3, do_rm_cache },
    13     { "rmcodecache",          3, do_rm_code_cache },
    14     { "getsize",              8, do_get_size },
    15     { "rmuserdata",           3, do_rm_user_data },
    16     { "cpcompleteapp",        6, do_cp_complete_app },
    17     { "movefiles",            0, do_movefiles },
    18     { "linklib",              4, do_linklib },
    19     { "mkuserdata",           5, do_mk_user_data },
    20     { "mkuserconfig",         1, do_mk_user_config },
    21     { "rmuser",               2, do_rm_user },
    22     { "idmap",                3, do_idmap },
    23     { "restorecondata",       4, do_restorecon_data },
    24     { "createoatdir",         2, do_create_oat_dir },
    25     { "rmpackagedir",         1, do_rm_package_dir },
    26     { "linkfile",             3, do_link_file }
    27 };

    应用程序安装

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

    do_install 函数直接调用frameworksasecmdsinstalldcommands.c中的install函数来安装

    1 int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
     2 {
     3     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
     4         ALOGE("invalid uid/gid: %d %d
    ", uid, gid);
     5         return -1;
     6     }
     7 
     8     std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
     9     const char* pkgdir = _pkgdir.c_str();
    10 
    11     if (mkdir(pkgdir, 0751) < 0) {
    12         ALOGE("cannot create dir '%s': %s
    ", pkgdir, strerror(errno));
    13         return -1;
    14     }
    15     if (chmod(pkgdir, 0751) < 0) {
    16         ALOGE("cannot chmod dir '%s': %s
    ", pkgdir, strerror(errno));
    17         unlink(pkgdir);
    18         return -1;
    19     }
    20 
    21     if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
    22         ALOGE("cannot setfilecon dir '%s': %s
    ", pkgdir, strerror(errno));
    23         unlink(pkgdir);
    24         return -errno;
    25     }
    26 
    27     if (chown(pkgdir, uid, gid) < 0) {
    28         ALOGE("cannot chown dir '%s': %s
    ", pkgdir, strerror(errno));
    29         unlink(pkgdir);
    30         return -1;
    31     }
    32 
    33     return 0;
    34 }



    . PackageInstaller 安装apk

     

    PackageInstaller 本身就是一个apk,代码位置在/packages/apps/PackageInstaller/”,用于显示安装应用的界面的一个apk。安装过程其实是通过PackageManagerService 调用Installer来完成的。



    安装过程中涉及到的类文件:

    PackageInstallerActivity.java

    在文件管理器里点击apk后就会调用该类,主要用于显示要安装的apk的一些权限信息

    InstallAppProgress.java

    当看完所有权限后,点安装后就会调用该类,用于显示安装进度,这时候PackageManagerService就在默默的安装应用。

    ApplicationPackageManager.java

    这是类是PackageManager的子类,我们使用mContext.getPackageManager得到的其实就是ApplicationPackageManager的对象,它爹PackageManager是个抽象类,对外的方法都定义在里面。

    PackageParser.java

    解析app,主要解析apk中的AndroidManifest.xml,解析里面的四大组件以及权限信息放入内存里,最后写到packages.xmlpackage.list/data/system下)中。

    AssetManager.java

    AndroidManifest.xmlapp中拿出来给PackageParser.java去解析。

    DefaultContainerService.java

    这个服务用于检查存储状态,得到合适的安装位置。

    Installer.java

    PackageManagerService调用它去执行安装,他会把PackageManagerService传过来的数据封装成命令,然后让底层的Installer去执行。

    PackageManagerService.java

    管理app的安装、移动、卸载、查询等。



    实现原理:

    1. 点击文件管理器中的apk时,文件管理器会启动PackageInstallerPackageInstallerActivity界面,并且将apk的信息通过intent传递给PackageInstallerActivity



    2. PackageInstaller启动过后会检查是否开启未知来源,未开启就需要先进入设置设置后,方可继续安装;

    1      @Override
    2     protected void onCreate(Bundle icicle) {
    3         ......
    4         mPm = getPackageManager();
    5         boolean requestFromUnknownSource =  isInstallRequestFromUnknownSource(intent);
    6         ......
    7         initiateInstall();
    8     }

    之后会依次调用initiateInstall()->startInstallConfirm();

    initiateInstall方法负责检查是否已经安装过,是否是系统应用等;

    startInstallConfirm负责初始化界面,显示权限信息;

    当点击安装按钮时,启动安装,切换界面到InstallAppProgress

     1 private void startInstall() {
     2         // Start subactivity to actually install the application
     3         Intent newIntent = new Intent();
     4         newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
     5                 mPkgInfo.applicationInfo);
     6         newIntent.setData(mPackageURI);
     7         newIntent.setClass(this, InstallAppProgress.class);
     8         ........
     9         startActivity(newIntent);
    10         finish();
    11     }


    3. InstallAppProgress中会调用initView去初始化界面并调用ApplicationPackageManagerinstallPackageWithVerificationAndEncryption方法来安装.

    1 @Override
    2     public void onCreate(Bundle icicle) {
    3         ......
    4         initView();
    5     }
     1 public void initView() {
     2         ......
     3         if ("package".equals(mPackageURI.getScheme())) {
     4             try {
     5                 pm.installExistingPackage(mAppInfo.packageName);
     6                 observer.packageInstalled(mAppInfo.packageName,
     7                         PackageManager.INSTALL_SUCCEEDED);
     8             } catch (PackageManager.NameNotFoundException e) {
     9                 observer.packageInstalled(mAppInfo.packageName,
    10                         PackageManager.INSTALL_FAILED_INVALID_APK);
    11             }
    12         } else {
    13             pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
    14                     installerPackageName, verificationParams, null);
    15         }
    16     }


    4. ApplicationPackageManagerinstallPackageWithVerificationAndEncryption里也是调用PMSinstallPackage 方法.

    1 @Override
    2     public void installPackageWithVerificationAndEncryption(Uri packageURI,
    3             IPackageInstallObserver observer, int flags, String installerPackageName,
    4             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { 
    5         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
    6                 installerPackageName, verificationParams, encryptionParams);
    7     }
    1 private void installCommon(Uri packageURI,
     2             PackageInstallObserver observer, int flags, String installerPackageName,
     3             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {  
     4         if (!"file".equals(packageURI.getScheme())) {
     5             throw new UnsupportedOperationException("Only file:// URIs are supported");
     6         }
     7         if (encryptionParams != null) {
     8             throw new UnsupportedOperationException("ContainerEncryptionParams not supported");
     9         }
    10 
    11         final String originPath = packageURI.getPath();
    12         try {
    13             mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
    14                     verificationParams, null);
    15         } catch (RemoteException ignored) {
    16         }
    17     }


    5. .installPackage() 方法里,首先会获取设置中的用户安装位置,并且会把InstallParams对象和安装位置flag封装到Message里,然后发出一个消息。

    1     @Override
    2     public void installPackage(String originPath, IPackageInstallObserver2 observer,
    3             int installFlags, String installerPackageName, VerificationParams verificationParams,
    4             String packageAbiOverride) {
    5         installPackageAsUser(originPath, observer, installFlags, installerPackageName,
    6                 verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
    7     }


    1 @Override
     2 public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
     3         int installFlags, String installerPackageName, VerificationParams verificationParams,
     4         String packageAbiOverride, int userId) {
     5 
     6     ......
     7 
     8     final Message msg = mHandler.obtainMessage(INIT_COPY);
     9     msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
    10             null, verificationParams, user, packageAbiOverride, null);
    11     mHandler.sendMessage(msg);  
    12 }


    6. PackageManagerService.PackageHandler#doHandleMessage 处理INIT_COPYMCS_BOUN消息。

    如果msg.what INIT_COPY

    连接DefaultContainerService服务把我们要安装的信息放到HandlerParams的一个ListmPendingInstalls然后发送MCS_BOUND消息。

    如果msg.what MCS_BOUN

    则通过 “HandlerParams params = mPendingInstalls.get(0)” 读取出我们要安装的包信息,然后清除该包信息,如果还有其他包就继续发MCS_BOUND这个消息,循环,直到都安装完了。

    然后执行PackageManagerService.HandlerParams#startCopy



    7. 执行HandlerParams#startCopy

    1 final boolean startCopy() {
     2             boolean res;
     3             try {
     4                 if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
     5 
     6                 if (++mRetries > MAX_RETRIES) {
     7                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
     8                     mHandler.sendEmptyMessage(MCS_GIVE_UP);
     9                     handleServiceError();
    10                     return false;
    11                 } else {
    12                     handleStartCopy();
    13                     Slog.i(TAG, "Apk copy done");
    14                     res = true;
    15                 }
    16             } catch (RemoteException e) {
    17                 if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
    18                 mHandler.sendEmptyMessage(MCS_RECONNECT);
    19                 res = false;
    20             }
    21             handleReturnCode();
    22             return res;
    23         }

    startCopy有两个重要的方法:handleStartCopy handleReturnCode


    调用handleStartCopy

    handleStartCopy方法中会检查应用是否能安装;

    不合法则返回FAILEDCODE,接着会调用DefaultContainerServicegetMinimalPackageInfo方法,该方法用于获取存储状态,返回合适的安装位置;经过一系列的判断,如果返回码是INSTALL_SUCCEEDED,那接下来就会调用InstallParamscopyApk如果安装到内置,调用的就是FileInstallArgscopyApk方法;如安装到外置就调用AsecInstallArgscopyApk方法;AsecInstallArgsFileInstallArgs都是InstallParams的子类。

    copyApk方法中会依次调用FileInstallArgs createCopyFile->PackageManagerServicecreateTempPackageFile方法去创建临时文件。


    handleStartCopy有两个作用:

    1. final InstallArgs args = createInstallArgs(this);

    2. 返回ret标识是否安装成功的



    调用handleReturnCode

    1 @Override
    2 void handleReturnCode() {
    3     if (mArgs != null) {
    4         processPendingInstall(mArgs, mRet);
    5     }
    6 }

    也就是调用installPackageLI(args, true, res)

    1        if (replace) {
    2             replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
    3                     installerPackageName, volumeUuid, res);
    4         } else {
    5             installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
    6                     args.user, installerPackageName, volumeUuid, res);
    7         }

    如果是第一次安装,则执行installNewPackageLI方法。

    之后的代码和PackageManagerService安装系统软件一样了。

    PackageManagerService#installNewPackageLI

    -->PackageManagerService#scanPackageLI(android.content.pm.PackageParser.Package, int, int, long, android.os.UserHandle)

    -->PackageManagerService#scanPackageDirtyLI

    -->PackageManagerService#createDataDirsLI

     

     1 private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
     2         int[] users = sUserManager.getUserIds();
     3         int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
     4         if (res < 0) {
     5             return res;
     6         }
     7         for (int user : users) {
     8             if (user != 0) {
     9                 res = mInstaller.createUserData(volumeUuid, packageName,
    10                         UserHandle.getUid(user, uid), user, seinfo);
    11                 if (res < 0) {
    12                     return res;
    13                 }
    14             }
    15         }
    16         return res;
    17     }

    调用InstallercreateUserDatainstall方法,连接底层的Installed服务来安装。

    备注: 关于adb工具安装apk的文章, 可以参考 http://blog.csdn.net/gaugamela/article/details/52691084




  • 相关阅读:
    hadoop 2.5 hdfs namenode –format 出错Usage: java NameNode [-backup] |
    自己动手编译hadoop-2.5.2源码
    CentOS Linux解决Device eth0 does not seem to be present
    Liz Murray成功故事的偶然与必然(转)
    【BZOJ4242】水壶(克鲁斯卡尔重构树,BFS)
    【BZOJ3551】Peaks加强版(Kruskal重构树,主席树)
    【agc023E】Inversions(线段树,动态规划)
    【CF183D】T-shirt(动态规划,贪心)
    【BZOJ2423】最长公共子序列(动态规划)
    【BZOJ2118】墨墨的等式(最短路)
  • 原文地址:https://www.cnblogs.com/neo-java/p/7117482.html
Copyright © 2011-2022 走看看