adb install 也是用的pm命令去安裝的,因此開始是在pm.java中。 java
frameworks\base\services\java\com\android\server\pm android
一、調用pm程序開始安裝 shell
得用Pm安裝時,通常是shell運行一個pm命令,並傳送相應的參數,咱們經過adb鏈接到機器,輸入pm,會打出pm的一些參數 併發
# pm
pm app
public static void main(String[] args) { new Pm().run(args); }
public void run(String[] args) { ......進行一系列的判斷...... if ("install".equals(op)) { runInstall(); return; } }
private void runInstall() { ................此處省略一萬字...................... mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName, verificationURI, null); }
frameworks\base\services\java\com\android\server\pm async
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest) { .................此處省略一萬字............................. final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer,filteredFlags,installerPackageName, verificationURI, manifestDigest); mHandler.sendMessage(msg); }
void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { if (DEBUG_INSTALL) Slog.i(TAG, "init_copy"); HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx); // 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. //鏈接服務 連接上返回真走else 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; }
調用connectToService方法
private boolean connectToService() { if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" + " DefaultContainerService"); //鏈接服務DefaultContainerService Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); //設置線程默認應用的優先級 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); //在鏈接成功的時候觸發DefaultContainerConnection的onServiceConnected if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; } //設置線程優先級爲後臺,這樣當多個線程併發後不少可有可無的線程分配的CPU時間將會減小,有利於主線程的處理 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return false; }
鏈接服務DefaultContainerConnection 綁定成功發送一條消息MCS_BOUND ide
final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); class DefaultContainerConnection implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected"); IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); //PackageHandler發了一條MCS_BOUND mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs)); } public void onServiceDisconnected(ComponentName name) { if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected"); } };
發送了一條消息MCS_BOUND和 IMediaContainerService imcs 對象
IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 函數
調用方法params.startCopy() post
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy"); 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; }
handleStartCopy進行一些安裝前準備工做,最後調用handleReturnCode ui
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); } }
mArgs 在handleStartCopy進行了初始化
/* * 調用遠程方法來獲取和安裝包信息 * Invoke remote method to get package information and install * location values. Override install location based on default * policy if needed and then create install arguments based * on the install location. */ public void handleStartCopy() throws RemoteException { .............................. int ret = PackageManager.INSTALL_SUCCEEDED; final InstallArgs args = createInstallArgs(this); mArgs = args; }
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); }installPackageLI調用這個方法
在installPackageLI中,會new 一個PackageParser對package進行解析,調用parsePackage函數 parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags)函數根據參數進行一些處理後最終調用parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)對包進行解析,咱們看到這個函數裏面主要對配置文件AndroidManifest.xml文件進行了解析。
//這個函數裏面主要對配置文件AndroidManifest.xml文件進行了解析 //返回解析到的全部數據pkg final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, null, mMetrics, parseFlags);
private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) { .............................. //replace判斷設備上面是否有安裝的app if (replace) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); } else { installNewPackageLI(pkg, parseFlags, scanMode, installerPackageName,res); } }跟蹤scanPackageLI()方法後發現,程序通過不少次的if else 的篩選,最後斷定能夠安裝後調用了 mInstaller.installprivate void installNewPackageLI(PackageParser.Package pkg, int parseFlags,int scanMode, String installerPackageName, PackageInstalledInfo res) { ***********************省略若干************************************************* PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis()); ***********************省略若干************************************************** }
if (mInstaller != null) { int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,pkg.applicationInfo.uid); if(ret < 0) { // Error from installer mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; return null; } }
技術交流羣 182189263