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节中已经分析,这里就不做展开。下面附上通过该方式安装应用程序的函数关系图:




浙公网安备 33010602011771号