Android-APK dynamic library on 32bit/64bit platforms

Source: Internet
Author: User
Tags symlink

Android-APK dynamic library on 32bit/64bit platforms

At present 64bit android system also slowly more, see also apk claim to support 64bit system, and then packed into a arm64-v8a directory, put a 64bit so, however, the apk Code does not load so according to the specifications, resulting in a series of file not found exceptions ~

 

Apk lib directory:

First look at the lib package directory in the apk:

Different types of cpu <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4NCjxoMiBpZD0 = "pms installation path"> PMS installation path:

The pms install process is complicated, so only the so-relatedScanPackageDirtyLIFunction:

Private PackageParser. package scanPackageDirtyLI (PackageParser. package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {... // invoke installer to do the actual installation // create data directory related items as external apk // rameworksativecmdsinstalldcommands. create int ret = ** createDataDirsLI ** (pkgName, pkg. applicationInfo. uid, pkg. applicationInfo. seinfo );... I F (isSystemApp (pkg )&&! IsUpdatedSystemApp (pkg )){... setBundledAppAbisAndRoots (pkg, pkgSetting );... setNativeLibraryPaths (pkg);} else {setNativeLibraryPaths (pkg );... if (isAsec) {copyRet = NativeLibraryHelper. findSupportedAbi (handle, abiList);} else {copyRet = NativeLibraryHelper. copyNativeBinariesForSupportedAbi (handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs);} setNativeLibraryPaths (pkg); if (DEBUG_ I NSTALL) Slog. I (TAG, Linking native library dir for + path); final int [] userIds = sUserManager. getUserIds (); synchronized (mInstallLock) {// Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. we do not provide // this symlink for 64 bit libraries. if (pkg. applicationInfo. primaryCpuAbi! = Null &&**! VMRuntime. is64BitAbi (pkg. applicationInfo. primaryCpuAbi) **) {final String nativeLibPath = pkg. applicationInfo. nativeLibraryDir; for (int userId: userIds) {if (mInstaller. linkNativeLibraryDirectory (pkg. packageName, nativeLibPath, userId) <0) {throw new PackageManagerException (INSTALL_FAILED_INTERNAL_ERROR, Failed linking native library dir (user = + userId + ));}}}}}}

Check the installation and configuration functions of the system app.SetBundledAppAbisAndRoots:

    /**     * Calculate the abis and roots for a bundled app. These can uniquely     * be determined from the contents of the system partition, i.e whether     * it contains 64 or 32 bit shared libraries etc. We do not validate any     * of this information, and instead assume that the system was built     * sensibly.     */    private void setBundledAppAbisAndRoots(PackageParser.Package pkg,                                           PackageSetting pkgSetting) {        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());        // If /system/lib64/apkname exists, assume that is the per-package        // native library directory to use; otherwise use /system/lib/apkname.        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);        setBundledAppAbi(pkg, apkRoot, apkName);        // pkgSetting might be null during rescan following uninstall of updates        // to a bundled app, so accommodate that possibility.  The settings in        // that case will be established later from the parsed package.        //        // If the settings aren't null, sync them up with what we've just derived.        // note that apkRoot isn't stored in the package settings.        if (pkgSetting != null) {            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;        }    }

Mainly inSetBundledAppAbiMedium:

    /**     * Deduces the ABI of a bundled app and sets the relevant fields on the     * parsed pkg object.     *     * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}     *        under which system libraries are installed.     * @param apkName the name of the installed package.     */    private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {        final File codeFile = new File(pkg.codePath);...        if (has64BitLibs && !has32BitLibs) {            // The package has 64 bit libs, but not 32 bit libs. Its primary            // ABI should be 64 bit. We can safely assume here that the bundled            // native libraries correspond to the most preferred ABI in the list.            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];            pkg.applicationInfo.secondaryCpuAbi = null;        } else if (has32BitLibs && !has64BitLibs) {            // The package has 32 bit libs but not 64 bit libs. Its primary            // ABI should be 32 bit.            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];            pkg.applicationInfo.secondaryCpuAbi = null;        } else if (has32BitLibs && has64BitLibs) {            // The application has both 64 and 32 bit bundled libraries. We check            // here that the app declares multiArch support, and warn if it doesn't.            //            // We will be lenient here and record both ABIs. The primary will be the            // ABI that's higher on the list, i.e, a device that's configured to prefer            // 64 bit apps will see a 64 bit primary ABI,            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {                Slog.e(TAG, Package:  + pkg +  has multiple bundled libs, but is not multiarch.);            }            if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];            } else {                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];            }        } else {            pkg.applicationInfo.primaryCpuAbi = null;            pkg.applicationInfo.secondaryCpuAbi = null;        } }

Determine the primaryCpuAbi secondaryCpuAbi variable value based on the file query. This determines whether the apk is fork by 64bit or 32bit zygote and the path searched by nativelibrary.

Main functions of nativelibrarySetNativeLibraryPaths:

/**     * Derive and set the location of native libraries for the given package,     * which varies depending on where and how the package was installed.     */    private void setNativeLibraryPaths(PackageParser.Package pkg) {        final ApplicationInfo info = pkg.applicationInfo;        final String codePath = pkg.codePath;        final File codeFile = new File(codePath);        final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);        final boolean asecApp = isForwardLocked(info) || isExternal(info);        info.nativeLibraryRootDir = null;        info.nativeLibraryRootRequiresIsa = false;        info.nativeLibraryDir = null;        info.secondaryNativeLibraryDir = null;        if (isApkFile(codeFile)) {            // Monolithic install            if (bundledApp) {                // If /system/lib64/apkname exists, assume that is the per-package                // native library directory to use; otherwise use /system/lib/apkname.                final String apkRoot = calculateBundledApkRoot(info.sourceDir);                final boolean is64Bit = VMRuntime.is64BitInstructionSet(                        getPrimaryInstructionSet(info));                // This is a bundled system app so choose the path based on the ABI.                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this                // is just the default path.                final String apkName = deriveCodePathName(codePath);                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;                info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,                        apkName).getAbsolutePath();                if (info.secondaryCpuAbi != null) {                    final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;                    info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),                            secondaryLibDir, apkName).getAbsolutePath();                }            } else if (asecApp) {                info.nativeLibraryRootDir = new File(codeFile.getParentFile(), LIB_DIR_NAME)                        .getAbsolutePath();            } else {                final String apkName = deriveCodePathName(codePath);                info.nativeLibraryRootDir = new File(mAppLib32InstallDir, apkName)                        .getAbsolutePath();            }            info.nativeLibraryRootRequiresIsa = false;            info.nativeLibraryDir = info.nativeLibraryRootDir;        } else {            // Cluster install            info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();            info.nativeLibraryRootRequiresIsa = true;            info.nativeLibraryDir = new File(info.nativeLibraryRootDir,                    getPrimaryInstructionSet(info)).getAbsolutePath();            if (info.secondaryCpuAbi != null) {                info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,                        VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();            }        }    }

Determine whether nativelibrarydir depends on info according to pkg application info.Info. primaryCpuAbi

    private static String getPrimaryInstructionSet(ApplicationInfo info) {        if (info.primaryCpuAbi == null) {            return getPreferredInstructionSet();        }        return VMRuntime.getInstructionSet(info.primaryCpuAbi);    }

Non-system apk will callNativeLibraryHelperOfFindSupportedAbiParse the. apk file and find the matched abi in the package subdirectory of the lib directory based on the system suportabilist.

The lib directory starting with the article. On the 64-bit machine, suportabilist is:

 public static final String[] SUPPORTED_ABIS = getStringList(ro.product.cpu.abilist, ,);
root@:/ # getprop ro.product.cpu.abilist                                 arm64-v8a,armeabi-v7a,armeabi

Will matchArm64-v8aAssignedInfo. primaryCpuAbi

CopyNativeBinariesForSupportedAbiCopy the matched lib directory to the local directory.

Finally, set NativeLibraryPaths,
If the match is 64bit, that isArm64-v8aThenDo not create soft links for/data/../lib, which is different from 32bit

System. loadlibrary

As a standard interface for dynamic library loading, you can directly view the implementation:

    public static void loadLibrary(String libName) {        Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());    }

To Runtime. java:

/*     * Searches for and loads the given shared library using the given ClassLoader.     */    void loadLibrary(String libraryName, ClassLoader loader) {        if (loader != null) {            String filename = loader.findLibrary(libraryName);            if (filename == null) {                // It's not necessarily true that the ClassLoader used                // System.mapLibraryName, but the default setup does, and it's                // misleading to say we didn't find libMyLibrary.so when we                // actually searched for liblibMyLibrary.so.so.                throw new UnsatisfiedLinkError(loader +  couldn't find  +                                               System.mapLibraryName(libraryName) + );            }            String error = doLoad(filename, loader);            if (error != null) {                throw new UnsatisfiedLinkError(error);            }            return;        }        String filename = System.mapLibraryName(libraryName);        List
  
    candidates = new ArrayList
   
    ();        String lastError = null;        for (String directory : mLibPaths) {            String candidate = directory + filename;            candidates.add(candidate);            if (IoUtils.canOpenReadOnly(candidate)) {                String error = doLoad(candidate, loader);                if (error == null) {                    return; // We successfully loaded the library. Job done.                }                lastError = error;            }        }        if (lastError != null) {            throw new UnsatisfiedLinkError(lastError);        }        throw new UnsatisfiedLinkError(Library  + libraryName +  not found; tried  + candidates);    }
   
  

HereClassLoader loaderIn fact, some related Child class parent classes and parameters will be initialized during apk startup.

Record the initial process at startup:

ActivityThread. java-handleBindApplication final ContextImpl appContext = ContextImpl. createAppContext (this, data.info); LoadedApk pi = getPackageInfo (Response app, data. compatInfo, appContext. getClassLoader (), false, true, false); ContextImpl. java-getClassLoader () LoadedApk. java-getClassLoader (): mLibDir = aInfo. nativeLibraryDir; mClassLoader = ApplicationLoaders. getDefault (). getClassLoader (zip, lib, mBaseClassLoader); ApplicationLoaders. java-getClassLoader (...) pathClassLoader pathClassloader = new PathClassLoader (zip, libPath, parent); // The libPath here is the aInfo uploaded above. nativeLibraryDirpublic class PathClassLoader extends BaseDexClassLoaderpublic class BaseDexClassLoader extends ClassLoader

Loader. findLibrary (libraryName );

    /**     * Finds the named native code library on any of the library     * directories pointed at by this instance. This will find the     * one in the earliest listed directory, ignoring any that are not     * readable regular files.     *     * @return the complete path to the library or {@code null} if no     * library was found     */    public String findLibrary(String libraryName) {        String fileName = System.mapLibraryName(libraryName);        for (File directory : nativeLibraryDirectories) {            String path = new File(directory, fileName).getPath();            if (IoUtils.canOpenReadOnly(path)) {                return path;            }        }        return null;    }

HereNativeLibraryDirectoriesThat is, when the values are set for the previous series of constructorAInfo. nativeLibraryDir

The subsequent logic will not be described. Find the directory based on the name, and then call the local JNI for final call.DlopenTo load and open so, it must be the same number of digits, which indicates whether the current process belongs to 64bit or 32bit. This will be in the zygote fork time zone, which is also the info. primaryCpuAbi obtained by PMS resolution.

AMS requests zygote fork app process to select

Focus only on relevant codeStartProcessLockedFunction:

    private final void startProcessLocked(ProcessRecord app, String hostingType,            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {... String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;            if (requiredAbi == null) {                requiredAbi = Build.SUPPORTED_ABIS[0];            }            String instructionSet = null;            if (app.info.primaryCpuAbi != null) {                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);            }            app.gids = gids;            app.requiredAbi = requiredAbi;            app.instructionSet = instructionSet;            // Start the process.  It will either succeed and return a result containing            // the PID of the new process, or else throw a RuntimeException.            boolean isActivityProcess = (entryPoint == null);            if (entryPoint == null) entryPoint = android.app.ActivityThread;            checkTime(startTime, startProcess: asking zygote to start proc);            Process.ProcessStartResult startResult = Process.start(entryPoint,                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,                    app.info.dataDir, entryPointArgs);            checkTime(startTime, startProcess: returned from zygote!);...}

True socket request implementation in Process:

return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

OpenZygoteSocketIfNeededThe communication will be selected based on the passed abiSocket

On 64-bit machines, two zygote services are started at startup to receive 64 32 apk requests:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote    class main    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netdservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary    class main    socket zygote_secondary stream 660 root system    onrestart restart zygote

We can see that the two zygote processes are basically the same. The difference is 64bit 32bit.
The socket registration during startup of these two zygote processes is not much to say.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.