这里说明下:BootClassLoader的创建,是在zygote进程创建的时候,在ZygoteInit的main方法中,调用preLoad预加载类的时候,通过反射的方式创建BootClassLoader,BootClassLoader是一个单例的。
一、创建应用程序时创建PathClassLoader
在创建应用程序进程的时候,最终会执行到ActivityThread#handleBindApplication方法,而在ActivityThread#handleBindApplication方法中,会调用下面这段代码:
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
在这里就会执行创建该应用程序进程的PathClassLoader的过程。
1.ActivityThread#getPackageInfoNoCheck
@Override
@UnsupportedAppUsage
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
2.ActivityThread#getPackageInfo
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo != null) {
if (!isLoadedApkResourceDirsUpToDate(packageInfo, aInfo)) {
packageInfo.updateApplicationInfo(aInfo, null);
}
return packageInfo;
}
if (localLOGV) {
Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
? mBoundApplication.processName : null)
+ ")");
}
// 创建当前应用程序进程的package信息
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode
&& (aInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
if (mSystemThread && "android".equals(aInfo.packageName)) {
// 加载系统应用程序信息
// getSystemContext().mPackageInfo其实就是获取LoadedApk对象
// 这是获取系统进程的LoadedApk信息
packageInfo.installSystemApplicationInfo(aInfo,
getSystemContext().mPackageInfo.getClassLoader());
}
if (differentUser) {
// Caching not supported across users
} else if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
return packageInfo;
}
}
3.LoadedApk#installSystemApplicationInfo
在调用installSystemApplicationInfo方法的时候,会传入一个默认的ClassLoader,这个默认的ClassLoader其实就是通过调用LoadedApk的getClassLoader创建的。
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
assert info.packageName.equals("android");
mApplicationInfo = info;
// 设置默认的ClassLoader(系统进程的ClassLoader)
mDefaultClassLoader = classLoader;
mAppComponentFactory = createAppFactory(info, mDefaultClassLoader);
// 根据当前应用程序进程的applicationInfo实例化ClassLoader,这是通过工厂进行实例化的
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
new ApplicationInfo(mApplicationInfo));
}
4.AppComponentFactory#instantiateClassLoader
通过工厂实例化ClassLoader,这个工厂方法其实并没有实现任何操作,而是直接返回了mDefaultClassLoader这个默认的ClassLoader
public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
@NonNull ApplicationInfo aInfo) {
return cl;
}
5.LoadedApk#getClassLoader
@UnsupportedAppUsage
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
createOrUpdateClassLoaderLocked(null /*addedPaths*/);
}
return mClassLoader;
}
}
6.LoadedApk#createOrUpdateClassLoaderLocked
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
// 这个if判断是用于系统服务器,也就是系统进程的ClassLoader的创建的
if (mPackageName.equals("android")) {
// Note: This branch is taken for system server and we don't need to setup
// jit profiling support.
if (mClassLoader != null) {
// nothing to update
return;
}
if (mBaseClassLoader != null) {
mDefaultClassLoader = mBaseClassLoader;
} else {
mDefaultClassLoader = ClassLoader.getSystemClassLoader();
}
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
new ApplicationInfo(mApplicationInfo));
return;
}
// 当程序包是当前应用程序程序包时,避免进行binder调用。 活动管理器将执行确保在加速过程之前执行dexopt。
// 同样,当我们没有ActivityThread对象时,也不要调用binder。
if (mActivityThread != null
&& !Objects.equals(mPackageName, ActivityThread.currentPackageName())
&& mIncludeCode) {
try {
ActivityThread.getPackageManager().notifyPackageUse(mPackageName,
PackageManager.NOTIFY_PACKAGE_USE_CROSS_PACKAGE);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
if (mRegisterPackage) {
try {
ActivityManager.getService().addPackageDependency(mPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
// Lists for the elements of zip/code and native libraries.
//
// Both lists are usually not empty. We expect on average one APK for the zip component,
// but shared libraries and splits are not uncommon. We expect at least three elements
// for native libraries (app-based, system, vendor). As such, give both some breathing
// space and initialize to a small value (instead of incurring growth code).
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
boolean isBundledApp = mApplicationInfo.isSystemApp()
&& !mApplicationInfo.isUpdatedSystemApp();
// Vendor apks are treated as bundled only when /vendor/lib is in the default search
// paths. If not, they are treated as unbundled; access to system libs is limited.
// Having /vendor/lib in the default search paths means that all system processes
// are allowed to use any vendor library, which in turn means that system is dependent
// on vendor partition. In the contrary, not having /vendor/lib in the default search
// paths mean that the two partitions are separated and thus we can treat vendor apks
// as unbundled.
final String defaultSearchPaths = System.getProperty("java.library.path");
final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib");
if (mApplicationInfo.getCodePath() != null
&& mApplicationInfo.isVendor() && treatVendorApkAsUnbundled) {
isBundledApp = false;
}
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
if (isBundledApp) {
// For bundled apps, add the base directory of the app (e.g.,
// /system/app/Foo/) to the permitted paths so that it can load libraries
// embedded in module apks under the directory. For now, GmsCore is relying
// on this, but this isn't specific to the app. Also note that, we don't
// need to do this for unbundled apps as entire /data is already set to
// the permitted paths for them.
libraryPermittedPath += File.pathSeparator
+ Paths.get(getAppDir()).getParent().toString();
// This is necessary to grant bundled apps access to
// libraries located in subdirectories of /system/lib
libraryPermittedPath += File.pathSeparator + defaultSearchPaths;
}
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
// 如果不要求包含代码,则构建一个不包含代码路径的类加载器
// 但是我们仍然需要设置库搜索路径和允许的路径,因为NativeActivity依赖于它
// (它试图通过mIncludeCode == false从LoadedApk调用类加载器上的System.loadLibrary())。
if (!mIncludeCode) {
if (mDefaultClassLoader == null) {
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(
"" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null /* classLoaderName */);
setThreadPolicy(oldPolicy);
mAppComponentFactory = AppComponentFactory.DEFAULT;
}
if (mClassLoader == null) {
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
new ApplicationInfo(mApplicationInfo));
}
return;
}
/*
* 完成所有组合后(如有必要,请实际创建Java类加载器并在必要时设置JIT分析支持。
* 在许多情况下,这是一个APK,因此请避免在TextUtils中使用StringBuilder。
*/
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip +
", JNI path: " + librarySearchPath);
boolean needToSetupJitProfiles = false;
if (mDefaultClassLoader == null) {
// Temporarily disable logging of disk reads on the Looper thread
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
libraryPermittedPath);
// 创建mDefaultClassLoader,这个方法最终是调用了ApplicationLoaders#getClassLoader
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName, sharedLibraries);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
setThreadPolicy(oldPolicy);
// Setup the class loader paths for profiling.
needToSetupJitProfiles = true;
}
if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
// Temporarily disable logging of disk reads on the Looper thread as this is necessary
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, libPaths);
} finally {
setThreadPolicy(oldPolicy);
}
}
// /aepx/com.android.runtime/lib, /vendor/lib, /odm/lib and /product/lib
// are added to the native lib search paths of the classloader.
// Note that this is done AFTER the classloader is
// created by ApplicationLoaders.getDefault().getClassLoader(...). The
// reason is because if we have added the paths when creating the classloader
// above, the paths are also added to the search path of the linker namespace
// 'classloader-namespace', which will allow ALL libs in the paths to apps.
// Since only the libs listed in <partition>/etc/public.libraries.txt can be
// available to apps, we shouldn't add the paths then.
//
// However, we need to add the paths to the classloader (Java) though. This
// is because when a native lib is requested via System.loadLibrary(), the
// classloader first tries to find the requested lib in its own native libs
// search paths. If a lib is not found in one of the paths, dlopen() is not
// called at all. This can cause a problem that a vendor public native lib
// is accessible when directly opened via dlopen(), but inaccesible via
// System.loadLibrary(). In order to prevent the problem, we explicitly
// add the paths only to the classloader, and not to the native loader
// (linker namespace).
List<String> extraLibPaths = new ArrayList<>(4);
String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : "";
if (!defaultSearchPaths.contains("/apex/com.android.runtime/lib")) {
extraLibPaths.add("/apex/com.android.runtime/lib" + abiSuffix);
}
if (!defaultSearchPaths.contains("/vendor/lib")) {
extraLibPaths.add("/vendor/lib" + abiSuffix);
}
if (!defaultSearchPaths.contains("/odm/lib")) {
extraLibPaths.add("/odm/lib" + abiSuffix);
}
if (!defaultSearchPaths.contains("/product/lib")) {
extraLibPaths.add("/product/lib" + abiSuffix);
}
if (!extraLibPaths.isEmpty()) {
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, extraLibPaths);
} finally {
setThreadPolicy(oldPolicy);
}
}
if (addedPaths != null && addedPaths.size() > 0) {
final String add = TextUtils.join(File.pathSeparator, addedPaths);
ApplicationLoaders.getDefault().addPath(mDefaultClassLoader, add);
// Setup the new code paths for profiling.
needToSetupJitProfiles = true;
}
// Setup jit profile support.
//
// It is ok to call this multiple times if the application gets updated with new splits.
// The runtime only keeps track of unique code paths and can handle re-registration of
// the same code path. There's no need to pass `addedPaths` since any new code paths
// are already in `mApplicationInfo`.
//
// It is NOT ok to call this function from the system_server (for any of the packages it
// loads code from) so we explicitly disallow it there.
//
// It is not ok to call this in a zygote context where mActivityThread is null.
if (needToSetupJitProfiles && !ActivityThread.isSystem() && mActivityThread != null) {
setupJitProfileSupport();
}
// Call AppComponentFactory to select/create the main class loader of this app.
// Since this may call code in the app, mDefaultClassLoader must be fully set up
// before invoking the factory.
// Invoke with a copy of ApplicationInfo to protect against the app changing it.
if (mClassLoader == null) {
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
new ApplicationInfo(mApplicationInfo));
}
}
7.ApplicationLoaders#getClassLoader
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey,
String classLoaderName, List<ClassLoader> sharedLibraries) {
/*
* 这里理论上是系统类加载器,其实就是BootClassLoader
*/
ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
synchronized (mLoaders) {
if (parent == null) {
parent = baseParent;
}
/*
* If we're one step up from the base class loader, find
* something in our cache. Otherwise, we create a whole
* new ClassLoader for the zip archive.
*/
if (parent == baseParent) {
ClassLoader loader = mLoaders.get(cacheKey);
if (loader != null) {
return loader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent,
targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths");
GraphicsEnvironment.getInstance().setLayerPaths(
classloader, librarySearchPath, libraryPermittedPath);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (cacheKey != null) {
mLoaders.put(cacheKey, classloader);
}
return classloader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader loader = ClassLoaderFactory.createClassLoader(
zip, null, parent, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return loader;
}
}
8.ClassLoaderFactory#createClassLoader
这里就是创建应用程序进程的PathClassLoader对象的具体位置
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, String classloaderName,
List<ClassLoader> sharedLibraries) {
ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
? null
: sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
if (isPathClassLoaderName(classloaderName)) {
// 创建PathClassLoader对象,并且返回
return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
} else if (isDelegateLastClassLoaderName(classloaderName)) {
return new DelegateLastClassLoader(dexPath, librarySearchPath, parent,
arrayOfSharedLibraries);
}
throw new AssertionError("Invalid classLoaderName: " + classloaderName);
}
二、创建SystemServer进程时创建PathClassLoader
创建SystemServer进程的时候,也会创建该进程对应的PathClassLoader,从ZygoteInit#startSystemServer方法开始创建SystemServer进程,在通过fork zygote进程创建完成SystemServer进程之后,就会返回一个pid,当pid=0,表示就是fork子进程成功,则执行对应的子进程需要的操作,在pid=0的if条件分支中,会调用handleSystemServerProcess方法,在这里会创建SystemServer的PathClassLoader
网友评论