美文网首页
Android-PathClassLoader的创建

Android-PathClassLoader的创建

作者: zzq_nene | 来源:发表于2020-12-01 21:58 被阅读0次

    这里说明下: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

    相关文章

      网友评论

          本文标题:Android-PathClassLoader的创建

          本文链接:https://www.haomeiwen.com/subject/wqciqktx.html