1. 前言
PackageManagerService在android系统中, 主要工作负责系统应用的安装与卸载工作,由于系统中还有一个名字叫PowerManagerService的系统服务,所以下面我将他的缩写命为PAMS,防止混淆。
顺便提一下,这篇文章理论基础是android 4.4.2。
2. PAMS启动过程
PAMS是一个系统服务,那它的启动必然是由系统所带动的。它的启动过程这里简单说一下,有兴趣的朋友可以根据这个思路跟一下代码。
话说在系统开机那一刻,init进程解析init.rc的时候会启动zygote进程,代码如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
位于“/system/bin/app_process”指向的是app_main.cpp,请注意init.rc里的传下来的参数,然后找到函数入口,定位到关键函数:
int main()
{ while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote";
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12;
} else {
className = arg;
break;
}
}
if (zygote) {
//1
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.`RuntimeInit`",
application ? "application" : "tool");
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
上面代码,其实只需要看注释1下面两行代码,继续往下走,找到AndroidRuntime.cpp的“start”函数,下面已截取关键函数,让大家省心:
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
可以看到这里是利用了jni的原理反射调用ZygoteInit类的main函数,好的,那就继续找到它的main函数,代码有删减:
public static void main(String argv[]) {
if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
}
很直观,直接看startSystemServer函数做了什么工作:
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=****",
"--setgid=****",
"--setgroups=****",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);
}
return true;
}
上面的代码核心思想是fork一个进程,当pid为0时候就执行handleSystemServerProcess函数,handleSystemServerProcess函数的核心代码如下:
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
继续往下就会调用SystemServer的main函数,中间会跳转几个函数,这些这里不再赘述。
到SystemServer的main函数里,PAMS就在这里启动。
关键代码如下:
pm = PackageManagerService.main(context, installer,
factoryTest != SystemServer.FACTORY_TEST_OFF,
onlyCore);
好啦,最后在这一小节,简单说一下,接下来PAMS第一次开机的时候会扫描系统各个存放apk的目录,然后解析其的AndroidManifest.xml,校验签名,优化dex,安装应用等操作。
3. installd底层服务启动过程
在继续讲PAMS之前,插播一下installd服务的启动过程,为啥讲的好好的PAMS,提这个感觉不相关的服务干嘛?这肯定是有关,而且PAMS最终还是依靠installd这个大哥干活呢,废话不多说,进入主题。
installd这个服务第一次出现的地方是在init.rc,代码如下:
service installd /system/bin/installd
class main
socket installd stream 600 system system
可以看到这个服务启动时由socket进行连接的,什么时候建立通信过程的呢,这里先留一个疑问,下文将会说明。
4. 解析过程
接第2节内容,我们看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;
}
好的,其他不解释,直接看PackageManagerService的构造函数,这里就不再深入解释binder的东西了。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore){
boolean optimize = false;
optimize = SystemProperties.getBoolean("persist.sys.boot.optimize", false);
if(optimize){
PackageManagerService_Optimize(context,installer,factoryTest,onlyCore);
}else{
PackageManagerService_Orig(context,installer,factoryTest,onlyCore);
}
}
好的,首先我自己参与定制系统,可知optimize变量为true,走优化分支,下面那个分支是默认分支,那个这里不讨论,只说明如何优化的。
5. 安装过程
应用安装相对应用卸载来说要稍微复杂一点,这里我会 比较详细的说一下。
据我所知,应用安装他开机启动的时候PAMS会在他的构造函数里面进行安装,还有就是用户自己安装的应用是调用到系统api的installPackage函数进行安装,还有一种是使用adb命令进行安装操作这三种情况。
5.1 开机安装
开机的时候,SystemServer会拉起PackageManagerService,然后会在PackageManagerService的构造函数里实现对应用的的安装操作。我们直接进入到PackageManagerService_Optimize函数开始分析。函数比较长,我第一次看的也有点难受,多看几遍就差不多弄懂啥意思了,有点考验自己的耐心了。
public void PackageManagerService_Optimize(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context; //获取上下文
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(context); //在这里创建packages.xml等文件对象
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
Slog.w(TAG, "Running with debug.separate_processes: "
+ separateProcesses);
}
} else {
mDefParseFlags = 0;
mSeparateProcesses = null;
}
mInstaller = installer; //为当前对象赋值为installer
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
d.getMetrics(mMetrics);
File frameworkDir;
int scanMode;
long startTime;
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");
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
readPermissions(); //解析etc/permissions/目录下的各种xml文件
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
/**
* 下面这段代码也很重要,他会去读/data/system/packages.xml,解析之后将存起,第一次是没有这个文件的,所以会跳过,
* packages.xml记录了应用包的各种重要信息,安装,更新,卸载都会更新这个文件
* /
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}
startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
if (mNoDexOpt) {
Slog.w(TAG, "Running ENG build: no pre-dexopt!");
scanMode |= SCAN_NO_DEX;
}
final HashSet<String> alreadyDexOpted = new HashSet<String>();
/**
* Add everything in the in the boot class path to the
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
String bootClassPath = System.getProperty("java.boot.class.path");
if (bootClassPath != null) {
String[] paths = splitString(bootClassPath, ':');
for (int i=0; i<paths.length; i++) {
alreadyDexOpted.add(paths[i]);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
boolean didDexOpt = false;
/**
* Ensure all external libraries have had dexopt run on them.
*/
if (mSharedLibraries.size() > 0) {
Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
ExecutorService executorService = Executors.newFixedThreadPool(sNThreads);
while (libs.hasNext()) {
final String lib = libs.next().path;
if (lib == null) {
continue;
}
try {
if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
alreadyDexOpted.add(lib);
didDexOpt = true;
executorService.submit(new Runnable() {
@Override
public void run() {
mInstaller.dexopt(lib, Process.SYSTEM_UID, true); //预优化操作
}
});
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
}
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
frameworkDir = new File(Environment.getRootDirectory(), "framework");
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
ExecutorService executorService = Executors.newFixedThreadPool(sNThreads);
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
final String path = libPath.getPath();
// Skip the file if we alrady did it.
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
if (dalvik.system.DexFile.isDexOptNeeded(path)) {
didDexOpt = true;
executorService.submit(new Runnable() {
@Override
public void run() {
mInstaller.dexopt(path, Process.SYSTEM_UID, true);
}
});
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
if (didDexOpt) {
File dalvikCacheDir = new File(dataDir, "dalvik-cache");
// If we had to do a dexopt of one of the previous
// things, then something on the system has changed.
// Consider this significant, and wipe away all other
// existing dexopt files to ensure we don't leave any
// dangling around.
String[] files = dalvikCacheDir.list();
if (files != null) {
for (int i=0; i<files.length; i++) {
String fn = files[i];
if (fn.startsWith("data@app@")
|| fn.startsWith("data@app-private@")) {
Slog.i(TAG, "Pruning dalvik file: " + fn);
(new File(dalvikCacheDir, fn)).delete();
}
}
}
}
}
}
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
mFrameworkInstallObserver.startWatching();
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();
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();
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();
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
synchronized (mInstallLock) {
synchronized (mPackages) {
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
mInstaller.moveFiles();
// Prune any system packages that no longer exist.
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* If this is not a system app, it can't be a
* disable system app.
*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
Slog.i(TAG, "Expecting better updatd system app for " + ps.name
+ "; removing system app");
removePackageLI(ps, true);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
removeDataDirsLI(ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
cleanupInstallFailedPackage(deletePkgsList.get(i));
}
//delete tmp files
deleteTempPackageFiles();
// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
}
}
if(SystemProperties.get("persist.sys.qb.enable","false").equals("true"))
mDataAppPackage.clear();
if(SystemProperties.get("ro.laterscan.enable","false").equals("false")) {
Slog.e(TAG, "isFirstBoot() = " + isFirstBoot());
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下的安装包,它的实现中会有调用scanPackageLI去解析安装包并实现安装过程
scanDirLI(mAppInstallDir, 0, scanMode, 0);
mDrmAppInstallObserver = new AppDirObserver(
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);
mDrmAppInstallObserver.startWatching();
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanMode, 0);
}
synchronized (mPackages) {
/**
* Remove disable package settings for any updated system
* apps that were removed via an OTA. If they're not a
* previously-updated app, remove them completely.
* Otherwise, just revoke their system-level permissions.
*/
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
String msg;
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
removeDataDirsLI(deletedAppName);
} else {
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
+ deletedAppName;
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
reportSettingsProblem(Log.WARN, msg);
}
}
}
//later user
if(SystemProperties.get("ro.laterscan.enable","false").equals("true"))
{
getLauncherFormFile();
scanDataLauncher();
}
synchronized (mInstallLock) {
synchronized (mPackages) {
updateAllSharedLibrariesLPw();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
final boolean regrantPermissions = mSettings.mInternalSdkPlatform
!= mSdkVersion;
if (regrantPermissions) Slog.i(TAG, "Platform changed from "
+ mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
// If this is the first boot, and it is a normal boot, then
// we need to initialize the default preferred apps.
if (!mRestoredSettings && !onlyCore) {
mSettings.readDefaultPreferredAppsLPw(this, 0);
}
// can downgrade to reader
mSettings.writeLPr(); //更新packages.xml文件
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Runtime.getRuntime().gc();
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
}
上边代码,做了一些注释,但实现安装的关键函数是scanPackageLI,他通过调用parsePackage解析安装包中AndroidManifest.xml,并通过调用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;
}
经过socket连接调用到了native installd服务的do_install函数(这个连接过程下文卸载操作会说的详细一些)
static int do_install(char **arg, char reply[REPLY_MAX])
{
ALOGE("has do_install");
return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */
}
install函数其实就是创建data/data/packagename目录下的各种数据文件,与之对应的卸载,即是删除这些文件,完成卸载操作。
5.2 应用层安装
除了系统自己安装之外,也可以开发者自己调用系统api安装,毕竟每次安装都重启之后让PAMS来安装是不太合理的,实际就是调用installPackage函数。如下:
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
installPackage(packageURI, observer, flags, null);
}
然后:
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags,
final String installerPackageName) {
installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
null, null);
}
再然后:
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);
}
再然后:
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
.........//此处省略n行
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
verificationParams, encryptionParams, user);
mHandler.sendMessage(msg);
}
上面函数installPackageWithVerificationAndEncryption可以看到他发了一个消息,并传递了对象参数,找到处理消息的地方:
void doHandleMessage(Message msg) {
switch (msg.what) {
......//此处省去n行代码
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// If a bind was already initiated we dont really
// need to do anything. The pending install
// will be processed later on.
if (!mBound) {
// If this is the only one pending we might
// have to bind to the service again.
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
params.serviceError();
return;
} else {
// Once we bind to the service, the first
// pending request will be processed.
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
......//此处省去n行代码
}
}
在接受到 INIT_COPY 消息后,将要安装的参数信息加入到 PendingInstalls 中去,如果是第一个安装,发送 MCS_BOUND 消息触发实际安装过程。
case MCS_BOUND: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
// Something seriously wrong. Bail out
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
params.serviceError();
}
mPendingInstalls.clear();
} else if (mPendingInstalls.size() > 0) {
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
if (params.startCopy()) {
// We are done... look for more work or to
// go idle.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Checking for more work or unbind...");
// Delete pending install
if (mPendingInstalls.size() > 0) {
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) {
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
sendMessageDelayed(ubmsg, 10000);
}
} else {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing
// of next pending install.
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting MCS_BOUND for next woek");
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
上面函数取出第一个安装请求,并调用 startCopy 方法。
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
if (++mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
handleReturnCode();
return res;
}
在 startCopy 中调用 handleStartCopy 方法,handleReturnCode方法
handleStartCopy的核心就是copyApk,其他的都是些存储空间检查,权限检查等等安全校验。
void handleStartCopy() throws RemoteException {
synchronized (mInstallLock) {
mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
}
final boolean mounted;
if (Environment.isExternalStorageEmulated()) {
mounted = true;
} else {
final String status = Environment.getExternalStorageState();
mounted = (Environment.MEDIA_MOUNTED.equals(status)
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
}
if (mounted) {
final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
mStats.externalCacheSize = calculateDirectorySize(mContainerService,
userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
mStats.externalDataSize = calculateDirectorySize(mContainerService,
userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
// Always subtract cache size, since it's a subdirectory
mStats.externalDataSize -= mStats.externalCacheSize;
mStats.externalMediaSize = calculateDirectorySize(mContainerService,
userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
mStats.externalObbSize = calculateDirectorySize(mContainerService,
userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
}
}
handleReturnCode函数调用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);
}
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has a backupAgent defined.
final boolean update = res.removedInfo.removedPackage != null;
boolean doRestore = (!update
&& res.pkg != null
&& res.pkg.applicationInfo.backupAgentName != null);
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
// there's a restore pass performed. Token values are >= 1.
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
PostInstallData data = new PostInstallData(args, res);
mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ " to BM for possible restore");
try {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
} catch (RemoteException e) {
// can't happen; the backup manager is local
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Slog.e(TAG, "Backup Manager not found!");
doRestore = false;
}
}
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
});
}
上面的代码最终会通过installPackageLI完成对应用的安装。
private void installPackageLI(InstallArgs args,
boolean newInstall, PackageInstalledInfo res) {
........//此处省略n行
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
}
}
这个方法先是解析了package包,然后做了大量签名和权限校验的工作,最终走到判断是安装新的apk还是覆盖安装的判断语句上。
private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
// it has been renamed to an older name. The package we
// are trying to install should be installed as an update to
// the existing one, but that has not been requested, so bail.
Slog.w(TAG, "Attempt to re-install " + pkgName
+ " without first uninstalling package running as "
+ mSettings.mRenamedPackages.get(pkgName));
res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
return;
}
if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
// Don't allow installation over an existing package with the same name.
Slog.w(TAG, "Attempt to re-install " + pkgName
+ " without first uninstalling.");
res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
return;
}
}
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
System.currentTimeMillis(), user);
if (newPackage == null) {
Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
updateSettingsLI(newPackage,
installerPackageName,
null, null,
res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// remove package from internal structures. Note that we want deletePackageX to
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
// install.
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
}
}
}
可以看到最终还是一样会走到scanPackageLI中进行安装,剩下的就不再此赘述。
5.3 adb安装
安装应用还可以使用adb命令安装,例如:adb install packagePath
原理:
system\core\adb\commandline.c
adb_commandline函数:
if(!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
return install_app(ttype, serial, argc, argv);
}
找到这个位置,跳到install_app函数,它又会走下面这行代码:
pm_command(transport, serial, argc, argv);
我们找到pm_command函数的实现:
static int pm_command(transport_type transport, char* serial,
int argc, char** argv)
{
char buf[4096];
snprintf(buf, sizeof(buf), "shell:pm");
while(argc-- > 0) {
char *quoted;
quoted = dupAndQuote(*argv++);
strncat(buf, " ", sizeof(buf)-1);
strncat(buf, quoted, sizeof(buf)-1);
free(quoted);
}
send_shellcommand(transport, serial, buf);
return 0;
}
上面代码关键点是send_shellcommand函数,并且此时buf为“shell:pm install ***”,send_shellcommand它的实现是:
static int send_shellcommand(transport_type transport, char* serial, char* buf)
{
int fd, ret;
for(;;) {
fd = adb_connect(buf);
if(fd >= 0)
break;
fprintf(stderr,"- waiting for device -\n");
adb_sleep_ms(1000);
do_cmd(transport, serial, "wait-for-device", 0);
}
read_and_dump(fd);
ret = adb_close(fd);
if (ret)
perror("close");
return ret;
}
上面代码可以看出,他的作用是连接shell服务,没连上的话就重新再来一次
连接过程其实就是连接Pm.java的main函数,因为这个会被打成一个jar包,可以通过命令pm ***来带参执行,此时参数为install
那么我们看一下Pm.java的main函数:
public static void main(String[] args) {
new Pm().run(args);
}
再往下:
public void run(String[] args) {
.....此处省略n行代码
mArgs = args;
String op = args[0];
mNextArg = 1;
if ("install".equals(op)) {
runInstall();
return;
}
}
然后再看runInstall这个函数:
private void runInstall() {
.......//此处省略n行代码
PackageInstallObserver obs = new PackageInstallObserver();
try {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
installerPackageName, verificationParams, encryptionParams);
synchronized (obs) {
while (!obs.finished) {
try {
obs.wait();
} catch (InterruptedException e) {
}
}
if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
System.out.println("Success");
} else {
System.err.println("Failure ["
+ installFailureToString(obs.result)
+ "]");
}
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
}
可以看到最终是通过aidl调用到PAMS的installPackageWithVerificationAndEncryption函数,剩下过程就跟5.2安装过程一样了。
6. 卸载过程
PAMS除了安装,另一个重要功能就是卸载应用,下面跟一下,卸载的过程。
首先我们从deletePackageAsUser函数开始跟踪:
public void deletePackageAsUser(final String packageName,
final IPackageDeleteObserver observer,
final int userId, final int flags) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
final int uid = Binder.getCallingUid();
if (UserHandle.getUserId(uid) != userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"deletePackage for user " + userId);
}
if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
try {
observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
} catch (RemoteException re) {
}
return;
}
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
final int returnCode = deletePackageX(packageName, userId, flags); //7
if (observer != null) {
try {
observer.packageDeleted(packageName, returnCode);//8
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
} //end catch
} //end if
} //end run
});
}
上面的代码需要关注的是注释7的代码,他调用了deletePackageX函数做卸载操作,根据名字可知他是删除应用包的功能,还有就是注释8那里会有注册一个观察者,当卸载完成的时候会通知它。
继续往下的看:
private int deletePackageX(String packageName, int userId, int flags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
if (isPackageDeviceAdmin(packageName, userId)) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
boolean removedForAllUsers = false;
boolean systemUpdate = false;
// for the uninstall-updates case and restricted profiles, remember the per-
// userhandle installed state
int[] allUsers;
boolean[] perUserInstalled;
synchronized (mPackages) {
PackageSetting ps = mSettings.mPackages.get(packageName);
allUsers = sUserManager.getUserIds();
perUserInstalled = new boolean[allUsers.length];
for (int i = 0; i < allUsers.length; i++) {
perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
}
}
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
res = deletePackageLI(packageName, //9
(flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(userId),
true, allUsers, perUserInstalled,
flags | REMOVE_CHATTY, info, true);
systemUpdate = info.isRemovedPackageSystemUpdate;
if (res && !systemUpdate && mPackages.get(packageName) == null) {
removedForAllUsers = true;
}
if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
+ " removedForAllUsers=" + removedForAllUsers);
}
if (res) {
info.sendBroadcast(true, systemUpdate, removedForAllUsers);
// If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
null, packageName, null, null);
}
}
// Force a gc here.
Runtime.getRuntime().gc();
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
if (info.args != null) {
synchronized (mInstallLock) {
info.args.doPostDeleteLI(true);
}
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
上面的代码看关键的注释9所标注的函数deletePackageLI,跟踪这个函数的实现:
private boolean deletePackageLI(String packageName, UserHandle user,
boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
PackageSetting ps;
boolean dataOnly = false;
int removeUser = -1;
int appId = -1;
synchronized (mPackages) {
ps = mSettings.mPackages.get(packageName);
if (ps == null) {
Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
}
if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
&& user.getIdentifier() != UserHandle.USER_ALL) {
// The caller is asking that the package only be deleted for a single
// user. To do this, we just mark its uninstalled state and delete
// its data. If this is a system app, we only allow this to happen if
// they have set the special DELETE_SYSTEM_APP which requests different
// semantics than normal for uninstalling system apps.
if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user");
ps.setUserState(user.getIdentifier(),
COMPONENT_ENABLED_STATE_DEFAULT,
false, //installed
true, //stopped
true, //notLaunched
false, //blocked
null, null, null);
if (!isSystemApp(ps)) {
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
// Other user still have this package installed, so all
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
removeUser = user.getIdentifier();
appId = ps.appId;
mSettings.writePackageRestrictionsLPr(removeUser);
} else {
// We need to set it back to 'installed' so the uninstall
// broadcasts will be sent correctly.
if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
ps.setInstalled(true, user.getIdentifier());
}
} else {
// This is a system app, so we assume that the
// other users still have this package installed, so all
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
removeUser = user.getIdentifier();
appId = ps.appId;
mSettings.writePackageRestrictionsLPr(removeUser);
}
}
}
if (removeUser >= 0) {
// From above, we determined that we are deleting this only
// for a single user. Continue the work here.
if (DEBUG_REMOVE) Slog.d(TAG, "Updating install state for user: " + removeUser);
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.removedAppId = appId;
outInfo.removedUsers = new int[] {removeUser};
}
mInstaller.clearUserData(packageName, removeUser);
removeKeystoreDataIfNeeded(removeUser, appId);
schedulePackageCleaning(packageName, removeUser, false);
return true;
}
if (dataOnly) {
// Delete application data first
if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
return true;
}
boolean ret = false;
mSettings.mKeySetManager.removeAppKeySetData(packageName);
if (isSystemApp(ps)) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled, //10
flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, ps.appId, "uninstall pkg");
ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
allUserHandles, perUserInstalled,
outInfo, writeSettings);
}
return ret;
}
再然后卸载系统app会跳到deleteSystemPackageLI函数,普通app会走下面的deleteInstalledPackageLI函数,那我讲一下普通app卸载的过程:
private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags,
int[] allUserHandles, boolean[] perUserInstalled,
PackageRemovedInfo outInfo, boolean writeSettings) {
if (outInfo != null) {
outInfo.uid = ps.appId;
}
// Delete package data from internal structures and also remove data if flag is set
removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings); //11
// Delete application code and resources
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
ps.resourcePathString, ps.nativeLibraryPathString);
}
return true;
}
好的,继续看上面注释11的函数实现:
private void removePackageDataLI(PackageSetting ps,
int[] allUserHandles, boolean[] perUserInstalled,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = ps.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
removePackageLI(ps, (flags&REMOVE_CHATTY) != 0); //12
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
// reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.removedUsers = deletedPs != null
? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
: null;
}
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
removeDataDirsLI(packageName); //13
schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
synchronized (mPackages) {
if (deletedPs != null) {
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
if (outInfo != null) {
outInfo.removedAppId = mSettings.removePackageLPw(packageName);
}
if (deletedPs != null) {
updatePermissionsLPw(deletedPs.name, null, 0);
if (deletedPs.sharedUser != null) {
// remove permissions associated with package
mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
}
}
clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
if (allUserHandles != null && perUserInstalled != null) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
for (int i = 0; i < allUserHandles.length; i++) {
if (DEBUG_REMOVE) {
Slog.d(TAG, " user " + allUserHandles[i]
+ " => " + perUserInstalled[i]);
}
ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
}
}
}
// can downgrade to reader
if (writeSettings) {
// Save settings now
mSettings.writeLPr();
}
}
if (outInfo != null) {
// A user ID was deleted here. Go through all users and remove it
// from KeyStore.
removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
}
}
在注释12的函数是删除组件信息,注释13函数继续往下是删除data/data下与包名相对应的目录。
先看注释12:在mPackages总安装应用列表中删除对应实例,清除所有应用组件,如activity, provider, service, contentresolver, receiver等结构
void removePackageLI(PackageSetting ps, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
Log.d(TAG, "Removing package " + ps.name);
}
// writer
synchronized (mPackages) {
mPackages.remove(ps.name);
if (ps.codePathString != null) {
mAppDirs.remove(ps.codePathString);
}
final PackageParser.Package pkg = ps.pkg;
if (pkg != null) {
cleanPackageDataStructuresLILPw(pkg, chatty);
}
}
}
注释13的话,内容会比多,休息一下继续吧,哈哈
好了,意思意思继续了,哈哈哈~
removeDataDirsLI函数实现如下:
private int removeDataDirsLI(String packageName) {
int[] users = sUserManager.getUserIds();
int res = 0;
for (int user : users) {
int resInner = mInstaller.remove(packageName, user); //14
if (resInner < 0) {
res = resInner;
}
}
final File nativeLibraryFile = new File(mAppLibInstallDir, packageName);
NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
if (!nativeLibraryFile.delete()) {
Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath());
}
return res;
}
注释14可以看到他调用了Installer类的remove函数:
public int remove(String name, int userId) {
StringBuilder builder = new StringBuilder("remove");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return execute(builder.toString());
}
上面代码是将包名与用户id拼接在一起,然后调用execute,通过socket发送给natvie层的installd服务处理:
private int execute(String cmd) {
String res = transaction(cmd);
try {
return Integer.parseInt(res);
} catch (NumberFormatException ex) {
return -1;
}
}
private String transaction(String cmd){
optimize = SystemProperties.getBoolean("persist.sys.boot.optimize", false);
if(optimize){
return transaction_Optimize(cmd);
}else{
return transaction_Orig(cmd);
}
}
private String transaction_Optimize(String cmd) {
int transactionId;
synchronized (mTransactionIdLock) {
transactionId = mLastTransactionId++;
if (mLastTransactionId < 0) {
mLastTransactionId = 0;
}
}
try {
synchronized (mResponses) {
long startWaitTime = System.nanoTime();
while(mResponses.get(transactionId) == null) {
synchronized (mPendingRequests) {
if (!mPendingRequests.contains(transactionId)) {
if (!connect()) {
Slog.e(TAG, "connection failed");
return "-1";
}
if (!writeCommand(cmd, transactionId)) {
/*
* If installd died and restarted in the background (unlikely but
* possible) we'll fail on the next write (this one). Try to
* reconnect and write the command one more time before giving up.
*/
Slog.e(TAG, "write command failed? reconnect!");
if (!connect() || !writeCommand(cmd, transactionId)) {
return "-1";
}
}
if (LOCAL_DEBUG) {
Slog.i(TAG, "send ["+transactionId+"]: '" + cmd + "'");
}
mPendingRequests.add(transactionId);
checkPoller();
}
}
final long timeToWait = startWaitTime - System.nanoTime() + *****;
if (timeToWait > 0) {
mResponses.wait(100000);
} else {
Slog.e(TAG, "timeout wating for response");
break;
}
}
}
} catch (InterruptedException e) {
return "-1";
}
synchronized (mPendingRequests) {
mPendingRequests.remove(new Integer(transactionId));
}
checkPoller();
String s;
synchronized (mResponses) {
s = mResponses.get(transactionId);
mResponses.remove(transactionId);
}
if (LOCAL_DEBUG) {
Slog.i(TAG, "recv: ["+transactionId+"]'" + s + "'");
}
return s == null ? "-1" : s;
}
好的,我们到native服务看一下:
int main(const int argc, const char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
int lsocket, s, count;
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.boot.optimize", value, "false");
pthread_t worker_threads, signal_thread;
pthread_attr_t pthread_custom_attr;
sigset_t sigs_to_block;
if(0 == strcmp(value, "true")){
pthread_mutex_init(&io_mutex, NULL);
pthread_cond_init(&io_wait, NULL);
pthread_attr_init(&pthread_custom_attr);
sigemptyset(&sigs_to_block);
sigaddset(&sigs_to_block, SIGIO);
pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
pthread_create(&signal_thread, &pthread_custom_attr, io_signal_handler, NULL);
}
ALOGI("installd firing up\n");
if (initialize_globals() < 0) {
ALOGE("Could not initialize globals; exiting.\n");
exit(1);
}
if (initialize_directories() < 0) {
ALOGE("Could not create directories; exiting.\n");
exit(1);
}
drop_privileges();
lsocket = android_get_control_socket(SOCKET_PATH);
if (lsocket < 0) {
ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
exit(1);
}
if (listen(lsocket, 5)) {
ALOGE("Listen on socket failed: %s\n", strerror(errno));
exit(1);
}
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
for (;;) {
alen = sizeof(addr);
s = accept(lsocket, &addr, &alen);
if (s < 0) {
ALOGE("Accept failed: %s\n", strerror(errno));
continue;
}
fcntl(s, F_SETFD, FD_CLOEXEC);
if(0 == strcmp(value, "true")){
fcntl(s, F_SETFL, O_ASYNC | O_NONBLOCK);
fcntl(s, F_SETSIG, 0);
fcntl(s, F_SETOWN, getpid());
write_error = 0;
}
ALOGI("new connection\n");
int id;
for (;;) {
unsigned short count;
if(0 == strcmp(value, "true")){
if (readx(s, &id, sizeof(id))) {
ALOGE("failed to read transaction id\n");
break;
}
}
if (readx(s, &count, sizeof(count))) {
ALOGE("failed to read size\n");
break;
}
if ((count < 1) || (count >= BUFFER_MAX)) {
ALOGE("invalid size %d\n", count);
break;
}
if (readx(s, buf, count)) {
ALOGE("failed to read command\n");
break;
}
buf[count] = 0;
if(0 == strcmp(value, "true")){
thread_parm *args = (thread_parm*) malloc(sizeof(thread_parm));
args->s = s;
strncpy(args->cmd, buf, count + 1);
args->id = id;
pthread_create(&worker_threads, &pthread_custom_attr, executeAsync, (void*) args);
}else{
if (execute(s, buf,id)) break; //15
}
}
ALOGI("closing connection\n");
close(s);
}
if(0 == strcmp(value, "true")){
pthread_kill(&signal_thread, SIGKILL);
pthread_join(&signal_thread, NULL);
}
return 0;
}
installd.c的main函数实现如上所示,其他不用多解释了,比较好看懂,直接到注释15吧,核心execute函数,处理socket收到的数据:
static int execute(int s, char cmd[BUFFER_MAX], int id)
{
char reply[REPLY_MAX];
char *arg[TOKEN_MAX+1];
unsigned i;
unsigned n = 0;
unsigned short count;
int ret = -1;
char buf[16] = "";
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.boot.optimize", value, "false");
// ALOGI("execute('%s')\n", cmd);
/* default reply is "" */
reply[0] = 0;
/* n is number of args (not counting arg[0]) */
arg[0] = cmd;
while (*cmd) {
if (isspace(*cmd)) {
*cmd++ = 0;
n++;
arg[n] = cmd;
if (n == TOKEN_MAX) {
ALOGE("too many arguments\n");
goto done;
}
}
cmd++;
}
for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
if (!strcmp(cmds[i].name,arg[0])) {
if (n != cmds[i].numargs) {
ALOGE("%s requires %d arguments (%d given)\n",
cmds[i].name, cmds[i].numargs, n);
} else {
ret = cmds[i].func(arg + 1, reply); //16
}
goto done;
}
}
ALOGE("unsupported command '%s'\n", arg[0]);
done:
if (reply[0]) {
n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
} else {
n = snprintf(cmd, BUFFER_MAX, "%d", ret);
}
if (n > BUFFER_MAX) n = BUFFER_MAX;
count = n;
// ALOGI("reply [%d]: '%s'\n", id, cmd);
if(0 == strcmp(value, "true")){
pthread_mutex_lock(&io_mutex);
if (write_error) {
goto exec_error;
}
memcpy(buf, &id, sizeof(id));
memcpy(buf+sizeof(id), &count, sizeof(count));
if (writex(s, buf, sizeof(id)+sizeof(count))) {
write_error = 1;
goto exec_error;
}
if (writex(s, cmd, count)) {
write_error = 1;
goto exec_error;
}
pthread_mutex_unlock(&io_mutex);
return 0;
exec_error:
pthread_cond_broadcast(&io_wait);
pthread_mutex_unlock(&io_mutex);
return -1;
}else{
if (writex(s, &count, sizeof(count))) return -1;
if (writex(s, cmd, count)) return -1;
return 0;
}
}
先看一下这个结构体:
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 },
{ "backupdata", 3, do_backupdata},
{ "restoredata", 3, do_restoredata},
};
所以注释16调用do_remove 函数,好的,继续看do_remove 函数实现:
static int do_remove(char **arg, char reply[REPLY_MAX])
{
ALOGE("has do_remove");
return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */
}
上面函数就做了调用uninstall函数,那么继续:
int uninstall(const char *pkgname, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) //17
return -1;
/* delete contents AND directory, no exceptions */
return delete_dir_contents(pkgdir, 1, NULL); //18
}
注释17最后拼接了一个data/data/packagename的路径变量pkgdir,给到了注释18的函数,delete_dir_contents函数的实现:
int delete_dir_contents(const char *pathname,
int also_delete_dir,
const char *ignore)
{
int res = 0;
DIR *d;
d = opendir(pathname);
if (d == NULL) {
ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
return -errno;
}
res = _delete_dir_contents(d, ignore);
closedir(d);
if (also_delete_dir) {
if (rmdir(pathname)) {
ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
res = -1;
}
}
return res;
}
上面函数实现大概意思就是打开那个路径,然后递归查找删除里面所有的内容,完成卸载操作重要的一步,为什么说是重要的一步,因为卸载不仅仅是要删除package的组件信息和删除data/data下安装包的数据文件,还有一个就是删除应用的dex文件。
上面我没有提到,那我们回过头去找一下是在哪里做的:
private int deletePackageX(String packageName, int userId, int flags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
if (isPackageDeviceAdmin(packageName, userId)) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
boolean removedForAllUsers = false;
boolean systemUpdate = false;
// for the uninstall-updates case and restricted profiles, remember the per-
// userhandle installed state
int[] allUsers;
boolean[] perUserInstalled;
synchronized (mPackages) {
PackageSetting ps = mSettings.mPackages.get(packageName);
allUsers = sUserManager.getUserIds();
perUserInstalled = new boolean[allUsers.length];
for (int i = 0; i < allUsers.length; i++) {
perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
}
}
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
res = deletePackageLI(packageName,
(flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(userId),
true, allUsers, perUserInstalled,
flags | REMOVE_CHATTY, info, true);
systemUpdate = info.isRemovedPackageSystemUpdate;
if (res && !systemUpdate && mPackages.get(packageName) == null) {
removedForAllUsers = true;
}
if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
+ " removedForAllUsers=" + removedForAllUsers);
}
if (res) {
info.sendBroadcast(true, systemUpdate, removedForAllUsers);
// If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
null, packageName, null, null);
}
}
// Force a gc here.
Runtime.getRuntime().gc();
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
if (info.args != null) {
synchronized (mInstallLock) {
info.args.doPostDeleteLI(true); //18
}
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
我们接着deletePackageX函数那里开始,注释18那行代码就是删除dex文件的关键函数,我们可以跟踪一下删除dex文件流程:
boolean doPostDeleteLI(boolean delete) {
// XXX err, shouldn't we respect the delete flag?
cleanUpResourcesLI();
return true;
}
下面会有一些列的函数跳转:
void cleanUpResourcesLI() {
String sourceDir = getCodePath();
if (cleanUp()) {
int retCode = mInstaller.rmdex(sourceDir);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location "
+ sourceDir + ", retcode=" + retCode);
// we don't consider this to be a failure of the core package deletion
}
}
}
这里是不是似曾相识的味道,没错,经过类似的操作,最终会调到native installd服务的do_rm_dex函数:
static int do_rm_dex(char **arg, char reply[REPLY_MAX])
{
ALOGE("has do_rm_dex");
return rm_dex(arg[0]); /* pkgname */
}
再然后拼接了dex文件的路径,然后删除了这个dex文件,完事儿了。
int rm_dex(const char *path)
{
char dex_path[PKG_PATH_MAX];
if (validate_apk_path(path)) return -1;
if (create_cache_path(dex_path, path)) return -1;
ALOGV("unlink %s\n", dex_path);
if (unlink(dex_path) < 0) {
ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
return -1;
} else {
return 0;
}
}
总结一下,卸载过程总的来说是删除了应用的组件信息。data/data下的数据文件,以及data/dalvik-cache下的dex文件。
7. 总结
大体过程说一下,就是PAMS先解析apk,然后呢,再通过socket连接installed服务,进行安装与卸载操作。写的不够详细后面再重新组织补充语言。