app 安装的流程:
1 网络下载应用安装――通过应用市场完成,没有安装界面
2 ADB工具安装――没有安装界面。
3 第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由 packageinstaller.apk应用处理安装及卸载过程的界面。
安装其实就是把apk文件copy到了对应的目录
1 system/app ——系统自带的应用程序,获得adb root权限才能删除 里面存储的都是系统的 app - apk 文件
2 data/app —————用户程序安装的目录。安装时把 apk文件复制到此目录 可以将文件取出并安装,和我们本身的apk 是一样的。
3 data/data —————开辟存放应用程序的数据的文件夹
包括我们应用的 so库,缓存文件 等等。
PackageManagerService源码:
首先我们看下packageManagerService的 main
方法中的代码:
public static final PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
这段代码呢,我们可以看到通过new 的方式创建了一个对象,并添加到了 ServiceManager
中,serviceManager 内部是一个 HashMap的集合,存储了很多相关的 binder
服务,缓存起来,我们在使用的时候, 会通过 getService(key)
的方式去 map
中获取。
在构造函数中,是用同步的方式初始化了解析所需要的文件目录:
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
我们可以看到在 构造函数中调用了 scanDirLI
方法, 我们继续跟进。
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
for (File file : files) {
... // 进行校验文件 格式
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
... // 删除了无效的文件目录
}
}
}
这里遍历的文件目录,就是我们上面的初始化的File, 比如我们 app的目录 就是data/app
下。 进行了遍历,下面我们进scanPackageLI
看看它都做了什么?
在里面做了两件比较重要的事情:
1.创建了PackageParser
对象
PackageParser pp = new PackageParser();
2.调用了 parsePackage
方法 并返回了 PackageParser.Package
对象。
pkg = pp.parsePackage(scanFile, parseFlags);
我们要在这里稍微停一下, 说说这个PackageParser.Package
. 为啥要停呢? 它有啥特别之处么? 让我们看一下它的类的信息就清楚了:
public final static class Package {
public String packageName;
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
// TODO: work towards making these paths invariant
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public String codePath;
/** Path of base APK */
public String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
... // 部分代码。
}
Ok, 你也看到了, 里面定义了 我们的packageName
、apk 路径 baseCodePath
以及 各种 Arraylist 来保存我们的 Activity
、Service
、权限
等等。
好的,我们继续往下面走。 下面我们的 主角从 PackageManagerService
切换到了 我们的 PackageParser
.
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
我们看到parsePakcage
转调用了parseMonolithicPackage
方法,让我们继续。
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
final AssetManager assets = new AssetManager();
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
不多说,直接进入我们的 parseBaseApk
方法。 这里有两点用说:
- 调用了
loadApkIntoAssetManager
方法呢,就是把我们app 的资源添加到了AssetManager
。
int cookie = assets.addAssetPath(apkPath);
2.调用了重载方法 解析AndroidManifest.xml
文件
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {}
解析Xml的代码,我们看着个分支:
if (tagName.equals("application")) {
... // 省略部分代码
if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
}
直接来看 parseBaseApplication
中的操作:
1.解析了application 节点中的相关信息 如 icon
、theme
等。
2.解析了application 节点下各个子节点的信息。
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, attrs, flags, outError);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.services.add(s);
}
我们只看其中的一个节点:
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
}
parseActivity
中解析了 <activity>
节点下的相关信息,比如 exported
、tag
、theme
、intent-filter
等,封装成了一个类 即Activity
。 然后执行了
owner.activities.add(a);
也就是添加到了 PackageParser.Package
中。
总结
从整体的角度看,我们所做的这一系列操作,其实只是在做一件事,创建一个PackageParser.Package
对象,然后填充它,然后 return 回去。