01-APP的安装过程
Android应用程序安装有四种方式,分别如下:
- 系统启动时安装,没有安装界面
- 第三方应用安装,有安装界面,也是我们最熟悉的方式
- ADB命令安装,没有安装界面
- 通过Google Play市场安装,没有安装界面

虽然安装方式不同,但是最后四种方式都是通过PackageManagerService服务来完成应用程序的安装。而PackageManagerService服务则通过与Installd服务通信,发送具体的指令来执行应用程序的安装、卸载等工作。它们的关系如下图所示:
public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }
应用程序在安装时涉及到如下几个重要目录:
system/app | 系统应用程序的目录 |
data/app | 用户程序安装的目录 |
data/data | 存放应用程序数据的目录 |
data/dalvik-cache | 存放的是经过优化的dex文件 |
1.1 系统启动时安装
系统启动时安装APK的函数关系图如下:

1.1.1 PackageManagerService简介
应用程序管理服务PackageManagerService是Android系统的核心服务之一,在系统启动的时候由SystemServer组件负责启动起来。PackageManagerService用于管理系统中的所有安装包信息以及应用程序的安装和卸载,但是实际应用程序的安装卸载并不是由PackageManagerService亲自完成,而是通过socket通信,PackageManagerService来访问installd服务来实现应用程序的安装和卸载。
SystemServer关键代码如下:
SystemServer.java位置:/frameworks/base/services/java/com/android/server/SystemServer.java。
public class SystemServer { ... /** * Called to initialize native system services. */ private static native void nativeInit(); public static void main(String[] args) { ... System.loadLibrary("android_servers"); Slog.i(TAG, "Entered the Android system server!"); // Initialize native services. nativeInit(); // This used to be its own separate thread, but now it is // just the loop we run on the main thread. ServerThread thr = new ServerThread(); thr.initAndLoop(); } }
SystemServer在main函数中创建ServerThread类对象来启动PackageManagerService。关键代码如下:
class ServerThread { private static final String TAG = "SystemServer"; …… ContentResolver mContentResolver; …… public void initAndLoop() { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); Looper.prepareMainLooper(); …… boolean onlyCore = false; boolean firstBoot = false; …… try { Slog.i(TAG, "Display Manager"); display = new DisplayManagerService(context, wmHandler); ServiceManager.addService(Context.DISPLAY_SERVICE, display, true); Slog.i(TAG, "Telephony Registry"); telephonyRegistry = new TelephonyRegistry(context); ServiceManager.addService("telephony.registry", telephonyRegistry); Slog.i(TAG, "Scheduling Policy"); ServiceManager.addService("scheduling_policy", new SchedulingPolicyService()); AttributeCache.init(context); if (!display.waitForDefaultDisplay()) { reportWtf("Timeout waiting for default display to be initialized.", new Throwable()); } Slog.i(TAG, "Package Manager"); // 处于加密状态时,紧解析核心应用 String cryptState = SystemProperties.get("vold.decrypt"); if (ENCRYPTING_STATE.equals(cryptState)) { Slog.w(TAG, "Detected encryption in progress - only parsing core apps"); onlyCore = true; } else if (ENCRYPTED_STATE.equals(cryptState)) { Slog.w(TAG, "Device encrypted - only parsing core apps"); onlyCore = true; } pm = PackageManagerService.main(context, installer, factoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore); …… } }
initAndLoop函数中代码:“String cryptState = SystemProperties.get("vold.decrypt");”是获取Android磁盘加密状态。Android磁盘加密机制是从Android3.0引入的,详细可以参考:《Android安全架构深究》一书第10章设备安全的磁盘加密章节。在默认情况下,Android磁盘加密功能是关闭的,必须由用户手动打开或托管设备的设备策略打开。所以,默认情况下,传递给PackageManagerService.main函数的onlyCore参数为false。
接着,ServerThread调用PackageManagerService的静态函数main安装应用。
在ServerThread类中,除了启动PackageManagerService外,还启动其他系统服务,包括ActivityManagerService、WindowManagerService、AlarmManagerService等,详细见ServerThread类的源码,这里我们只关注PackageManagerService,下面的章节,我们就开始从PackageManagerService.main函数分析开始。
1.1.2 扫描关键目录
PackageManagerService位置:
/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
上述main函数定义如下:
public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }
main函数中创建PackageManagerService服务对象,并把服务添加到ServiceManager中。ServiceManager是Android系统Binder进程通信机制的守护进程,一直运行在后台。它主要负责管理系统中的Binder对象。
我们接着分析PackageManagerService类的构造函数,关键代码如下:
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { synchronized (mInstallLock) { // writer synchronized (mPackages) { mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(), WATCHDOG_TIMEOUT); File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); mAppInstallDir = new File(dataDir, "app"); mAppLibInstallDir = new File(dataDir, "app-lib"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); …… mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); mDalvikCacheDir = new File(dataDir, "dalvik-cache"); …… // Find base frameworks (resource packages without code). mFrameworkInstallObserver = new AppDirObserver( frameworkDir.getPath(), OBSERVER_EVENTS, true, false); mFrameworkInstallObserver.startWatching(); //扫描”/system/framework”目录下的apk scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanMode | SCAN_NO_DEX, 0); // Collected privileged system packages. File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); mPrivilegedInstallObserver = new AppDirObserver( privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true); mPrivilegedInstallObserver.startWatching(); //扫描”/system/priv-app”目录下的apk scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0); // Collect ordinary system packages. File systemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( systemAppDir.getPath(), OBSERVER_EVENTS, true, false); mSystemInstallObserver.startWatching(); //扫描”/system/app”目录下的apk scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all vendor packages. File vendorAppDir = new File("/vendor/app"); mVendorInstallObserver = new AppDirObserver( vendorAppDir.getPath(), OBSERVER_EVENTS, true, false); mVendorInstallObserver.startWatching(); // vender目录其实连接到/system/vendor,实际扫描:/system/vendor/app目录下的apk scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands"); mInstaller.moveFiles(); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>(); //由上一部分内容知道,默认情况下磁盘加密状态关闭,即mOnlyCore状态false if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); mAppInstallObserver.startWatching(); //扫描”/data/app”目录下的apk scanDirLI(mAppInstallDir, 0, scanMode, 0); mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false); mDrmAppInstallObserver.startWatching(); //扫描”/data/app-private”目录下的apk scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); …… } …….. }
如上代码,可以看到PackageManagerService在构造函数中,会扫描如下6个目录下的APK,保证这些APK的信息被预先加载进来。
/system/framework |
/system/priv-app |
/system/app |
/system/vendor/app |
/data/app |
/data/app-private |
/system/app目录存放的是系统自带的apk;
/data/app目录下存放的是用户安装的apk;
/system/priv-app目录下的应用是特权应用,这对这些应用富裕signatureOrSystem保护级别的权限,而不是所有/system下的应用
TOOD:查看Android安全架构深究
我们接着分析scanDirLI函数,其函数定义如下:
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); …… int i; for (i=0; i<files.length; i++) { File file = new File(dir, files[i]); //只扫描apk后缀的文件 if (!isPackageFilename(files[i])) { // Ignore entries which are not apk's continue; } PackageParser.Package pkg = scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); …… } }
scanPackageLI函数主要扫描apk文件并返回解析后的PackageParser.Package对象。
scanPackageLI的关键代码:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode, long currentTime, UserHandle user) { …… String scanPath = scanFile.getPath(); parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(scanPath); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); //解析安装包 final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags); …… //保存解析后的安装包 PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); …… return scannedPkg; }
1.1.3 解析保存应用程序信息
查看parsePackage函数位置:frameworks/base/core/java/android/content/pm/PackageParser.java,其关键代码如下:
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = sourceFile.getPath(); …… XmlResourceParser parser = null; AssetManager assmgr = null; //AssetManager用来管理包中的资源 Resources res = null; //Resources就是资源,包括图片、xml等 boolean assetError = true; try { assmgr = new AssetManager(); int cookie = assmgr.addAssetPath(mArchiveSourcePath); if (cookie != 0) { res = new Resources(assmgr, metrics, null); assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); assetError = false; } else { Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); } } catch (Exception e) { Slog.w(TAG, "Unable to read AndroidManifest.xml of " + mArchiveSourcePath, e); } …… Package pkg = null; Exception errorException = null; try { // XXXX todo: need to figure out correct configuration. pkg = parsePackage(res, parser, flags, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } …… parser.close(); assmgr.close(); // Set code and resource paths pkg.mPath = destCodePath; pkg.mScanPath = mArchiveSourcePath; //pkg.applicationInfo.sourceDir = destCodePath; //pkg.applicationInfo.publicSourceDir = destRes; pkg.mSignatures = null; return pkg; }
上述函数主要是获取apk中的资源对象res和对Androidmanifest.xml文件进行格式化,并调用另一个parsePackage函数进一步做解析,这个才是Package真正生成的地方。
其函数关键代码如下:
private Package parsePackage( Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { …… String pkgName = parsePackageName(parser, attrs, flags, outError); …… final Package pkg = new Package(pkgName); …… pkg.mVersionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCode, 0); pkg.mVersionName = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_versionName, 0); if (pkg.mVersionName != null) { pkg.mVersionName = pkg.mVersionName.intern(); } String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { …… pkg.mSharedUserId = str.intern(); pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } …… pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); pkg.applicationInfo.installLocation = pkg.installLocation; /* Set the global "forward lock" flag */ if ((flags & PARSE_FORWARD_LOCK) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; } /* Set the global "on SD card" flag */ if ((flags & PARSE_ON_SDCARD) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; } …… while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals("application")) { …… if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { return null; } } else if (tagName.equals("keys")) { if (!parseKeys(pkg, res, parser, attrs, outError)) { return null; } } else if (tagName.equals("permission-group")) { if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("permission")) { if (parsePermission(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("permission-tree")) { if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("uses-permission")) { if (!parseUsesPermission(pkg, res, parser, attrs, outError)) { return null; } } else if (tagName.equals("uses-configuration")) { ...... } else if (tagName.equals("uses-feature")) { ...... } else if (tagName.equals("uses-sdk")) { ...... } else if (tagName.equals("supports-screens")) { ...... } else if (tagName.equals("protected-broadcast")) { ...... } else if (tagName.equals("instrumentation")) { ...... } else if (tagName.equals("original-package")) { ...... } else if (tagName.equals("adopt-permissions")) { ...... } else if (tagName.equals("uses-gl-texture")) { ...... } else if (tagName.equals("compatible-screens")) { ...... } else if (tagName.equals("eat-comment")) { ...... } else if (RIGID_PARSER) { ...... } else { ...... } …… return pkg; }
由上面的代码知道,该函数主要是解析安装包并根据AndroidManifest.xml文件的标签调用响应的解析函数进行解析,如:parseApplication、parseKeys、parsePermissionGroup、parsePermission、parseUsesPermission等等,并把解析后的信息保存到Package对象pkg中并返回。这里我们只看parseApplication解析函数,其他解析函数类似,具体细节可以查看frameworks/base/core/java/android/content/pm/PackageParser.java函数查看。
parseApplication关键代码如下:
private boolean parseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException { final ApplicationInfo ai = owner.applicationInfo; final String pkgName = owner.applicationInfo.packageName; …… ai.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); ai.logo = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_description, 0); …… ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, str, outError); …… ai.uiOptions = sa.getInt(com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); …… while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { …… String tagName = parser.getName(); if (tagName.equals("activity")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, hardwareAccelerated); …… owner.activities.add(a); } else if (tagName.equals("receiver")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); …… owner.receivers.add(a); } else if (tagName.equals("service")) { Service s = parseService(owner, res, parser, attrs, flags, outError); …… owner.services.add(s); } else if (tagName.equals("provider")) { Provider p = parseProvider(owner, res, parser, attrs, flags, outError); …… owner.providers.add(p); } else if (tagName.equals("activity-alias")) { Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); …… owner.activities.add(a); } else if (parser.getName().equals("meta-data")) { …… } else if (tagName.equals("library")) { …… } else if (tagName.equals("uses-library")) { …… }else if (tagName.equals("uses-package")) { …… }else{ …… } }//end of while return true; }
parseApplication代码主要解析application标签下的子标签内容,并调用相应子标签对应的函数解析,如:parseActivity、parseService、parseProvider等,并将解析的数据保存到ApplicationInfo和Package对象里,同时检查application及其子标签的格式是否合法。
1.1.4 安装应用程序
到这里,我们再返回到1.1.2节中scanPackageLI完成解析后,调用了另外一个scanPackageLI函数,其定义如下:
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime) { ...... synchronized (mPackages) { ...... // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); ...... int N = pkg.providers.size(); int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); p.info.processName = fixProcessName(pkg.applicationInfo.processName, p.info.processName, pkg.applicationInfo.uid); mProvidersByComponent.put(new ComponentName(p.info.packageName, p.info.name), p); ...... } N = pkg.services.size(); for (i=0; i<N; i++) { PackageParser.Service s = pkg.services.get(i); s.info.processName = fixProcessName(pkg.applicationInfo.processName, s.info.processName, pkg.applicationInfo.uid); mServices.addService(s); ...... } N = pkg.receivers.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.receivers.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver"); ...... } N = pkg.activities.size(); for (i=0; i<N; i++) { PackageParser.Activity a = pkg.activities.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mActivities.addActivity(a, "activity"); ...... } ...... } ...... //这里主要是获取应用程序的安装目录,并保存到pkg.applicationInfo.dataDir中 File dataPath; if (mPlatformPackage == pkg) { // The system package is special. dataPath = new File (Environment.getDataDirectory(), "system"); pkg.applicationInfo.dataDir = dataPath.getPath(); } else { dataPath = getDataPathForPackage(pkg.packageName, 0); …… if (dataPath.exists()) { //条件1:已经安装过,这里系统应用程序是已经安装了的,所以是执行此处的逻辑 …… pkg.applicationInfo.dataDir = dataPath.getPath(); } else { …… //条件2:createDataDirsLI才是实际进行安装的操作 int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.seinfo); …… if (dataPath.exists()) { pkg.applicationInfo.dataDir = dataPath.getPath(); } else { Slog.w(TAG, "Unable to create data directory: " + dataPath); pkg.applicationInfo.dataDir = null; } } …… } …… return pkg; }
这个函数主要是把前面解析安装包得到的activity、service、receiver、provider等信息保存到PackageParse.Package对象中。
该函数在解析过程中,如果应用程序第一次安装,则进入条件2的代码逻辑,并调用createDataDirsLI函数,这个函数才是真正安装操作的,安装程序并保存创建的程序目录。但是由于我们是系统启动方式,此时的应用程序都是已经安装了的,所以是进入条件1的代码逻辑。我们会在1.2节中讲手动安装apk的方式,此时进入的就是条件2的代码逻辑。这里我们假设是应用程序未安装,接着分析createDataDirsLI函数。
createDataDirsLI函数定义如下:
private int createDataDirsLI(String packageName, int uid, String seinfo) { int[] users = sUserManager.getUserIds(); int res = mInstaller.install(packageName, uid, uid, seinfo); if (res < 0) { return res; } for (int user : users) { if (user != 0) { res = mInstaller.createUserData(packageName, UserHandle.getUid(user, uid), user); if (res < 0) { return res; } } } return res; }
可以看到该函数调用Installer类的install成员函数执行安装操作,安装成功后才调用createUserData函数创建应用程序的用户数据。这里我们主要分析Installer类的install成员函数细节。
Installer.java位置: frameworks/base/services/java/com/android/server/pm/Installer.java
install函数定义如下:
public int install(String name, int uid, int gid, String seinfo) { StringBuilder builder = new StringBuilder("install"); builder.append(' '); builder.append(name); builder.append(' '); builder.append(uid); builder.append(' '); builder.append(gid); builder.append(' '); builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); }
该函数将传递的参数组合成一个install的字符串命令,传递给execute函数执行。我们接着分析execute函数。
execute函数定义:
private int execute(String cmd) { String res = transaction(cmd); try { return Integer.parseInt(res); } catch (NumberFormatException ex) { return -1; } }
该函数调用transaction执行命令。
transaction函数定义:
private synchronized String transaction(String cmd) { if (!connect()) { …… } if (!writeCommand(cmd)) { …… } …… }
这里transaction实际是通过CS的通信方式发送指令给服务端进行具体的操作,包括安装卸载等。
connect是跟服务端进行连接,连接成功后才调用writeCommand函数将具体的命令cmd发送过去。
我们接着看connect函数实现,看它是跟那个服务通信。
connect函数定义:
private boolean connect() { if (mSocket != null) { return true; } Slog.i(TAG, "connecting..."); try { mSocket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress("installd", LocalSocketAddress.Namespace.RESERVED); mSocket.connect(address); mIn = mSocket.getInputStream(); mOut = mSocket.getOutputStream(); } catch (IOException ex) { disconnect(); return false; } return true; }
writeCommand函数定义:
private boolean writeCommand(String _cmd) { byte[] cmd = _cmd.getBytes(); int len = cmd.length; if ((len < 1) || (len > 1024)) return false; buf[0] = (byte) (len & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); try { mOut.write(buf, 0, 2); mOut.write(cmd, 0, len); } catch (IOException ex) { Slog.e(TAG, "write error"); disconnect(); return false; } return true; }
到这里,我们就明了,原来PackageManagerService是跟Installd服务进行通信,通过给Installd服务进程发送具体指令进行安装卸载应用程序,,如上面安装程序操作则发送了一个”install”开头的字符串命令。并通过writeCommand函数发送给Installd服务端进程。
Installd服务进程是由init进程启动的,其源码位于:frameworks/base/cmds/installd。

仔细看installd.c源码,可以看到一个命令数组:
struct cmdinfo { const char *name; unsigned numargs; int (*func)(char **arg, char reply[REPLY_MAX]); }; struct cmdinfo cmds[] = { //命令名称 参数个数 对应函数 { "ping", 0, do_ping }, { "install", 4, do_install }, { "dexopt", 3, do_dexopt }, { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, { "remove", 2, do_remove }, { "rename", 2, do_rename }, { "fixuid", 3, do_fixuid }, { "freecache", 1, do_free_cache }, { "rmcache", 2, do_rm_cache }, { "getsize", 6, do_get_size }, { "rmuserdata", 2, do_rm_user_data }, { "movefiles", 0, do_movefiles }, { "linklib", 3, do_linklib }, { "mkuserdata", 3, do_mk_user_data }, { "rmuser", 1, do_rm_user }, };
到这里,我们就明白了上面的install函数为什么构造一个带有”install”的字符串,其实是发送给Installd服务进程调用do_install执行安装操作。
public int install(String name, int uid, int gid, String seinfo) { StringBuilder builder = new StringBuilder("install"); … return execute(builder.toString()); }
我们看do_install函数的实现:
static int do_install(char **arg, char reply[REPLY_MAX]) { return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */ }
这里它调用了commands.c文件的install函数:
install函数定义:
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) { char pkgdir[PKG_PATH_MAX]; //程序目录路径最长256 char libsymlink[PKG_PATH_MAX]; char applibdir[PKG_PATH_MAX]; struct stat libStat; // 权限判断 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { ALOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; } // 组合应用程序安装目录pkgdir=”/data/data/应用程序包名” if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { ALOGE("cannot create package path\n"); return -1; } …… // 创建应用程序安装目录pkgdir=”/data/data/应用程序包名” if (mkdir(pkgdir, 0751) < 0) { ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); return -1; } // 修改应用程序安装目录pkgdir=”/data/data/应用程序包名”权限 if (chmod(pkgdir, 0751) < 0) { ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); unlink(pkgdir); return -1; } …… return 0; }
至此,我们就分析完系统启东市安装apk的完整流程
1.2 第三方应用安装
手动安装apk函数关系如下图:

1.2.1 调用PackageInstaller应用程序的PackageInstallActivity
我们看下PackageInstaller.apk的AndroidManifest.xml文件中
<activity android:configChanges="keyboardHidden|orientation|screenSize" android:excludeFromRecents="true" android:name=".PackageInstallerActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.INSTALL_PACKAGE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="file"/> <data android:mimeType="application/vnd.android.package-archive"/> </intent-filter> <intent-filter> <action android:name="android.intent.action.INSTALL_PACKAGE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="file"/> <data android:scheme="package"/> </intent-filter> </activity>
点击的时候发送” android.intent.action.INSTALL_PACKAGE”消息,调用起PackageInstaller.apk应用程序的PackageInstallerActivity处理并开始安装程序。
PackageInstallerActivity定义如下:
public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener { private static final String TAG = "PackageInstaller"; …… @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); // 获取Intent传递过来的数据 final Intent intent = getIntent(); mPackageURI = intent.getData(); mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); mPm = getPackageManager(); … initiateInstall(); } …… }
我们看到PackageInstallerActivity接收到Intent后,获取其地址,并调用initiateInstall函数开始安装。
initiateInstall函数关键代码如下:
private void initiateInstall() { String pkgName = mPkgInfo.packageName; …… startInstallConfirm(); }
initiateInstall开始检查安装包是否安装过,并调用startInstallConfirm函数弹出选择对话框供用户选择是否安装。也就是下面我们常见的安装界面:
接着分析startInstallConfirm函数,关键代码如下:
private void startInstallConfirm() { mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); if (mScrollView == null) { // There is nothing to scroll view, so the ok button is immediately // set to install. mOk.setText(R.string.install); mOkCanInstall = true; } else { mScrollView.setFullScrollAction(new Runnable() { @Override public void run() { mOk.setText(R.string.install); mOkCanInstall = true; } }); } }
startInstallConfirm初始化并显示安装界面,同时绑定确认和取消按钮事件。接下来,我们看onClick函数。
其关键代码如下:
public void onClick(View v) { if(v == mOk) { if (mOkCanInstall || mScrollView == null) { //确认安装,并调用另一个Activity处理 …… newIntent.setClass(this, InstallAppProgress.class); …… startActivity(newIntent); finish(); } …… } else if(v == mCancel) { //取消安装 …… } }
这里面onClick函数发送Intent给InstallAppProgess类处理安装任务。
1.2.2 调用PackageInstaller应用程序的InstallAppProgess
我们查看InstallAppProgess类的onCreate函数。
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Intent intent = getIntent(); mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mInstallFlowAnalytics = intent.getParcelableExtra(EXTRA_INSTALL_FLOW_ANALYTICS); mInstallFlowAnalytics.setContext(this); mPackageURI = intent.getData(); final String scheme = mPackageURI.getScheme(); if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME); throw new IllegalArgumentException("unexpected scheme " + scheme); } initView(); }
onCreate获取传递过来的Intent并调用initView函数。
initView函数关键代码如下:
public void initView() { …… PackageInstallObserver observer = new PackageInstallObserver(); if ("package".equals(mPackageURI.getScheme())) { //安装一个已经存在的应用程序 try { pm.installExistingPackage(mAppInfo.packageName); observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_SUCCEEDED); } catch (PackageManager.NameNotFoundException e) { observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_FAILED_INVALID_APK); } } else { //第一次安装 pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, installerPackageName, verificationParams, null); } }
initView先是做一些布局初始化的工作,如果是第一次安装,则调用PackageManager类的installPackageWithVerificationAndEncryption函数完成安装。传递过去的第一个参数实际是安装包的路径,第二个参数则是一个应用程序安装的观察者。
这里PackageManager是抽象类,该函数的具体实现在PackageManagerService类里,所以实际上是调用PackageManagerService服务进行安装。
1.2.3 调用PackageManagerService服务的函数完成安装
跳转到PacakgeManagerService类,查看installPackageWithVerificationAndEncryption函数关键代码:
public void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { …… //该函数发送一个”INIT_COPY”的消息和一个InstallParams类对象给 //PackageHandler类对象mHandler处理 final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, verificationParams, encryptionParams, user); mHandler.sendMessage(msg); }
我们跳转到PackageHandler类的消息处理函数handleMessage:
public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } }
该函数调用doHandleMessage进行消息处理,我们看看doHandleMessage接收到INIT_COPY消息后如何处理:
void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { …… if (!mBound) { …… } else { mPendingInstalls.add(idx, params); //发送MCS_BOUND消息 if (idx == 0) { mHandler.sendEmptyMessage(MCS_BOUND); } } break; } case MCS_BOUND: { …… if (mContainerService == null) { …… } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) { …… } } } …… } …… } }
在接收到INIT_COPY消息后,mHandler又给自己发送MCS_BOUND消息。在该消息的处理过程中,调用HandlerParams类的startCopy函数。注意的是HandlerParams是抽象类,InstallParams继承了HandlerParams并实现下述3个抽象函数。后面分析到这3个函数,我们 就需要到HandleParams类下查找。
- abstract void handleStartCopy() throws RemoteException;
- abstract void handleServiceError();
- abstract void handleReturnCode();
我们继续看startCopy函数的关键代码:
final boolean startCopy() { boolean res; try { …… if (++mRetries > MAX_RETRIES) { …… handleServiceError(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { …… } handleReturnCode(); return res; }
startCopy调用了3个函数:handleServiceError、handleStartCopy和handleReturnCode。
handleServiceError是用来处理安装错误的,这里我们不展开讲;
handleStartCopy主要是获取安装包信息,并给两个关键变量完成赋值工作,分别是InstallArgs类对象mArgs和mRet变量。
handleStartCopy关键代码:
public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; …… final InstallArgs args = createInstallArgs(this); mArgs = args; …… mRet = ret; }
handleReturnCode函数定义如下:
@Override void handleReturnCode() { if (mArgs != null) { processPendingInstall(mArgs, mRet); …… } }
这里,我们看到handleReturnCode调用processPendingInstall并传递handleStartCopy赋值的两个参数mArgs和mRet。
processPendingInstall函数关键代码如下:
private void processPendingInstall(final InstallArgs args, final int currentStatus) { // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { public void run() { 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, res.uid); } …… } }); }
该函数启动了一个线程并调用installPackageLI安装。
private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) { …… if (replace) { replacePackageLI(pkg, parseFlags, scanMode, args.user, installerPackageName, res); } else { installNewPackageLI(pkg, parseFlags, scanMode | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, res); } …… }
这里,installPackageLI有两种操作,如果应用程序已经在,则调用replacePackageLI替换,如果是第一次安装,则调用installNewPackageLI函数,这里我们假设是第一次安装。
接下来分析installNewPackageLI函数的关键代码:
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { …… PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis(), user); …… }
这里,我们又看到1.1分析中调用的scanPackageLI函数,后面的分析就跟1.1.4节一样了,这里就不重复讲。
1.3通过ADB命令安装
TODO:继续详细化ADB内容
ADB的执行机制其实是按照客户端、服务端的方式工作。
(1)客户端:adb或adb.exe,运行于PC段
(2)服务端:adbd,运行在手机端或模拟器等设备上的守护进程。该进程由init父进程创建。

通过ADB命令方式安装,其整体函数关系如下图所示:

首先,要想进一步了解ADB命令安装的工作方式,就需要我们进一步研究adb模块的源码。adb运行的入口在:
system\core\adb\adb.c,我们查看main函数定义:
int main(int argc, char **argv) { #if ADB_HOST //也就是我们的PC客户端 adb_sysdeps_init(); adb_trace_init(); D("Handling commandline()\n"); return adb_commandline(argc - 1, argv + 1); //运行PC段的adb/adb.exe可执行程序 #else /* If adbd runs inside the emulator this will enable adb tracing via * adb-debug qemud service in the emulator. */ adb_qemu_trace_init(); if((argc > 1) && (!strcmp(argv[1],"recovery"))) { adb_device_banner = "recovery"; recovery_mode = 1; } start_device_log(); D("Handling main()\n"); return adb_main(0, DEFAULT_ADB_PORT); //运行在目标设备上的adbd可执行程序 #endif }
接着分析adb_commandline函数的关键代码:
int adb_commandline(int argc, char **argv) { …… if(!strcmp(argv[0], "devices")) {….} if(!strcmp(argv[0], "connect")) {…} if(!strcmp(argv[0], "disconnect")) {…} if (!strcmp(argv[0], "emu")) {…} if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {…} if(!strcmp(argv[0], "kill-server")) {…} if(!strcmp(argv[0], "sideload")) {…} if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") || !strcmp(argv[0], "root")) {…} …… if(!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); } if(!strcmp(argv[0], "uninstall")) { if (argc < 2) return usage(); return uninstall_app(ttype, serial, argc, argv); } …… }
adb_commandline其实就是处理我们输入的命令行,调用响应的函数工作。

我们看到当收到”install”指令时,调用install_app函数执行安装工作。
int install_app(transport_type transport, char* serial, int argc, char** argv) { …… apk_file = argv[file_arg]; …… err = do_sync_push(apk_file, apk_dest, verify_apk); …… pm_command(transport, serial, argc, argv); …… }
install_app再安装前,调用了pm_command函数做一些命令行修改,实际就是给命令行字符串添加”shell:pm”指令,这里pm其实就是pm.jar,Package管理器。pm.jar主要执行终端下传递过来的pm命令。类似的jar包还有am.jar,Activity管理器等,它们都位于\system\framework目录下。
也就是说,adb命令安装方式实际上是调用pm包管理器来对安装包进行安装卸载等工作。
pm.jar包的关键方法:Pm.java,其文件位置:com/android/commands/pm/Pm.java。
该文件的入口函数为:main函数:
public final class Pm { IPackageManager mPm; IUserManager mUm; …… public static void main(String[] args) { new Pm().run(args); } …… }
main函数创建Pm类对象并调用run函数,其关键代码如下:
public void run(String[] args) { …… mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); …… if ("list".equals(op)) { runList(); return; } if ("path".equals(op)) { runPath(); return; } if ("dump".equals(op)) { runDump(); return; } if ("install".equals(op)) { runInstall(); return; } if ("uninstall".equals(op)) { runUninstall(); return; } …… }
我们分析下面这行代码:
TODO: 学习了解下Binder机制
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))。
Stub是接口IPackageManager的静态抽象类,asInterface是返回IPackageManager代理的静态方法。
我们在返回看PackageManagerService.java的定义:
public class PackageManagerService extends IPackageManager.Stub { …… }
所以,IPackageManager类对象mPm的函数实际上是调用PackageManagerService类对应的函数。
安装操作会调用runInstall函数。
runInstall函数关键代码如下:
/* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags) { installPackage(packageURI, observer, flags, null); }
通过函数的注释我们可以知道这个是通过网络下载的方式安装APK。
该函数调用另一个installPackage函数:
public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags, final String installerPackageName) { installPackageWithVerification(packageURI, observer, flags, installerPackageName, null, null, null); }
该函数调用installPackageWithVerification:
@Override public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, VerificationParams.NO_UID, manifestDigest); installPackageWithVerificationAndEncryption(packageURI, observer, flags, installerPackageName, verificationParams, encryptionParams); }
到这里,我们看到installPackageWithVerification调用了installPackageWithVerificationAndEncryption函数进行安装,该函数我们在1.2.3节中已经分析,这里就不做展开。下面附上通过该方式安装应用程序的函数关系图:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)