引言
记录下PKMS初始化时xml文件和apk安装时的解析类。
1.frameworks/base/services/core/java/com/android/server/pm/Settings.java
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
private final File mPackageListFilename;
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
/key是类似“android.ui.system”这样的字段,在Android中每个应用都有一个UID,两个相同的UID的应用可以运行在/一个进程中,为了让两个应用运行在一个进程中,需要在manifest中设置sharedUserId这个属性,这个属性是字符串,但是在linux系统中uid是一个整型,因此就有了SharedUserSetting类型,这个类型除了name还有uid(对应linux中的uid),还有一个列表字段,用于记录系统中相同shardUserId的应用。/ final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<String, SharedUserSetting>();
/主要保存的是/system/etc/permissions/platform.xml中的permission标签内容,因为Android系统是基于linux的系统,有用户组的概念,platform定义了一些权限,并且定制了哪些用户组具有哪些权限,一旦应用属于某个用户组,那么它就有这个用户组的所有权限/ final PermissionSettings mPermissions;
1.1 Setting构造函数
Settings(File dataDir, PermissionSettings permission, Object lock) {
mLock = lock;
mPermissions = permission;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
Setting构造函数主要工作是创建系统文件夹,一些包管理的文件
packages.xml、packages-backup.xml是一组,用于描述系统所安装的Package信息,其中packages-backup.xml是packages.xml的备份
packages.list用于描述系统中存在的所有非系统自带的apk信息以及UID大于10000的apk。当APK有变化时,PKMS就会更新该文件。
1.2 addSharedUserLPw方法
该方法将shareUserId name和一个int类型的UID对应起来。UID的定义在Process.java中。
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
public static final int ROOT_UID = 0;
public static final int SYSTEM_UID = 1000;
public static final int PHONE_UID = 1001;
public static final int SHELL_UID = 2000;
@UnsupportedAppUsage
public static final int LOG_UID = 1007;
@UnsupportedAppUsage
public static final int WIFI_UID = 1010;
...
public static final int FIRST_APPLICATION_UID = 10000;
public static final int LAST_APPLICATION_UID = 19999;
Setting模块的AndroidManifest.xml里面,如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.settings"
coreApp="true"
android:sharedUserId="android.uid.system">
在xml里面android:sharedUserId属性设置为”android.uid.system”。sharedUserId这个属性主要有两个作用:
1.两个或者多个声明了同一种sharedUserId的应用可以共享彼此的数据
2.通过声明特定sharedUserId,该应用所在进程将赋予指定的UID。如Setting声明了system的uid,则就可以共享system用户所对应的权限。
除了了xml了声明sharedUserId外,应用编译的时候还必须使用对应的证书进行签名。如Setting需要platform的签名。
1.3 PID、UID、GID的区别
PID是进程的身份识别,程序一旦运行,就会给应用分配唯一的PID。一个应用可能包含多个进程,每个进程有唯一的一个PID。进程终止后PID被系统回收,再次打开应用,会分配一个PID(新进程的PID一般比之前的号大)。
调用adb shell ps可以查看系统运行的进程。
UID是用户ID。UID在linux中就是用户ID,表明哪个用户运行了这个程序,主要用于权限的管理。而Android为单用户系统,这时候UID被赋予了新的使命,数据共享,为了实现数据共享,android为每个应用都分配了不同的uid,不像传统的linux,每个用户相同就为之分配相同的UID。
GID时用户组ID。对于普通的应用程序来说GID等于UID,由于每个应用程序的UID和GID不相同,所以不管是native还是java层都能够达到保护私有数据的作用。
adb shell cat /proc/PID号/status
SharedUserSetting类架构
PKMS的构造函数创建一个Settings的实例mSettings,mSettings有三个成员变量mSharedUsers,mUserIds,mOtherUserIds。addSharedUserLPw方法都涉及这三个成员变量。SharedUserSetting的成员变量packages是一个PackageSetting类型的ArraySet。PackageSetting继承自PackageSettingBase,PackageSetting保存着package的多种信息。
2.SystemConfig类 2.1 SystemConfig构造函数
主要读取下面路径的配置 /system/etc/、/system/etc/、/vendor/etc、/odm/etc、/oem/etc、/product/etc 目录下sysconfig和permissions
SystemConfig() {
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
if (!skuProperty.isEmpty()) {
String skuDir = "sku_" + skuProperty;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions", skuDir),
odmPermissionFlag);
}
int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
}
SystemConfig构造函数中主要通过readPermissions函数将对应目录下的xml文件中定义的各个节点读取出来保存到SystemConfig成员变量中。在终端的/system/etc/permissions目录下可以看到很多xml配置文件,如下:
HWSTF:/system/etc/permissions $ ls -all
total 300
drwxr-xr-x 2 root root 4096 2018-08-08 00:01:00.000000000 +0800 .
drwxr-xr-x 26 root root 4096 2018-08-08 00:01:00.000000000 +0800 ..
-rw-r--r-- 1 root root 1515 2018-08-08 00:01:00.000000000 +0800 HiViewTunnel-core.xml
-rw-r--r-- 1 root root 830 2018-08-08 00:01:00.000000000 +0800 android.hardware.bluetooth_le.xml
-rw-r--r-- 1 root root 927 2018-08-08 00:01:00.000000000 +0800 android.hardware.faketouch.xml
-rw-r--r-- 1 root root 834 2018-08-08 00:01:00.000000000 +0800 android.hardware.fingerprint.xml
-rw-r--r-- 1 root root 942 2018-08-08 00:01:00.000000000 +0800 android.hardware.location.gps.xml
-rw-r--r-- 1 root root 949 2018-08-08 00:01:00.000000000 +0800 android.hardware.location.xml
-rw-r--r-- 1 root root 888 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.hce.xml
-rw-r--r-- 1 root root 891 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.hcef.xml
-rw-r--r-- 1 root root 921 2018-08-08 00:01:00.000000000 +0800 android.hardware.nfc.xml
-rw-r--r-- 1 root root 870 2018-08-08 00:01:00.000000000 +0800 android.hardware.opengles.aep.xml
-rw-r--r-- 1 root root 824 2018-08-08 00:01:00.000000000 +0800
...
这些配置文件都是编译时从framework指定位置拷贝过来的(framework/native/data/etc),下面是platform.xml里面的部分
<permissions>
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.READ_EXTERNAL_STORAGE" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<library name="org.apache.http.legacy"
file="/system/framework/org.apache.http.legacy.boot.jar" />
<allow-in-power-save package="com.android.providers.downloads" />
<!-- These are the packages that shouldn't run as system user -->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
<allow-in-data-usage-save package="com.dti.att" />
<feature name="android.hardware.vulkan.level" version="0" />
...
</permissions>
readPermissions方法内部调用readPermissionsFromXml方法来解析xml里面的各个节点,其中xml涉及到的标签内容有permission、assign-permission、library、feature等,这些标签的内容解析出来保存到SystemConfig的对应数据结构的全局变量中,以便管理查询。
feature用来描述设备是否支持硬件特性; library用于指定系统库,当应用程序运行时,系统会为进城加载一些必须的库; assign-permission将system中描述的permission与uid关联; permission将permission和gid关联。
总结下SystemConfig初始化时解析xml文件节点以及对应的全局变量。
3. PackageParser
这个类作用是解析APK,在其类中注释如下:
这个类主要用于解析apk安装包,它能解析单一apk文件,也能够解析multiple APKs(一个apk文件里面包含多个apk文件)。这些multiple APKs需要满足下面几个条件:
1.所有的apk必须具有完全相同的软件包包名,版本代码和签名证书
2.所有的apk必须具有唯一的拆分名称
3.所有安装必须含有一个单一的apk
解析步骤
1.将apk解析成package 2.将package转化为packageinfo
类结构
里面有很多内部类和方法,下面讲介绍里面的主要内部类以及部分解析的方法 3.1 内部类 3.1.1 NewPermissionInfo
记录新的权限
public static class NewPermissionInfo {
@UnsupportedAppUsage
public final String name;
@UnsupportedAppUsage
public final int sdkVersion;
public final int fileVersion;
public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
this.name = name;
this.sdkVersion = sdkVersion;
this.fileVersion = fileVersion;
}
}
3.1.2 SplitPermissionInfo 主要记录一个权限拆分为颗粒度更小的权限
public static class SplitPermissionInfo {
public final String rootPerm;
表示旧的权限拆分为颗粒度更小的权限
表示在那个版本上拆分
public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
this.rootPerm = rootPerm;
this.newPerms = newPerms;
this.targetSdk = targetSdk;
}
}
3.1.3 ParsePackageItemArgs 主要为解析包单个item的参数
static class ParsePackageItemArgs {
final Package owner;
final String[] outError;
final int nameRes;
final int labelRes;
final int iconRes;
final int roundIconRes;
final int logoRes;
final int bannerRes;
String tag;
TypedArray sa;
ParsePackageItemArgs(Package _owner, String[] _outError,
int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
int _bannerRes) {
owner = _owner;
outError = _outError;
nameRes = _nameRes;
labelRes = _labelRes;
iconRes = _iconRes;
logoRes = _logoRes;
bannerRes = _bannerRes;
roundIconRes = _roundIconRes;
}
}
3.1.4 ParseComponentArgs 主要为解析包中单个组件的参数
@VisibleForTesting
public static class ParseComponentArgs extends ParsePackageItemArgs {
final String[] sepProcesses;
final int processRes;
final int descriptionRes;
final int enabledRes;
int flags;
public ParseComponentArgs(Package _owner, String[] _outError,
int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
int _bannerRes,
String[] _sepProcesses, int _processRes,
int _descriptionRes, int _enabledRes) {
super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
_bannerRes);
sepProcesses = _sepProcesses;
processRes = _processRes;
descriptionRes = _descriptionRes;
enabledRes = _enabledRes;
}
}
3.1.5 PackageLite
表示在解析过程中的一个轻量级的独立的安装包
public static class PackageLite {
@UnsupportedAppUsage
public final String packageName;
public final int versionCode;
public final int versionCodeMajor;
@UnsupportedAppUsage
public final int installLocation;
public final VerifierInfo[] verifiers;
public final String[] splitNames;
public final boolean[] isFeatureSplits;
public final String[] usesSplitNames;
public final String[] configForSplit;
public final String codePath;
public final String baseCodePath;
public final String[] splitCodePaths;
public final int baseRevisionCode;
public final int[] splitRevisionCodes;
public final boolean coreApp;
public final boolean debuggable;
public final boolean multiArch;
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode;
this.versionCodeMajor = baseApk.versionCodeMajor;
this.installLocation = baseApk.installLocation;
this.verifiers = baseApk.verifiers;
this.splitNames = splitNames;
this.isFeatureSplits = isFeatureSplits;
this.usesSplitNames = usesSplitNames;
this.configForSplit = configForSplit;
this.codePath = codePath;
this.baseCodePath = baseApk.codePath;
this.splitCodePaths = splitCodePaths;
this.baseRevisionCode = baseApk.revisionCode;
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp;
this.debuggable = baseApk.debuggable;
this.multiArch = baseApk.multiArch;
this.use32bitAbi = baseApk.use32bitAbi;
this.extractNativeLibs = baseApk.extractNativeLibs;
this.isolatedSplits = baseApk.isolatedSplits;
}
3.1.6 ApkLite 表示解析过程中的一个轻量级独立的apk
public static class ApkLite {
public final String codePath;
public final String packageName;
public final String splitName;
public boolean isFeatureSplit;
public final String configForSplit;
public final String usesSplitName;
public final int versionCode;
public final int versionCodeMajor;
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
public final SigningDetails signingDetails;
public final boolean coreApp;
public final boolean debuggable;
public final boolean multiArch;
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
public ApkLite(String codePath, String packageName, String splitName,
boolean isFeatureSplit,
String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
SigningDetails signingDetails, boolean coreApp,
boolean debuggable, boolean multiArch, boolean use32bitAbi,
boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
this.isFeatureSplit = isFeatureSplit;
this.configForSplit = configForSplit;
this.usesSplitName = usesSplitName;
this.versionCode = versionCode;
this.versionCodeMajor = versionCodeMajor;
this.revisionCode = revisionCode;
this.installLocation = installLocation;
this.signingDetails = signingDetails;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.coreApp = coreApp;
this.debuggable = debuggable;
this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi;
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
}
备注:PackageLite和ApkLite代表不同的含义,前者是包,后者是指apk,一个包中可能包含多个apk
3.1.7 SplitNameComparator 表示类比较器,在拆包中排序用到
private static class SplitNameComparator implements Comparator<String> {
@Override
public int compare(String lhs, String rhs) {
if (lhs == null) {
return -1;
} else if (rhs == null) {
return 1;
} else {
return lhs.compareTo(rhs);
}
}
}
3.1.8 Package 表示从磁盘上的apk文件解析出来的完整包,一个包由一个基础的apk和多个拆分的apk构成。
public final static class Package implements Parcelable {
@UnsupportedAppUsage
public String packageName;
public String manifestPackageName;
public String[] splitNames;
public String volumeUuid;
public String codePath;
public String baseCodePath;
public String[] splitCodePaths;
public int baseRevisionCode;
public int[] splitRevisionCodes;
public int[] splitFlags;
public int[] splitPrivateFlags;
public boolean baseHardwareAccelerated;
@UnsupportedAppUsage
public ApplicationInfo applicationInfo = new ApplicationInfo();
@UnsupportedAppUsage
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
@UnsupportedAppUsage
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);
@UnsupportedAppUsage
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
@UnsupportedAppUsage
public ArrayList<String> protectedBroadcasts;
public Package parentPackage;
public ArrayList<Package> childPackages;
public String staticSharedLibName = null;
public long staticSharedLibVersion = 0;
public ArrayList<String> libraryNames = null;
@UnsupportedAppUsage
public ArrayList<String> usesLibraries = null;
public ArrayList<String> usesStaticLibraries = null;
public long[] usesStaticLibrariesVersions = null;
public String[][] usesStaticLibrariesCertDigests = null;
@UnsupportedAppUsage
public ArrayList<String> usesOptionalLibraries = null;
@UnsupportedAppUsage
public String[] usesLibraryFiles = null;
public ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
public ArrayList<String> mOriginalPackages = null;
public String mRealPackage = null;
public ArrayList<String> mAdoptPermissions = null;
@UnsupportedAppUsage
public Bundle mAppMetaData = null;
@UnsupportedAppUsage
public int mVersionCode;
public int mVersionCodeMajor;
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
}
@UnsupportedAppUsage
public String mVersionName;
@UnsupportedAppUsage
public String mSharedUserId;
@UnsupportedAppUsage
public int mSharedUserLabel;
@UnsupportedAppUsage
@NonNull public SigningDetails mSigningDetails = SigningDetails.UNKNOWN;
@UnsupportedAppUsage
public int mPreferredOrder = 0;
public long[] mLastPackageUsageTimeInMills =
new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
@UnsupportedAppUsage
public Object mExtras;
@UnsupportedAppUsage
public ArrayList<ConfigurationInfo> configPreferences = null;
@UnsupportedAppUsage
public ArrayList<FeatureInfo> reqFeatures = null;
public ArrayList<FeatureGroupInfo> featureGroups = null;
@UnsupportedAppUsage
public int installLocation;
public boolean coreApp;
public boolean mRequiredForAllUsers;
public String mRestrictedAccountType;
public String mRequiredAccountType;
public String mOverlayTarget;
public String mOverlayCategory;
public int mOverlayPriority;
public boolean mOverlayIsStatic;
public int mCompileSdkVersion;
public String mCompileSdkVersionCodename;
@UnsupportedAppUsage
public ArraySet<String> mUpgradeKeySets;
@UnsupportedAppUsage
public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
public String cpuAbiOverride;
public boolean use32bitAbi;
public byte[] restrictUpdateHash;
public boolean visibleToInstantApps;
public boolean isStub;
@UnsupportedAppUsage
public Package(String packageName) {
this.packageName = packageName;
this.manifestPackageName = packageName;
applicationInfo.packageName = packageName;
applicationInfo.uid = -1;
}
...
}
3.1.9 Component
public static abstract class IntentInfo extends IntentFilter {
@UnsupportedAppUsage
public boolean hasDefault;
@UnsupportedAppUsage
public int labelRes;
@UnsupportedAppUsage
public CharSequence nonLocalizedLabel;
@UnsupportedAppUsage
public int icon;
@UnsupportedAppUsage
public int logo;
@UnsupportedAppUsage
public int banner;
public int preferred;
...
}
public static abstract class Component<II extends IntentInfo> {
@UnsupportedAppUsage
public final ArrayList<II> intents;
@UnsupportedAppUsage
public final String className;
@UnsupportedAppUsage
public Bundle metaData;
@UnsupportedAppUsage
public Package owner;
public int order;
ComponentName componentName;
String componentShortName;
...
}
3.1.10 Permission 继承于Component,对应AndroidManifest里面的标签
public final static class Permission extends Component<IntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final PermissionInfo info;
@UnsupportedAppUsage
public boolean tree;
@UnsupportedAppUsage
public PermissionGroup group;
public Permission(Package _owner) {
super(_owner);
info = new PermissionInfo();
}
...
}
继承于Component,对应AndroidManifest里面的标签
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
@UnsupportedAppUsage
public final ActivityInfo info;
private boolean mHasMaxAspectRatio;
private boolean hasMaxAspectRatio() {
return mHasMaxAspectRatio;
}
public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
super(args, _info);
info = _info;
info.applicationInfo = args.owner.applicationInfo;
}
public void setPackageName(String packageName) {
super.setPackageName(packageName);
info.packageName = packageName;
}
...
}
一些其他的基本类似类在这里就不再详细的介绍,下面看下类里面的一些方法:
3.2 内部方法 里面的方法基本上是和解析相关的方法,这里以parseActivity为例说明,其他的解析大同小异。
3.2.1 parsePackage 这个类是解析package最开始的方法,其他的解析方法都是从这个入口进入的,这里分为两种解析,一种是single APK ,另一种是cluster APKs。
@UnsupportedAppUsage
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (packageFile.isDirectory()) {
parsed = parseClusterPackage(packageFile, flags);
} else {
parsed = parseMonolithicPackage(packageFile, flags);
}
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}
3.2.2 parseActivity 这个方法主要是解析AndroidManifest中activity标签的内容,并将其保存到PackageParser.Activity对象中。
private Activity parseActivity(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
if (cachedArgs.mActivityArgs == null) {
cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_icon,
R.styleable.AndroidManifestActivity_roundIcon,
R.styleable.AndroidManifestActivity_logo,
R.styleable.AndroidManifestActivity_banner,
mSeparateProcesses,
R.styleable.AndroidManifestActivity_process,
R.styleable.AndroidManifestActivity_description,
R.styleable.AndroidManifestActivity_enabled);
}
cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
cachedArgs.mActivityArgs.sa = sa;
cachedArgs.mActivityArgs.flags = flags;
Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
if (outError[0] != null) {
sa.recycle();
return null;
}
boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
if (setExported) {
a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
}
a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
a.info.applicationInfo.uiOptions);
String parentName = sa.getNonConfigurationString(
R.styleable.AndroidManifestActivity_parentActivityName,
Configuration.NATIVE_CONFIG_VERSION);
if (parentName != null) {
String parentClassName = buildClassName(a.info.packageName, parentName, outError);
if (outError[0] == null) {
a.info.parentActivityName = parentClassName;
} else {
Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
parentName);
outError[0] = null;
}
}
String str;
str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
if (str == null) {
a.info.permission = owner.applicationInfo.permission;
} else {
a.info.permission = str.length() > 0 ? str.toString().intern() : null;
}
str = sa.getNonConfigurationString(
R.styleable.AndroidManifestActivity_taskAffinity,
Configuration.NATIVE_CONFIG_VERSION);
a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
owner.applicationInfo.taskAffinity, str, outError);
a.info.splitName =
sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0);
a.info.flags = 0;
if (sa.getBoolean(
R.styleable.AndroidManifestActivity_multiprocess, false)) {
a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
(owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
|| sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
}
if (!receiver) {
if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
hardwareAccelerated)) {
a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
}
a.info.launchMode = sa.getInt(
R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
a.info.documentLaunchMode = sa.getInt(
R.styleable.AndroidManifestActivity_documentLaunchMode,
ActivityInfo.DOCUMENT_LAUNCH_NONE);
a.info.maxRecents = sa.getInt(
R.styleable.AndroidManifestActivity_maxRecents,
ActivityManager.getDefaultAppRecentsLimitStatic());
a.info.configChanges = getActivityConfigChanges(
sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
a.info.softInputMode = sa.getInt(
R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
a.info.persistableMode = sa.getInteger(
R.styleable.AndroidManifestActivity_persistableMode,
ActivityInfo.PERSIST_ROOT_ONLY);
if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
}
a.info.screenOrientation = sa.getInt(
R.styleable.AndroidManifestActivity_screenOrientation,
SCREEN_ORIENTATION_UNSPECIFIED);
setActivityResizeMode(a.info, sa, owner);
if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
false)) {
a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
}
if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
&& sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
== TypedValue.TYPE_FLOAT) {
a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
0 ));
}
a.info.lockTaskLaunchMode =
sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestActivity_directBootAware,
false);
a.info.requestedVrComponent =
sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
a.info.rotationAnimation =
sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_UNSPECIFIED);
a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
ActivityInfo.COLOR_MODE_DEFAULT);
if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
}
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
}
a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestActivity_directBootAware,
false);
}
if (a.info.directBootAware) {
owner.applicationInfo.privateFlags |=
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
}
boolean visibleToEphemeral =
sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
if (visibleToEphemeral) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
}
sa.recycle();
if (receiver && (owner.applicationInfo.privateFlags
&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
if (a.info.processName == owner.packageName) {
outError[0] = "Heavy-weight applications can not have receivers in main process";
}
}
if (outError[0] != null) {
return null;
}
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
if (parser.getName().equals("intent-filter")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, true , true ,
intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
a.order = Math.max(intent.getOrder(), a.order);
a.intents.add(intent);
}
final int visibility = visibleToEphemeral
? IntentFilter.VISIBILITY_EXPLICIT
: !receiver && isImplicitlyExposedIntent(intent)
? IntentFilter.VISIBILITY_IMPLICIT
: IntentFilter.VISIBILITY_NONE;
intent.setVisibilityToInstantApp(visibility);
if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
if (intent.isImplicitlyVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
if (LOG_UNSAFE_BROADCASTS && receiver
&& (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
for (int i = 0; i < intent.countActions(); i++) {
final String action = intent.getAction(i);
if (action == null || !action.startsWith("android.")) continue;
if (!SAFE_BROADCASTS.contains(action)) {
Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+ owner.packageName + " as requested at: "
+ parser.getPositionDescription());
}
}
}
} else if (!receiver && parser.getName().equals("preferred")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, false , false ,
intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in preferred at "
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
if (owner.preferredActivityFilters == null) {
owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
}
owner.preferredActivityFilters.add(intent);
}
final int visibility = visibleToEphemeral
? IntentFilter.VISIBILITY_EXPLICIT
: !receiver && isImplicitlyExposedIntent(intent)
? IntentFilter.VISIBILITY_IMPLICIT
: IntentFilter.VISIBILITY_NONE;
intent.setVisibilityToInstantApp(visibility);
if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
if (intent.isImplicitlyVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
} else if (parser.getName().equals("meta-data")) {
if ((a.metaData = parseMetaData(res, parser, a.metaData,
outError)) == null) {
return null;
}
} else if (!receiver && parser.getName().equals("layout")) {
parseLayout(res, parser, a);
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
if (receiver) {
Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
if (receiver) {
outError[0] = "Bad element under <receiver>: " + parser.getName();
} else {
outError[0] = "Bad element under <activity>: " + parser.getName();
}
return null;
}
}
}
if (!setExported) {
a.info.exported = a.intents.size() > 0;
}
return a;
}
3.3 PackageParser总结 上图画出了PackageParser解析Apk文件,得到的主要的数据结构,实际的内容远多于这些,我们仅保留了四大组件和权限相关的内容。
上面这些类,全部是定义于PackageParser中的内部类,这些内部类主要的作用就是保存AndroidManifest.xml解析出的对应信息。 以PackageParser.Activity为例,注意到该类持有ActivityInfo类,继承自 Component< ActivityIntentInfo>。其中,ActivityInfo用于保存Activity的信息;Component类是一个模板,对应元素类型是ActivityIntentInfo,顶层基类IntentFilter。四大组件中的其它成员,也有类似的继承结构。
这种设计的原因是:Package除了保存信息外,还需要支持Intent匹配查询。例如,当收到某个Intent后,由于ActivityIntentInfo继承自IntentFilter,因此它能判断自己是否满足Intent的要求。如果满足,则返回对应的ActivityInfo。
PackageParser整个扫描过程如下:
PackageParser首先解析出ApkLite,得到每个Apk文件的简化信息;
利用所有的ApkLite以及Xml中其它信息,解析出PackageLite;
利用PackageLite中的信息及XML中的其它信息,解析出Package信息;
? Package中基本上涵盖了AndroidManifest中涉及的所有信息。
注意:在上述的解析过程中,PackageParser利用AssetManager存储了Package中资源文件的地址。
|