一. APK安裝簡介
APK為Android 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).PackageManagerService由system_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(系統權限),mGlobalGids(Group-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.xml:packages.xml文件的備份。
-
packages.list:保存普通應用的數據目錄和uid等信息。
-
packages-stopped.xml:記錄系統中被強制停止運行的應用信息。系統在強制停止某個應用時,會講應用的信息記錄到該文件中。
-
packages-stopped-backup.xml:pacakges-stopped.xml文件的備份。
這幾個目錄在創建Settings對象的時候,就已經被封裝成對應的File文件。
packages-backup.xml是packages.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\n"); 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.\n"); 19 exit(1); 20 } 21 22 if (initialize_directories() < 0) { 23 ALOGE("Could not create directories; exiting.\n"); 24 exit(1); 25 } 26 27 if (selinux_enabled && selinux_status_open(true) < 0) { 28 ALOGE("Could not open selinux status; exiting.\n"); 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\n", strerror(errno)); 35 exit(1); 36 } 37 if (listen(lsocket, 5)) { 38 ALOGE("Listen on socket failed: %s\n", 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\n", strerror(errno)); 48 continue; 49 } 50 fcntl(s, F_SETFD, FD_CLOEXEC); 51 52 ALOGI("new connection\n"); 53 for (;;) { 54 unsigned short count; 55 if (readx(s, &count, sizeof(count))) { 56 ALOGE("failed to read size\n"); 57 break; 58 } 59 if ((count < 1) || (count >= BUFFER_MAX)) { 60 ALOGE("invalid size %d\n", count); 61 break; 62 } 63 if (readx(s, buf, count)) { 64 ALOGE("failed to read command\n"); 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\n"); 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')\n", 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\n"); 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)\n", 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'\n", 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'\n", 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 函數直接調用frameworks\base\cmds\installd\commands.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\n", 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\n", pkgdir, strerror(errno)); 13 return -1; 14 } 15 if (chmod(pkgdir, 0751) < 0) { 16 ALOGE("cannot chmod dir '%s': %s\n", 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\n", 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\n", 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.xml和package.list(/data/system下)中。
AssetManager.java:
把AndroidManifest.xml從app中拿出來給PackageParser.java去解析。
DefaultContainerService.java:
這個服務用於檢查存儲狀態,得到合適的安裝位置。
Installer.java:
PackageManagerService調用它去執行安裝,他會把PackageManagerService傳過來的數據封裝成命令,然后讓底層的Installer去執行。
PackageManagerService.java:
管理app的安裝、移動、卸載、查詢等。
實現原理:
1. 點擊文件管理器中的apk時,文件管理器會啟動PackageInstaller的PackageInstallerActivity界面,並且將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去初始化界面並調用ApplicationPackageManager的installPackageWithVerificationAndEncryption方法來安裝.
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. ApplicationPackageManager的installPackageWithVerificationAndEncryption里也是調用PMS的installPackage 方法.
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_COPY、MCS_BOUN消息。
則連接DefaultContainerService服務,把我們要安裝的信息放到HandlerParams的一個List中mPendingInstalls,然后發送MCS_BOUND消息。
如果msg.what 是MCS_BOUN:
則通過 “HandlerParams params = mPendingInstalls.get(0)” 讀取出我們要安裝的包信息,然后清除該包信息,如果還有其他包就繼續發MCS_BOUND這個消息,循環,直到都安裝完了。
然后執行PackageManagerService.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:
如不合法則返回FAILED的CODE,接着會調用DefaultContainerService的getMinimalPackageInfo方法,該方法用於獲取存儲狀態,返回合適的安裝位置;經過一系列的判斷,如果返回碼是INSTALL_SUCCEEDED,那接下來就會調用InstallParams的copyApk;如果安裝到內置,調用的就是FileInstallArgs的copyApk方法;如安裝到外置就調用AsecInstallArgs的copyApk方法;AsecInstallArgs和FileInstallArgs都是InstallParams的子類。
copyApk方法中會依次調用FileInstallArgs 的createCopyFile->PackageManagerService的createTempPackageFile方法去創建臨時文件。
handleStartCopy有兩個作用:
1. final InstallArgs args = createInstallArgs(this);
2. 返回ret標識是否安裝成功的。
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 }
調用Installer的createUserData和install方法,連接底層的Installed服務來安裝。
備注: 關於adb工具安裝apk的文章, 可以參考 http://blog.csdn.net/gaugamela/article/details/52691084