Android安装APK详解
来源:互联网 发布:php 获取图片拍摄地点 编辑:程序博客网 时间:2024/06/08 01:53
转载自:http://cstsinghua.github.io/2016/06/13/Android安装APK详解/
Android安装APK详解
- 系统应用安装:开机时加载系统的APK和应用,没有安装界面;
- 网络下载应用安装:通过各种market应用完成,没有安装界面;
- ADB工具安装:即通过Android的SDK开发tools里面的adb.exe程序安装,没有安装界面;
- 第三方应用安装:通过SD卡里的APK文件安装(比如双击APK文件触发),有安装界面,系统默认已经安装了一个安装卸载应用的程序,即由packageinstaller.apk应用处理安装及卸载过程的界面。
Android APK安装概述
应用安装涉及到的目录
- /system/app :系统自带的应用程序,获得adb root权限才能删除
- /data/app :用户程序安装的目录。安装时把apk文件复制到此目录
- /data/data :存放应用程序的数据
- /data/dalvik-cache:将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,当然,ART–Android Runtime的可执行文件格式为oat,启用ART时,系统会执行dex文件转换至oat文件)
/data/system :该目录下的packages.xml文件,类似于Windows的注册表,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
/data/system/packages.xml中内容详解(这里列举的标签内容不一定完整,只是列举核心内容,packages.xml的完整定义详见官方文档):
该文件的根节点是…,内容树结构如下图所示:(1)permissions标签定义了目前系统中定义的所有权限。主要分为两类:系统定义的(package属性为android)和APK定义的(package属性为APK的包名)。
(2)package代表一个APK的属性,它的属性含义如下(这里并未完全列出,如需了解全部属性,请查看官方文档)。
name:APK的包名codePath:安装路径。有/system/app系统APK和/data/app两种。/system/app存放系统出厂时预置的一些APK,/data/app存放用户安装的第三方APK。system:如果APK被安装在/system/app下,system的值为true;安装在/data/app下面的话,值为true。ts:时间戳version:APK的版本号sharedUserId/userId:Android系统启动一个普通的APK时,会为这个APK分配一个独立的UID,这就是userId。如果APK要和系统中其它APK使用相同的UID的话,那就是sharedUserId。关于共享UID,下面有更详细的描述。
package的子标签perms:APK的AndroidManifest.xml文件中,每使用一个标签,标签中就会增加一项。
(3)代表一个共享UID,通常,共同实现一系列相似功能的APK共享一个UID。其子标签中的权限代表了这个共享UID的权限,所有使用的同一个共享UID的APK运行在同一进程中,这个进程的UID就是这个共享UID,这些APK都具有这个共享UID的权限。其属性包括:
name:共享UID的名字,在APK的android:sharedUserId属性中使用。userId:使用这个共享UID的所有APK运行时所在的进程的UID。
安装过程总述
安卓系统安装一个应用时,系统大致会进行如下操作:
- 复制APK安装包到data/app目录下,文件名会以应用的package命名;
- 解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录(一般情况下,会先执行dexopt即dex文件的优化,将优化后的dex文件保存至该目录下),并data/data目录下创建对应的应用数据目录(data/data目录可读可写);
- 更新/data/system/packages.xml中的内容,将APK的信息加入进去。
卸载过程概述
对照安装过程,卸载过程与之相逆:
删除安装过程中在上述目录下创建的文件及目录。
安装应用的过程代码解析
鉴于APK安装有四种方式,这里分别对各种方式下的安装详细过程进行代码级的解析。
安装过程代码解析的前奏
注意:由于Android API迭代较快,版本众多,不过关于安装和卸载的逻辑核心(代码主干)是不变的,最新level级别的API可能会加入更多分支或细节完善代码,一般建议以低版本的API作为分析基础,这样便于更加快速地厘清代码流程和主干,本文以API level14的源码做切入点,引用源代码部分前面的数字表示行号,对应于源文件里面的行号
我们知道,Android里面的包信息管理、安装和卸载等均是通过android/content/pm/PackageManager.java()这个类来完成的。而获取PackageManager的方式一般是:android/content/Context.getPackageManager()方法获取。
查看Context.java,可以发现Context类是抽象的,getPackageManager()也是抽象的。
/** * Interface to global information about an application environment. This is * an abstract class whose implementation is provided by * the Android system. It * allows access to application-specific resources and classes, as well as * up-calls for application-level operations such as launching activities, * broadcasting and receiving intents, etc. */51 public abstract class Context { ...196 /** Return PackageManager instance to find global package information. */197 public abstract PackageManager getPackageManager();
而Context的具体实现是android/app/ContextImpl.java里面的ContextImpl类,如下所示:
/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */138 class ContextImpl extends Context { ...481 @Override482 public PackageManager getPackageManager() {483 if (mPackageManager != null) {484 return mPackageManager;485 }486487 IPackageManager pm = ActivityThread.getPackageManager();488 if (pm != null) {489 // Doesn't matter if we make more than one instance.490 return (mPackageManager = new ApplicationPackageManager(this, pm));491 }492493 return null;494 }
可以看出,获取到的实际上是android/app/ApplicationPackageManager.java定义的ApplicationPackageManager类的实例。进入ApplicationPackageManager.java,代码如下:
60 /*package*/61 final class ApplicationPackageManager extends PackageManager { ...723 ApplicationPackageManager(ContextImpl context,724 IPackageManager pm) {725 mContext = context;726 mPM = pm;727 } ...934 @Override935 public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,936 String installerPackageName) {937 try {938 mPM.installPackage(packageURI, observer, flags, installerPackageName);939 } catch (RemoteException e) {940 // Should never happen!941 }942 }943944 @Override945 public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,946 int flags, String installerPackageName, Uri verificationURI,947 ManifestDigest manifestDigest) {948 try {949 mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,950 verificationURI, manifestDigest);951 } catch (RemoteException e) {952 // Should never happen!953 }954 }955956 @Override957 public void verifyPendingInstall(int id, int response) {958 try {959 mPM.verifyPendingInstall(id, response);960 } catch (RemoteException e) {961 // Should never happen!962 }963 } ...1226 private final IPackageManager mPM;
进入ApplicationPackageManager,其继承了PackageManager,这里其实采用了组合模式,其实ApplicationPackageManager的installPackage方法内部是调用内部组合变量mPM的installPackage方法,其实其他继承自PackageManager的方法的内部逻辑也都是实际调用了mPM变量的对应方法。而mPM变量是在ApplicationPackageManager的构造方法传入(726行,mPM = pm;),因此回滚到Context.java的487行(IPackageManager pm = ActivityThread.getPackageManager();),这里的pm就是最终执行安装或者其他操作的对象。跟踪下去,android/app/ActivityThread.java:
114 /**115 * This manages the execution of the main thread in an116 * application process, scheduling and executing activities,117 * broadcasts, and other operations on it as the activity118 * manager requests.119 *120 * {@hide}121 */122 public final class ActivityThread { ...1395 public static IPackageManager getPackageManager() {1396 if (sPackageManager != null) {1397 //Slog.v("PackageManager", "returning cur default = " + sPackageManager);1398 return sPackageManager;1399 }1400 IBinder b = ServiceManager.getService("package");1401 //Slog.v("PackageManager", "default service binder = " + b);1402 sPackageManager = IPackageManager.Stub.asInterface(b);1403 //Slog.v("PackageManager", "default service = " + sPackageManager);1404 return sPackageManager;1405 }1406
通过上面代码可以发现,最终返回的IPackageManager的实例对象是通过绑定系统的package服务获取到的,熟悉Android的朋友应该清楚,这实际就是调用PackageManager对应的service来完成。至此,可以明确PackageManager类的安装等等操作实际是通过com/android、server/pm/PackageManagerService.java中定义的类PackageManagerService来完成,其详细代码如下:
140 /**141 * Keep track of all those .apks everywhere.142 * 143 * This is very central to the platform's security; please run the unit144 * tests whenever making modifications here:145 * 146 mmm frameworks/base/tests/AndroidTests147 adb install -r -f out/target/product/passion/data/app/AndroidTests.apk148 adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner149 * 150 * {@hide}151 */152 public class PackageManagerService extends IPackageManager.Stub { ...439 class PackageHandler extends Handler {440 private boolean mBound = false;441 final ArrayList<HandlerParams> mPendingInstalls =442 new ArrayList<HandlerParams>();443444 private boolean connectToService() {445 if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +446 " DefaultContainerService");447 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);448 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);449 if (mContext.bindService(service, mDefContainerConn,450 Context.BIND_AUTO_CREATE)) {451 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);452 mBound = true;453 return true;454 }455 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);456 return false;457 }458459 private void disconnectService() {460 mContainerService = null;461 mBound = false;462 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);463 mContext.unbindService(mDefContainerConn);464 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);465 }466467 PackageHandler(Looper looper) {468 super(looper);469 }470471 public void handleMessage(Message msg) {472 try {473 doHandleMessage(msg);474 } finally {475 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);476 }477 }478 479 void doHandleMessage(Message msg) {480 switch (msg.what) {481 case INIT_COPY: {482 if (DEBUG_INSTALL) Slog.i(TAG, "init_copy");483 HandlerParams params = (HandlerParams) msg.obj;484 int idx = mPendingInstalls.size();485 if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx);486 // If a bind was already initiated we dont really487 // need to do anything. The pending install488 // will be processed later on.489 if (!mBound) {490 // If this is the only one pending we might491 // have to bind to the service again.492 if (!connectToService()) {493 Slog.e(TAG, "Failed to bind to media container service");494 params.serviceError();495 return;496 } else {497 // Once we bind to the service, the first498 // pending request will be processed.499 mPendingInstalls.add(idx, params);500 }501 } else {502 mPendingInstalls.add(idx, params);503 // Already bound to the service. Just make504 // sure we trigger off processing the first request.505 if (idx == 0) {506 mHandler.sendEmptyMessage(MCS_BOUND);507 }508 }509 break;510 }511 case MCS_BOUND: {512 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");513 if (msg.obj != null) {514 mContainerService = (IMediaContainerService) msg.obj;515 }516 if (mContainerService == null) {517 // Something seriously wrong. Bail out518 Slog.e(TAG, "Cannot bind to media container service");519 for (HandlerParams params : mPendingInstalls) {520 mPendingInstalls.remove(0);521 // Indicate service bind error522 params.serviceError();523 }524 mPendingInstalls.clear();525 } else if (mPendingInstalls.size() > 0) {526 HandlerParams params = mPendingInstalls.get(0);527 if (params != null) {528 if (params.startCopy()) {529 // We are done... look for more work or to530 // go idle.531 if (DEBUG_SD_INSTALL) Log.i(TAG,532 "Checking for more work or unbind...");533 // Delete pending install534 if (mPendingInstalls.size() > 0) {535 mPendingInstalls.remove(0);536 }537 if (mPendingInstalls.size() == 0) {538 if (mBound) {539 if (DEBUG_SD_INSTALL) Log.i(TAG,540 "Posting delayed MCS_UNBIND");541 removeMessages(MCS_UNBIND);542 Message ubmsg = obtainMessage(MCS_UNBIND);543 // Unbind after a little delay, to avoid544 // continual thrashing.545 sendMessageDelayed(ubmsg, 10000);546 }547 } else {548 // There are more pending requests in queue.549 // Just post MCS_BOUND message to trigger processing550 // of next pending install.551 if (DEBUG_SD_INSTALL) Log.i(TAG,552 "Posting MCS_BOUND for next woek");553 mHandler.sendEmptyMessage(MCS_BOUND);554 }555 }556 }557 } else {558 // Should never happen ideally.559 Slog.w(TAG, "Empty queue");560 }561 break;562 }563 case MCS_RECONNECT: {564 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");565 if (mPendingInstalls.size() > 0) {566 if (mBound) {567 disconnectService();568 }569 if (!connectToService()) {570 Slog.e(TAG, "Failed to bind to media container service");571 for (HandlerParams params : mPendingInstalls) {572 mPendingInstalls.remove(0);573 // Indicate service bind error574 params.serviceError();575 }576 mPendingInstalls.clear();577 }578 }579 break;580 }581 case MCS_UNBIND: {582 // If there is no actual work left, then time to unbind.583 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");584585 if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {586 if (mBound) {587 if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");588589 disconnectService();590 }591 } else if (mPendingInstalls.size() > 0) {592 // There are more pending requests in queue.593 // Just post MCS_BOUND message to trigger processing594 // of next pending install.595 mHandler.sendEmptyMessage(MCS_BOUND);596 }597598 break;599 }600 case MCS_GIVE_UP: {601 if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");602 mPendingInstalls.remove(0);603 break;604 }605 case SEND_PENDING_BROADCAST: {606 String packages[];607 ArrayList<String> components[];608 int size = 0;609 int uids[];610 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);611 synchronized (mPackages) {612 if (mPendingBroadcasts == null) {613 return;614 }615 size = mPendingBroadcasts.size();616 if (size <= 0) {617 // Nothing to be done. Just return618 return;619 }620 packages = new String[size];621 components = new ArrayList[size];622 uids = new int[size];623 Iterator<HashMap.Entry<String, ArrayList<String>>>624 it = mPendingBroadcasts.entrySet().iterator();625 int i = 0;626 while (it.hasNext() && i < size) {627 HashMap.Entry<String, ArrayList<String>> ent = it.next();628 packages[i] = ent.getKey();629 components[i] = ent.getValue();630 PackageSetting ps = mSettings.mPackages.get(ent.getKey());631 uids[i] = (ps != null) ? ps.userId : -1;632 i++;633 }634 size = i;635 mPendingBroadcasts.clear();636 }637 // Send broadcasts638 for (int i = 0; i < size; i++) {639 sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);640 }641 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);642 break;643 }644 case START_CLEANING_PACKAGE: {645 String packageName = (String)msg.obj;646 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);647 synchronized (mPackages) {648 if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {649 mSettings.mPackagesToBeCleaned.add(packageName);650 }651 }652 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);653 startCleaningPackages();654 } break;655 case POST_INSTALL: {656 if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);657 PostInstallData data = mRunningInstalls.get(msg.arg1);658 mRunningInstalls.delete(msg.arg1);659 boolean deleteOld = false;660661 if (data != null) {662 InstallArgs args = data.args;663 PackageInstalledInfo res = data.res;664665 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {666 res.removedInfo.sendBroadcast(false, true);667 Bundle extras = new Bundle(1);668 extras.putInt(Intent.EXTRA_UID, res.uid);669 final boolean update = res.removedInfo.removedPackage != null;670 if (update) {671 extras.putBoolean(Intent.EXTRA_REPLACING, true);672 }673 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,674 res.pkg.applicationInfo.packageName,675 extras, null, null);676 if (update) {677 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,678 res.pkg.applicationInfo.packageName,679 extras, null, null);680 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,681 null, null,682 res.pkg.applicationInfo.packageName, null);683 }684 if (res.removedInfo.args != null) {685 // Remove the replaced package's older resources safely now686 deleteOld = true;687 }688 }689 // Force a gc to clear up things690 Runtime.getRuntime().gc();691 // We delete after a gc for applications on sdcard.692 if (deleteOld) {693 synchronized (mInstallLock) {694 res.removedInfo.args.doPostDeleteLI(true);695 }696 }697 if (args.observer != null) {698 try {699 args.observer.packageInstalled(res.name, res.returnCode);700 } catch (RemoteException e) {701 Slog.i(TAG, "Observer no longer exists.");702 }703 }704 } else {705 Slog.e(TAG, "Bogus post-install token " + msg.arg1);706 }707 } break;708 case UPDATED_MEDIA_STATUS: {709 if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");710 boolean reportStatus = msg.arg1 == 1;711 boolean doGc = msg.arg2 == 1;712 if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);713 if (doGc) {714 // Force a gc to clear up stale containers.715 Runtime.getRuntime().gc();716 }717 if (msg.obj != null) {718 @SuppressWarnings("unchecked")719 Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;720 if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");721 // Unload containers722 unloadAllContainers(args);723 }724 if (reportStatus) {725 try {726 if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");727 PackageHelper.getMountService().finishMediaUpdate();728 } catch (RemoteException e) {729 Log.e(TAG, "MountService not running?");730 }731 }732 } break;733 case WRITE_SETTINGS: {734 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);735 synchronized (mPackages) {736 removeMessages(WRITE_SETTINGS);737 removeMessages(WRITE_STOPPED_PACKAGES);738 mSettings.writeLPr();739 }740 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);741 } break;742 case WRITE_STOPPED_PACKAGES: {743 Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);744 synchronized (mPackages) {745 removeMessages(WRITE_STOPPED_PACKAGES);746 mSettings.writeStoppedLPr();747 }748 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);749 } break;750 case CHECK_PENDING_VERIFICATION: {751 final int verificationId = msg.arg1;752 final PackageVerificationState state = mPendingVerification.get(verificationId);753754 if (state != null) {755 final InstallArgs args = state.getInstallArgs();756 Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());757 mPendingVerification.remove(verificationId);758759 int ret = PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT;760 processPendingInstall(args, ret);761762 mHandler.sendEmptyMessage(MCS_UNBIND);763 }764765 break;766 }767 case PACKAGE_VERIFIED: {768 final int verificationId = msg.arg1;769770 final PackageVerificationState state = mPendingVerification.get(verificationId);771 if (state == null) {772 Slog.w(TAG, "Invalid verification token " + verificationId + " received");773 break;774 }775776 final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;777778 state.setVerifierResponse(response.callerUid, response.code);779780 if (state.isVerificationComplete()) {781 mPendingVerification.remove(verificationId);782783 final InstallArgs args = state.getInstallArgs();784785 int ret;786 if (state.isInstallAllowed()) {787 ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;788 try {789 ret = args.copyApk(mContainerService, true);790 } catch (RemoteException e) {791 Slog.e(TAG, "Could not contact the ContainerService");792 }793 } else {794 ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;795 }796797 processPendingInstall(args, ret);798799 mHandler.sendEmptyMessage(MCS_UNBIND);800 }801802 break;803 }804 }805 }806 } ... ...831 public static final IPackageManager main(Context context, boolean factoryTest,832 boolean onlyCore) {833 PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);834 ServiceManager.addService("package", m);835 return m;836 } ... ...860 public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {861 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,862 SystemClock.uptimeMillis());863 864 if (mSdkVersion <= 0) {865 Slog.w(TAG, "**** ro.build.version.sdk not set!");866 }867 868 mContext = context;869 mFactoryTest = factoryTest;870 mOnlyCore = onlyCore;871 mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));872 mMetrics = new DisplayMetrics();873 mSettings = new Settings();874 mSettings.addSharedUserLPw("android.uid.system",875 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);876 mSettings.addSharedUserLPw("android.uid.phone",877 MULTIPLE_APPLICATION_UIDS878 ? RADIO_UID : FIRST_APPLICATION_UID,879 ApplicationInfo.FLAG_SYSTEM);880 mSettings.addSharedUserLPw("android.uid.log",881 MULTIPLE_APPLICATION_UIDS882 ? LOG_UID : FIRST_APPLICATION_UID,883 ApplicationInfo.FLAG_SYSTEM);884 mSettings.addSharedUserLPw("android.uid.nfc",885 MULTIPLE_APPLICATION_UIDS886 ? NFC_UID : FIRST_APPLICATION_UID,887 ApplicationInfo.FLAG_SYSTEM);888 889 String separateProcesses = SystemProperties.get("debug.separate_processes");890 if (separateProcesses != null && separateProcesses.length() > 0) {891 if ("*".equals(separateProcesses)) {892 mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;893 mSeparateProcesses = null;894 Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");895 } else {896 mDefParseFlags = 0;897 mSeparateProcesses = separateProcesses.split(",");898 Slog.w(TAG, "Running with debug.separate_processes: "899 + separateProcesses);900 }901 } else {902 mDefParseFlags = 0;903 mSeparateProcesses = null;904 }905 906 mInstaller = new Installer();907 908 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);909 Display d = wm.getDefaultDisplay();910 d.getMetrics(mMetrics);911 912 synchronized (mInstallLock) {913 // writer914 synchronized (mPackages) {915 mHandlerThread.start();916 mHandler = new PackageHandler(mHandlerThread.getLooper());917 918 File dataDir = Environment.getDataDirectory();919 mAppDataDir = new File(dataDir, "data");920 mUserAppDataDir = new File(dataDir, "user");921 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");922 923 mUserManager = new UserManager(mInstaller, mUserAppDataDir);924 925 readPermissions();926 927 mRestoredSettings = mSettings.readLPw();928 long startTime = SystemClock.uptimeMillis();929 930 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,931 startTime);932 933 // Set flag to monitor and not change apk file paths when934 // scanning install directories.935 int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;936 if (mNoDexOpt) {937 Slog.w(TAG, "Running ENG build: no pre-dexopt!");938 scanMode |= SCAN_NO_DEX;939 }940 941 final HashSet<String> libFiles = new HashSet<String>();942 943 mFrameworkDir = new File(Environment.getRootDirectory(), "framework");944 mDalvikCacheDir = new File(dataDir, "dalvik-cache");945 946 boolean didDexOpt = false;947 948 /**949 * Out of paranoia, ensure that everything in the boot class950 * path has been dexed.951 */952 String bootClassPath = System.getProperty("java.boot.class.path");953 if (bootClassPath != null) {954 String[] paths = splitString(bootClassPath, ':');955 for (int i=0; i<paths.length; i++) {956 try {957 if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {958 libFiles.add(paths[i]);959 mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);960 didDexOpt = true;961 }962 } catch (FileNotFoundException e) {963 Slog.w(TAG, "Boot class path not found: " + paths[i]);964 } catch (IOException e) {965 Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "966 + e.getMessage());967 }968 }969 } else {970 Slog.w(TAG, "No BOOTCLASSPATH found!");971 }972 973 /**974 * Also ensure all external libraries have had dexopt run on them.975 */976 if (mSharedLibraries.size() > 0) {977 Iterator<String> libs = mSharedLibraries.values().iterator();978 while (libs.hasNext()) {979 String lib = libs.next();980 try {981 if (dalvik.system.DexFile.isDexOptNeeded(lib)) {982 libFiles.add(lib);983 mInstaller.dexopt(lib, Process.SYSTEM_UID, true);984 didDexOpt = true;985 }986 } catch (FileNotFoundException e) {987 Slog.w(TAG, "Library not found: " + lib);988 } catch (IOException e) {989 Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "990 + e.getMessage());991 }992 }993 }994 995 // Gross hack for now: we know this file doesn't contain any996 // code, so don't dexopt it to avoid the resulting log spew.997 libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");998 999 /**1000 * And there are a number of commands implemented in Java, which1001 * we currently need to do the dexopt on so that they can be1002 * run from a non-root shell.1003 */1004 String[] frameworkFiles = mFrameworkDir.list();1005 if (frameworkFiles != null) {1006 for (int i=0; i<frameworkFiles.length; i++) {1007 File libPath = new File(mFrameworkDir, frameworkFiles[i]);1008 String path = libPath.getPath();1009 // Skip the file if we alrady did it.1010 if (libFiles.contains(path)) {1011 continue;1012 }1013 // Skip the file if it is not a type we want to dexopt.1014 if (!path.endsWith(".apk") && !path.endsWith(".jar")) {1015 continue;1016 }1017 try {1018 if (dalvik.system.DexFile.isDexOptNeeded(path)) {1019 mInstaller.dexopt(path, Process.SYSTEM_UID, true);1020 didDexOpt = true;1021 }1022 } catch (FileNotFoundException e) {1023 Slog.w(TAG, "Jar not found: " + path);1024 } catch (IOException e) {1025 Slog.w(TAG, "Exception reading jar: " + path, e);1026 }1027 }1028 }10291030 if (didDexOpt) {1031 // If we had to do a dexopt of one of the previous1032 // things, then something on the system has changed.1033 // Consider this significant, and wipe away all other1034 // existing dexopt files to ensure we don't leave any1035 // dangling around.1036 String[] files = mDalvikCacheDir.list();1037 if (files != null) {1038 for (int i=0; i<files.length; i++) {1039 String fn = files[i];1040 if (fn.startsWith("data@app@")1041 || fn.startsWith("data@app-private@")) {1042 Slog.i(TAG, "Pruning dalvik file: " + fn);1043 (new File(mDalvikCacheDir, fn)).delete();1044 }1045 }1046 }1047 }10481049 // Find base frameworks (resource packages without code).1050 mFrameworkInstallObserver = new AppDirObserver(1051 mFrameworkDir.getPath(), OBSERVER_EVENTS, true);1052 mFrameworkInstallObserver.startWatching();1053 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM1054 | PackageParser.PARSE_IS_SYSTEM_DIR,1055 scanMode | SCAN_NO_DEX, 0);1056 1057 // Collect all system packages.1058 mSystemAppDir = new File(Environment.getRootDirectory(), "app");1059 mSystemInstallObserver = new AppDirObserver(1060 mSystemAppDir.getPath(), OBSERVER_EVENTS, true);1061 mSystemInstallObserver.startWatching();1062 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM1063 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);1064 1065 // Collect all vendor packages.1066 mVendorAppDir = new File("/vendor/app");1067 mVendorInstallObserver = new AppDirObserver(1068 mVendorAppDir.getPath(), OBSERVER_EVENTS, true);1069 mVendorInstallObserver.startWatching();1070 scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM1071 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);10721073 if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");1074 mInstaller.moveFiles();10751076 // Prune any system packages that no longer exist.1077 if (!mOnlyCore) {1078 Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();1079 while (psit.hasNext()) {1080 PackageSetting ps = psit.next();1081 if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 01082 && !mPackages.containsKey(ps.name)1083 && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {1084 psit.remove();1085 String msg = "System package " + ps.name1086 + " no longer exists; wiping its data";1087 reportSettingsProblem(Log.WARN, msg);1088 mInstaller.remove(ps.name, 0);1089 mUserManager.removePackageForAllUsers(ps.name);1090 }1091 }1092 }1093 1094 mAppInstallDir = new File(dataDir, "app");1095 //look for any incomplete package installations1096 ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();1097 //clean up list1098 for(int i = 0; i < deletePkgsList.size(); i++) {1099 //clean up here1100 cleanupInstallFailedPackage(deletePkgsList.get(i));1101 }1102 //delete tmp files1103 deleteTempPackageFiles();11041105 if (!mOnlyCore) {1106 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,1107 SystemClock.uptimeMillis());1108 mAppInstallObserver = new AppDirObserver(1109 mAppInstallDir.getPath(), OBSERVER_EVENTS, false);1110 mAppInstallObserver.startWatching();1111 scanDirLI(mAppInstallDir, 0, scanMode, 0);1112 1113 mDrmAppInstallObserver = new AppDirObserver(1114 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);1115 mDrmAppInstallObserver.startWatching();1116 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,1117 scanMode, 0);1118 } else {1119 mAppInstallObserver = null;1120 mDrmAppInstallObserver = null;1121 }11221123 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,1124 SystemClock.uptimeMillis());1125 Slog.i(TAG, "Time to scan packages: "1126 + ((SystemClock.uptimeMillis()-startTime)/1000f)1127 + " seconds");11281129 // If the platform SDK has changed since the last time we booted,1130 // we need to re-grant app permission to catch any new ones that1131 // appear. This is really a hack, and means that apps can in some1132 // cases get permissions that the user didn't initially explicitly1133 // allow... it would be nice to have some better way to handle1134 // this situation.1135 final boolean regrantPermissions = mSettings.mInternalSdkPlatform1136 != mSdkVersion;1137 if (regrantPermissions) Slog.i(TAG, "Platform changed from "1138 + mSettings.mInternalSdkPlatform + " to " + mSdkVersion1139 + "; regranting permissions for internal storage");1140 mSettings.mInternalSdkPlatform = mSdkVersion;1141 1142 updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);11431144 // can downgrade to reader1145 mSettings.writeLPr();11461147 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,1148 SystemClock.uptimeMillis());11491150 // Now after opening every single application zip, make sure they1151 // are all flushed. Not really needed, but keeps things nice and1152 // tidy.1153 Runtime.getRuntime().gc();11541155 mRequiredVerifierPackage = getRequiredVerifierLPr();1156 } // synchronized (mPackages)1157 } // synchronized (mInstallLock)1158 } ...
仔细分析上述代码,主要分两个部分:PackageManagerService的构造方法(启动流程)(860-1158行)、PackageHandler的逻辑(439-806行)。PackageManagerService是在系统启动阶段由systemserver启动的一个java层服务,用来管理/system/framework,/system/app,/data/app,/data/app-private等目录下的apk文件,PackageManagerService的启动流程主要包括:
以下是PackageManagerService主要的工作内容:
- 建立java层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现;
- 建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息;
解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系统支持的各种硬件模块的feature.主要工作:
(1)建立底层user ids和group ids 同上层permissions之间的映射;可以指定一个权限与几个组ID对应。当一个APK被授予这个权限时,它也同时属于这几个组。
(2)给一些底层用户分配权限,如给shell授予各种permission权限;把一个权限赋予一个UID,当进程使用这个UID运行时,就具备了这个权限。
(3) library,系统增加的一些应用需要link的扩展jar库;
(4) feature,系统每增加一个硬件,都要添加相应的feature.将解析结果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等几个集合中供系统查询和权限配置使用
- 检查/data/system/packages.xml是否存在,这个文件是在解析apk时由writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。
- 检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要的则通过dexopt进行优化;
- 启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。当有add event时调用scanPackageLI(File , int , int)处理;当有remove event时调用removePackageLI()处理;
- 对于以上几个目录下的apk逐个解析,主要是解析每个apk的AndroidMa-nifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息,并将每个apk的配置信息添加到全局列表进行管理。调用installer.install()进行安装工作,检查apk里的dex文件是否需要再优化,如果需要优化则通过辅助工具dexopt进行优化处理;将解析出的componet添加到pkg的对应列表里;对apk进行签名和证书校验,进行完整性验证。
将解析的每个apk的信息保存到packages.xml和packages.list文件里,packages.list记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)。
开机安装过程代码解析
有了上面的认识,接下来分析安装的过程就比较轻松了(均围绕PackageManagerService.java展开)。开机安装过程的代码流程如下:
扫描各目录(/system/framework、/system/app、/vendor/app、/data/app/、/data/app-private)下的jar包或安装包:
a.扫描安装“/system/framework”目录下的jar包(1049-1055行);
b.扫描安装系统/system/app的应用程序(1057-1063行);
c.制造商的目录下/vendor/app应用包(1065-1071行);
d.扫描“/data/app”目录,即用户安装的第三方应用(1108-1111行);
e.扫描” data\app-private”目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保护的视频是使用DRM保护的文件)(1113-1117行)。
扫描目录关键方法的代码清单:
2732 private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {2733 String[] files = dir.list();2734 if (files == null) {2735 Log.d(TAG, "No files in app dir " + dir);2736 return;2737 }27382739 if (DEBUG_PACKAGE_SCANNING) {2740 Log.d(TAG, "Scanning app dir " + dir);2741 }27422743 int i;2744 for (i=0; i<files.length; i++) {2745 File file = new File(dir, files[i]);2746 if (!isPackageFilename(files[i])) {2747 // Ignore entries which are not apk's2748 continue;2749 }2750 PackageParser.Package pkg = scanPackageLI(file,2751 flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);2752 // Don't mess around with apps in system partition.2753 if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&2754 mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {2755 // Delete the apk2756 Slog.w(TAG, "Cleaning up failed install of " + file);2757 file.delete();2758 }2759 }2760 }
从上面扫描方法的代码中可以看出实质是调用了scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime) ,其代码在2814-2923行定义。分析其代码,发现最终实质是调用scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime)。而后者这个方法代码定义在3106-3905行之间,前面一段主要是各种校验和检查,关键部分代码为:3495 //invoke installer to do the actual installation3496 int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,3497 pkg.applicationInfo.uid);3498 if (ret < 0) {3499 // Error from installer3500 mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;3501 return null;3502 }3503 // Create data directories for all users3504 mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
不难看出,mInstaller.install是真正执行安装之处。而看看mInstaller的定义:
258 // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages259 // LOCK HELD. Can be called with mInstallLock held.260 final Installer mInstaller;
查看com/android/server/pm/Installer.java,其代码相对比较少,分析起来比较容易,其install方法调用了execute(String cmd)方法,而execute(String cmd)又调用transaction(cmd):
148 private synchronized String transaction(String cmd) {149 if (!connect()) {150 Slog.e(TAG, "connection failed");151 return "-1";152 }153154 if (!writeCommand(cmd)) {155 /*156 * If installd died and restarted in the background (unlikely but157 * possible) we'll fail on the next write (this one). Try to158 * reconnect and write the command one more time before giving up.159 */160 Slog.e(TAG, "write command failed? reconnect!");161 if (!connect() || !writeCommand(cmd)) {162 return "-1";163 }164 }165 if (LOCAL_DEBUG) {166 Slog.i(TAG, "send: '" + cmd + "'");167 }168 if (readReply()) {169 String s = new String(buf, 0, buflen);170 if (LOCAL_DEBUG) {171 Slog.i(TAG, "recv: '" + s + "'");172 }173 return s;174 } else {175 if (LOCAL_DEBUG) {176 Slog.i(TAG, "fail");177 }178 return "-1";179 }180 }
首先是149行的connect方法:
43 private boolean connect() {44 if (mSocket != null) {45 return true;46 }47 Slog.i(TAG, "connecting...");48 try {49 mSocket = new LocalSocket();5051 LocalSocketAddress address = new LocalSocketAddress("installd",52 LocalSocketAddress.Namespace.RESERVED);5354 mSocket.connect(address);5556 mIn = mSocket.getInputStream();57 mOut = mSocket.getOutputStream();58 } catch (IOException ex) {59 disconnect();60 return false;61 }62 return true;63 }
到这里已经很清楚了,实则是通过socket连接到本地方法,即指挥installd在C语言的文件中完成工作。
网络下载应用安装过程代码解析
当从网络上下载APK完成后,自动调用Packagemanager的安装方法installPackage。如前面所述,最终是调用PackageManagerService的installPackage方法。如下:
4882 /* Called when a downloaded package installation has been confirmed by the user */4883 public void installPackage(4884 final Uri packageURI, final IPackageInstallObserver observer, final int flags) {4885 installPackage(packageURI, observer, flags, null);4886 }48874888 /* Called when a downloaded package installation has been confirmed by the user */4889 public void installPackage(4890 final Uri packageURI, final IPackageInstallObserver observer, final int flags,4891 final String installerPackageName) {4892 installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,4893 null);4894 }48954896 @Override4897 public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,4898 int flags, String installerPackageName, Uri verificationURI,4899 ManifestDigest manifestDigest) {4900 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);49014902 final int uid = Binder.getCallingUid();49034904 final int filteredFlags;49054906 if (uid == Process.SHELL_UID || uid == 0) {4907 if (DEBUG_INSTALL) {4908 Slog.v(TAG, "Install from ADB");4909 }4910 filteredFlags = flags | PackageManager.INSTALL_FROM_ADB;4911 } else {4912 filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB;4913 }49144915 final Message msg = mHandler.obtainMessage(INIT_COPY);4916 msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,4917 verificationURI, manifestDigest);4918 mHandler.sendMessage(msg);4919 }
可以发现,调用之后进入到4945-4918行,通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法。在前面章节已经介绍了PackageManagerService中PackageHandler的定义。HandleMessage()把信息发给doHandleMessage()方法,方法中用switch语句进行判定传来Message进行分支处理。这里传入的消息的msg.what是INIT_COPY,进入到INIT_COPY分支,可以看到,一旦成功绑定了com.android.defcontainer.DefaultContainerService服务,则进入506行–mHandler.sendEmptyMessage(MCS_BOUND);此时进入doHandleMessage方法的switch语句的MCS_BOUND分支,跟踪进去,关键代码:
528 if (params.startCopy()) {
params是PackageManagerService中内部抽象类HandlerParams的子类InstallParams(参见上面4916行)的实例,HandlerParams代码清单:
5202 private abstract class HandlerParams {5203 private static final int MAX_RETRIES = 4;52045205 /**5206 * Number of times startCopy() has been attempted and had a non-fatal5207 * error.5208 */5209 private int mRetries = 0;52105211 final boolean startCopy() {5212 boolean res;5213 try {5214 if (DEBUG_INSTALL) Slog.i(TAG, "startCopy");52155216 if (++mRetries > MAX_RETRIES) {5217 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");5218 mHandler.sendEmptyMessage(MCS_GIVE_UP);5219 handleServiceError();5220 return false;5221 } else {5222 handleStartCopy();5223 res = true;5224 }5225 } catch (RemoteException e) {5226 if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");5227 mHandler.sendEmptyMessage(MCS_RECONNECT);5228 res = false;5229 }5230 handleReturnCode();5231 return res;5232 }52335234 final void serviceError() {5235 if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");5236 handleServiceError();5237 handleReturnCode();5238 }52395240 abstract void handleStartCopy() throws RemoteException;5241 abstract void handleServiceError();5242 abstract void handleReturnCode();5243 }5244
startCopy()方法中关键代码是先调用handleStartCopy()方法,再调用handleReturnCode()方法(由子类实现,这里即InstallParams的handleStartCopy()方法和handleReturnCode()方法),handleStartCopy()代码较多,但是前面基本是校验相关逻辑,关键部分在:
5557 } else {5558 /*5559 * No package verification is enabled, so immediately start5560 * the remote call to initiate copy using temporary file.5561 */5562 ret = args.copyApk(mContainerService, true);5563 }
args是抽象类InstallArgs的子类实现类SdInstallArgs(安装在SD卡时)或FileInstallArgs(非安装在)的实例对象,copyApk是负责将下载的APK文件copy到/data/app目录下。而handleReturnCode方法如下:
5569 @Override5570 void handleReturnCode() {5571 // If mArgs is null, then MCS couldn't be reached. When it5572 // reconnects, it will try again to install. At that point, this5573 // will succeed.5574 if (mArgs != null) {5575 processPendingInstall(mArgs, mRet);5576 }5577 }
这时可以清楚的看见processPendingInstall()被调用。其代码为:
5129 private void processPendingInstall(final InstallArgs args, final int currentStatus) {5130 // Queue up an async operation since the package installation may take a little while.5131 mHandler.post(new Runnable() {5132 public void run() {5133 mHandler.removeCallbacks(this);5134 // Result object to be returned5135 PackageInstalledInfo res = new PackageInstalledInfo();5136 res.returnCode = currentStatus;5137 res.uid = -1;5138 res.pkg = null;5139 res.removedInfo = new PackageRemovedInfo();5140 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {5141 args.doPreInstall(res.returnCode);5142 synchronized (mInstallLock) {5143 installPackageLI(args, true, res);5144 }5145 args.doPostInstall(res.returnCode);5146 }51475148 // A restore should be performed at this point if (a) the install5149 // succeeded, (b) the operation is not an update, and (c) the new5150 // package has a backupAgent defined.5151 final boolean update = res.removedInfo.removedPackage != null;5152 boolean doRestore = (!update5153 && res.pkg != null5154 && res.pkg.applicationInfo.backupAgentName != null);51555156 // Set up the post-install work request bookkeeping. This will be used5157 // and cleaned up by the post-install event handling regardless of whether5158 // there's a restore pass performed. Token values are >= 1.5159 int token;5160 if (mNextInstallToken < 0) mNextInstallToken = 1;5161 token = mNextInstallToken++;51625163 PostInstallData data = new PostInstallData(args, res);5164 mRunningInstalls.put(token, data);5165 if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);51665167 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {5168 // Pass responsibility to the Backup Manager. It will perform a5169 // restore if appropriate, then pass responsibility back to the5170 // Package Manager to run the post-install observer callbacks5171 // and broadcasts.5172 IBackupManager bm = IBackupManager.Stub.asInterface(5173 ServiceManager.getService(Context.BACKUP_SERVICE));5174 if (bm != null) {5175 if (DEBUG_INSTALL) Log.v(TAG, "token " + token5176 + " to BM for possible restore");5177 try {5178 bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);5179 } catch (RemoteException e) {5180 // can't happen; the backup manager is local5181 } catch (Exception e) {5182 Slog.e(TAG, "Exception trying to enqueue restore", e);5183 doRestore = false;5184 }5185 } else {5186 Slog.e(TAG, "Backup Manager not found!");5187 doRestore = false;5188 }5189 }51905191 if (!doRestore) {5192 // No restore possible, or the Backup Manager was mysteriously not5193 // available -- just fire the post-install work request directly.5194 if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);5195 Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);5196 mHandler.sendMessage(msg);5197 }5198 }5199 });5200 }
关键部分代码为5140-5146行:
5140 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {5141 args.doPreInstall(res.returnCode);5142 synchronized (mInstallLock) {5143 installPackageLI(args, true, res);5144 }5145 args.doPostInstall(res.returnCode);5146 }
这里installPackageLI(args, true, res)的代码为:
5573 private void installPackageLI(InstallArgs args,5574 boolean newInstall, PackageInstalledInfo res) {5575 int pFlags = args.flags;5576 String installerPackageName = args.installerPackageName;5577 File tmpPackageFile = new File(args.getCodePath());5578 boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);5579 boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);5580 boolean replace = false;5581 int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE5582 | (newInstall ? SCAN_NEW_INSTALL : 0);5583 // Result object to be returned5584 res.returnCode = PackageManager.INSTALL_SUCCEEDED;55855586 // Retrieve PackageSettings and parse package5587 int parseFlags = PackageParser.PARSE_CHATTY |5588 (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |5589 (onSd ? PackageParser.PARSE_ON_SDCARD : 0);5590 parseFlags |= mDefParseFlags;5591 PackageParser pp = new PackageParser(tmpPackageFile.getPath());5592 pp.setSeparateProcesses(mSeparateProcesses);5593 final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,5594 null, mMetrics, parseFlags);5595 if (pkg == null) {5596 res.returnCode = pp.getParseError();5597 return;5598 }5599 String pkgName = res.name = pkg.packageName;5600 if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {5601 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {5602 res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;5603 return;5604 }5605 }5606 if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {5607 res.returnCode = pp.getParseError();5608 return;5609 }56105611 /* If the installer passed in a manifest digest, compare it now. */5612 if (args.manifestDigest != null) {5613 if (DEBUG_INSTALL) {5614 final String parsedManifest = pkg.manifestDigest == null ? "null"5615 : pkg.manifestDigest.toString();5616 Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "5617 + parsedManifest);5618 }56195620 if (!args.manifestDigest.equals(pkg.manifestDigest)) {5621 res.returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;5622 return;5623 }5624 } else if (DEBUG_INSTALL) {5625 final String parsedManifest = pkg.manifestDigest == null5626 ? "null" : pkg.manifestDigest.toString();5627 Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);5628 }56295630 // Get rid of all references to package scan path via parser.5631 pp = null;5632 String oldCodePath = null;5633 boolean systemApp = false;5634 synchronized (mPackages) {5635 // Check if installing already existing package5636 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {5637 String oldName = mSettings.mRenamedPackages.get(pkgName);5638 if (pkg.mOriginalPackages != null5639 && pkg.mOriginalPackages.contains(oldName)5640 && mPackages.containsKey(oldName)) {5641 // This package is derived from an original package,5642 // and this device has been updating from that original5643 // name. We must continue using the original name, so5644 // rename the new package here.5645 pkg.setPackageName(oldName);5646 pkgName = pkg.packageName;5647 replace = true;5648 } else if (mPackages.containsKey(pkgName)) {5649 // This package, under its official name, already exists5650 // on the device; we should replace it.5651 replace = true;5652 }5653 }5654 PackageSetting ps = mSettings.mPackages.get(pkgName);5655 if (ps != null) {5656 oldCodePath = mSettings.mPackages.get(pkgName).codePathString;5657 if (ps.pkg != null && ps.pkg.applicationInfo != null) {5658 systemApp = (ps.pkg.applicationInfo.flags &5659 ApplicationInfo.FLAG_SYSTEM) != 0;5660 }5661 }5662 }56635664 if (systemApp && onSd) {5665 // Disable updates to system apps on sdcard5666 Slog.w(TAG, "Cannot install updates to system apps on sdcard");5667 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;5668 return;5669 }56705671 if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {5672 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;5673 return;5674 }5675 // Set application objects path explicitly after the rename5676 setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());5677 pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();5678 if (replace) {5679 replacePackageLI(pkg, parseFlags, scanMode,5680 installerPackageName, res);5681 } else {5682 installNewPackageLI(pkg, parseFlags, scanMode,5683 installerPackageName,res);5684 }5685 }
关键部分在最后的5678-5684行,如果是重复安装则调用replacePackageLI,负责调用installNewPackageLI(pkg, parseFlags, scanMode,installerPackageName,res);这里以installNewPackageLI为例:
6259 /*6260 * Install a non-existing package.6261 */6262 private void installNewPackageLI(PackageParser.Package pkg,6263 int parseFlags,6264 int scanMode,6265 String installerPackageName, PackageInstalledInfo res) {6266 // Remember this for later, in case we need to rollback this install6267 String pkgName = pkg.packageName;62686269 boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();6270 res.name = pkgName;6271 synchronized(mPackages) {6272 if (mSettings.mRenamedPackages.containsKey(pkgName)) {6273 // A package with the same name is already installed, though6274 // it has been renamed to an older name. The package we6275 // are trying to install should be installed as an update to6276 // the existing one, but that has not been requested, so bail.6277 Slog.w(TAG, "Attempt to re-install " + pkgName6278 + " without first uninstalling package running as "6279 + mSettings.mRenamedPackages.get(pkgName));6280 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;6281 return;6282 }6283 if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {6284 // Don't allow installation over an existing package with the same name.6285 Slog.w(TAG, "Attempt to re-install " + pkgName6286 + " without first uninstalling.");6287 res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;6288 return;6289 }6290 }6291 mLastScanError = PackageManager.INSTALL_SUCCEEDED;6292 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,6293 System.currentTimeMillis());6294 if (newPackage == null) {6295 Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);6296 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {6297 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;6298 }6299 } else {6300 updateSettingsLI(newPackage,6301 installerPackageName,6302 res);6303 // delete the partially installed application. the data directory will have to be6304 // restored if it was already existing6305 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {6306 // remove package from internal structures. Note that we want deletePackageX to6307 // delete the package data and cache directories that it created in6308 // scanPackageLocked, unless those directories existed before we even tried to6309 // install.6310 deletePackageLI(6311 pkgName, false,6312 dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,6313 res.removedInfo, true);6314 }6315 }6316 }
关键代码部分为:
6292 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,6293 System.currentTimeMillis());
最终回到了和开机安装一样的地方,与开机方式安装调用统一方法scanPackageLI。后续步骤则完全一致了。
从ADB工具安装过程代码解析
通过adb命令方式,真实的入口其实是com/android/commands/pm/Pm.java,其中showUsage方法为使用方法说明:
1111 private static void showUsage() {1112 System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]");1113 System.err.println(" pm list permission-groups");1114 System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");1115 System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");1116 System.err.println(" pm list features");1117 System.err.println(" pm list libraries");1118 System.err.println(" pm path PACKAGE");1119 System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");1120 System.err.println(" pm uninstall [-k] PACKAGE");1121 System.err.println(" pm clear PACKAGE");1122 System.err.println(" pm enable PACKAGE_OR_COMPONENT");1123 System.err.println(" pm disable PACKAGE_OR_COMPONENT");1124 System.err.println(" pm disable-user PACKAGE_OR_COMPONENT");1125 System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");1126 System.err.println(" pm get-install-location");1127 System.err.println(" pm createUser USER_NAME");1128 System.err.println(" pm removeUser USER_ID");1129 System.err.println("");1130 System.err.println("pm list packages: prints all packages, optionally only");1131 System.err.println(" those whose package name contains the text in FILTER. Options:");1132 System.err.println(" -f: see their associated file.");1133 System.err.println(" -d: filter to only show disbled packages.");1134 System.err.println(" -e: filter to only show enabled packages.");1135 System.err.println(" -s: filter to only show system packages.");1136 System.err.println(" -3: filter to only show third party packages.");1137 System.err.println(" -u: also include uninstalled packages."); ...
而安装时调用的方法即runInstall(),方法内的关键代码为:
798 PackageInstallObserver obs = new PackageInstallObserver();799 try {800 mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName,801 verificationURI, null);802803 synchronized (obs) {804 while (!obs.finished) {805 try {806 obs.wait();807 } catch (InterruptedException e) {808 }809 }810 if (obs.result == PackageManager.INSTALL_SUCCEEDED) {811 System.out.println("Success");812 } else {813 System.err.println("Failure ["814 + installFailureToString(obs.result)815 + "]");816 }817 }818 } catch (RemoteException e) {819 System.err.println(e.toString());820 System.err.println(PM_NOT_RUNNING_ERR);821 }
可以看出,实则调用mPm变量的installPackageWithVerification方法。mPm变量为IPackageManager接口的实现类的对象,通过78行,不难发现,其实又是绑定远程的PackageManagerService来完成具体的操作,此时就回到与网络下载的地方了,后续步骤可参加网络下载部分的分析。
53 public final class Pm {54 IPackageManager mPm;5556 private WeakHashMap<String, Resources> mResourceCache57 = new WeakHashMap<String, Resources>();5859 private String[] mArgs;60 private int mNextArg;61 private String mCurArgData;6263 private static final String PM_NOT_RUNNING_ERR =64 "Error: Could not access the Package Manager. Is the system running?";65 private static final int ROOT_UID = 0;6667 public static void main(String[] args) {68 new Pm().run(args);69 }7071 public void run(String[] args) {72 boolean validCommand = false;73 if (args.length < 1) {74 showUsage();75 return;76 }7778 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));79 if (mPm == null) {80 System.err.println(PM_NOT_RUNNING_ERR);81 return;82 }
通过第三方应用从SD卡安装的过程代码分析
这其实相当于在PackagManager之上提供一个更便捷的方式给用户安装APK,系统上层的源码中有一个类(Activity)com/android/packageinstaller/PackageInstallerActivity.java,通过它可以便捷地使UI方式安装APK。PackageInstallerActivity的oncreate方法如下(本文的采用的版本可能与读者的版本不同,所以行号和代码细节会有差异,请注意):
235 @Override236 protected void onCreate(Bundle icicle) {237 super.onCreate(icicle);238 //get intent information239 final Intent intent = getIntent();240 mPackageURI = intent.getData();241 mPm = getPackageManager();242 mPkgInfo = PackageUtil.getPackageInfo(mPackageURI);243 244 // Check for parse errors245 if(mPkgInfo == null) {246 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");247 showDialogInner(DLG_PACKAGE_ERROR);248 return;249 }250 251 //set view252 requestWindowFeature(Window.FEATURE_NO_TITLE);253 setContentView(R.layout.install_start);254 mInstallConfirm = findViewById(R.id.install_confirm_panel);255 mInstallConfirm.setVisibility(View.INVISIBLE);256 PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this,257 mPkgInfo.applicationInfo, mPackageURI);258 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);259 //check setting260 if(!isInstallingUnknownAppsAllowed()) {261 //ask user to enable setting first262 showDialogInner(DLG_UNKNOWN_APPS);263 return;264 }265 initiateInstall();266 }
如265行所示,进入initiateInstall方法,跟踪可以发现,又进入startInstallConfirm()方法,这主要是弹出对话框,让用户确认是否安装,如果确认,那么即进入:
273 public void onClick(View v) {274 if(v == mOk) {275 // Start subactivity to actually install the application276 Intent newIntent = new Intent();277 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,278 mPkgInfo.applicationInfo);279 newIntent.setData(mPackageURI);280 newIntent.setClass(this, InstallAppProgress.class);281 String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);282 if (installerPackageName != null) {283 newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);284 }285 if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);286 startActivity(newIntent);287 finish();288 } else if(v == mCancel) {289 // Cancel and finish290 finish();291 }292 }
确认后,打开新的activity:InstallAppProgress,com/android/packageinstaller/InstallAppProgress.java的关键代码:
126 @Override127 public void onCreate(Bundle icicle) {128 super.onCreate(icicle);129 Intent intent = getIntent();130 mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);131 mPackageURI = intent.getData();132 initView();133 } ...176 public void initView() {177 requestWindowFeature(Window.FEATURE_NO_TITLE);178 setContentView(R.layout.op_progress);179 int installFlags = 0;180 PackageManager pm = getPackageManager();181 try {182 PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, 183 PackageManager.GET_UNINSTALLED_PACKAGES);184 if(pi != null) {185 installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;186 }187 } catch (NameNotFoundException e) {188 }189 if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {190 Log.w(TAG, "Replacing package:" + mAppInfo.packageName);191 }192 PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,193 mPackageURI);194 mLabel = as.label;195 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);196 mStatusTextView = (TextView)findViewById(R.id.center_text);197 mStatusTextView.setText(R.string.installing);198 mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);199 mProgressBar.setIndeterminate(true);200 // Hide button till progress is being displayed201 mOkPanel = (View)findViewById(R.id.buttons_panel);202 mDoneButton = (Button)findViewById(R.id.done_button);203 mLaunchButton = (Button)findViewById(R.id.launch_button);204 mOkPanel.setVisibility(View.INVISIBLE);205206 String installerPackageName = getIntent().getStringExtra(207 Intent.EXTRA_INSTALLER_PACKAGE_NAME);208 PackageInstallObserver observer = new PackageInstallObserver();209 pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);210 }
如上所示,209行则是执行安装的地方,不难发现,这里是pm对象在180行获取,到这里,又回到和网络下载一样的地方了,后续步骤可以参见网络下载安装部分解析。
总结
- 安装和卸载都是通过PackageManager,实质上是实现了PackageManager的远程服务PackageManagerService来完成具体的操作,所有细节和逻辑均可以在PackageManagerService中跟踪查看;
- 所有安装方式殊途同归,最终就回到PackageManagerService中,然后调用底层本地代码的installd来完成。
- Android安装APK详解
- android安装apk流程详解
- Android APK安装过程及原理详解
- Android APK 安装过程及原理详解
- Android APK安装过程及原理详解
- Android下pm 命令详解 - 安装APK
- APK安装详解
- Android 下载APK 安装APK 打开APK
- Android 下载APK 安装APK 打开APK
- Android 下载APK 安装APK 打开APK
- Android 下载APK 安装APK 打开APK
- Apk文件如何安装到Android模拟器的方法详解
- Android——APK 安装过程 及 原理 详解
- Android下pm 命令详解 - 安装/卸载/APK等
- 【SealDEV 倾情奉献】Android APK 安装过程详解
- 【SealDEV 倾情奉献】Android APK 安装过程详解
- Android APK反编译详解
- Android APK反编译详解
- Java线上应用故障排查之二:高内存占用
- rsync+inotify-tools实时同步真正可用版
- Android onNewIntent()需要注意的一些问题
- day10 ARM伪指令、ARM混合调用
- day11 ARM混合调用案例、ARM核 异常处理流程、软件处理异常
- Android安装APK详解
- 利用serializable将对象保存到本地
- 数据结构与算法汇总
- unity c#调用c++ dll相关技术细节整理
- jquery与JavaScript部分使用区别
- WMI技术介绍和应用——WMI概述
- ESC/POS协议打印机工具类(java)
- js匹配正则
- 创建守护进程