您的位置:首页 > 移动开发 > Android开发

android中是如何对包进行解析--解析ContentProvider

2015-08-21 14:29 204 查看
如果了解过android的启动流程,我们知道android在启动的时候会去解析/data/system和/data/app下已经存在的apk。

那么是从哪里开始对这些包进行解析的呢?

1.

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;
}
android在启动的时候,会根据init.rc配置文件去执行PackageManagerService中的main方法。

该方法的操作很简单,就是生成一个PackageManagerService的对象,然后加载到ServiceManager进程中进行管理。

从这里我们就可以看出,ServiceManager进程就是用来管理android中Framework层的一些系统Service。

2.

main方法中代码很少,那么PackageManagerService是在哪里解析包的呢?

实际上在new一个PackageManagerService对象的时候,就对已存在的apk进行了解析。

下面我们对/data/app/下的apk解析过程做一个分析。

synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());

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);
在这里对android的一些路径进行了获取,这里我们就看到android默认的用户安装路径mAppInstallDir就是/data/app/。

知道用户的apk所在路径,下面就可以去遍历该路径下的所有apk,然后进行解析。

if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
mAppInstallObserver.startWatching();
scanDirLI(mAppInstallDir, 0, scanMode, 0);

mDrmAppInstallObserver = new AppDirObserver(
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
mDrmAppInstallObserver.startWatching();
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanMode, 0);


通过上面的scanDirLI方法,对/data/app/下面的apk进行遍历。
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
Log.d(TAG, "No files in app dir " + dir);
return;
}

if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir);
}

int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);
if (!isPackageFilename(files[i])) {
// Ignore entries which are not apk's
continue;
}
PackageParser.Package pkg = scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
// Don't mess around with apps in system partition.
if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
// Delete the apk
Slog.w(TAG, "Cleaning up failed install of " + file);
file.delete();
}
}
}
通过dir.list()我们得到/data/app/下所有的文件名,然后在后面的for循环中逐个判断是否是*.apk文件,如果是,就调用scanPackageLI进行解析;

如果不是,就继续循环,寻找下一个apk文件。

下面进入scanPackageLI

private PackageParser.Package scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
String scanPath = scanFile.getPath();
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
scanPath, mMetrics, parseFlags);
if (pkg == null) {
mLastScanError = pp.getParseError();
return null;
}
PackageSetting ps = null;
PackageSetting updatedPkg;


scanPackageLI返回PackageParser.Package类型的值,里面存储了对应apk的解析出来的信息。

final PackageParser.Package pkg = pp.parsePackage(scanFile,
scanPath, mMetrics, parseFlags);
这里就是去解析apk文件,从scanpackageLI的代码看出pp实际是一个PackageParser对象。

3. PackageParser.java

上面的pp.parsePackage会调用如下:

try {
// XXXX todo: need to figure out correct configuration.
pkg = parsePackage(res, parser, flags, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}


这里调用重载的parsePackage方法。

在这里面回去分析AndroidManifest.xml文件,当获取到application标签时,回去解析下面存在的控件。

if (tagName.equals("application")) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}

foundApp = true;
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
parseApplication就是去解析标签<application>中的资源。

下面我们来看一下parseApplication是怎么解析provider的。

while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}

String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
hardwareAccelerated);
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);

} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}

owner.providers.add(p);

}


我们看到上面会根据获取到不同的标签文件去解析不同的东西。

当我们的标签是provider时,就会调用parseProvider去解析。解析完成后就会把得到的Provider加入到owner.provider中。

private Provider parseProvider(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestProvider);

if (mParseProviderArgs == null) {
mParseProviderArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestProvider_name,
com.android.internal.R.styleable.AndroidManifestProvider_label,
com.android.internal.R.styleable.AndroidManifestProvider_icon,
com.android.internal.R.styleable.AndroidManifestProvider_logo,
mSeparateProcesses,
com.android.internal.R.styleable.AndroidManifestProvider_process,
com.android.internal.R.styleable.AndroidManifestProvider_description,
com.android.internal.R.styleable.AndroidManifestProvider_enabled);
mParseProviderArgs.tag = "<provider>";
}

mParseProviderArgs.sa = sa;
mParseProviderArgs.flags = flags;

Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
if (outError[0] != null) {
sa.recycle();
return null;
}

boolean providerExportedDefault = false;

if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
// For compatibility, applications targeting API level 16 or lower
// should have their content providers exported by default, unless they
// specify otherwise.
providerExportedDefault = true;
}

p.info.exported = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestProvider_exported,
providerExportedDefault);

String cpname = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);

p.info.isSyncable = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestProvider_syncable,
false);

String permission = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
if (str == null) {
str = permission;
}
if (str == null) {
p.info.readPermission = owner.applicationInfo.permission;
} else {
p.info.readPermission =
str.length() > 0 ? str.toString().intern() : null;
}
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
if (str == null) {
str = permission;
}
if (str == null) {
p.info.writePermission = owner.applicationInfo.permission;
} else {
p.info.writePermission =
str.length() > 0 ? str.toString().intern() : null;
}

p.info.grantUriPermissions = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
false);

p.info.multiprocess = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
false);

p.info.initOrder = sa.getInt(
com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
0);

p.info.flags = 0;

if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
false)) {
p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
if (p.info.exported) {
Slog.w(TAG, "Provider exported request ignored due to singleUser: "
+ p.className + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
p.info.exported = false;
}
}

sa.recycle();

if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
// A heavy-weight application can not have providers in its main process
// We can do direct compare because we intern all strings.
if (p.info.processName == owner.packageName) {
outError[0] = "Heavy-weight applications can not have providers in main process";
return null;
}
}

if (cpname == null) {
outError[0] = "<provider> does not include authorities attribute";
return null;
}
p.info.authority = cpname.intern();

if (!parseProviderTags(res, parser, attrs, p, outError)) {
return null;
}

return p;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: