我是靠谱客的博主 顺利铃铛,最近开发中收集的这篇文章主要介绍android 5.0后对于apk 跑32 64 的逻辑Inherit from hardware-specific part of the product configuration.Inherit from the common Open Source product configuration.Copy the 64-bit primary, 32-bit secondary zygote startup script Set the zygote property to select t,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1, 是否是 64 bit apk,在对应的 full_sky828_8s70.mk 里面,这里主要包含64 bit apk的支持, 还有zygote的启动方式,64 bit apk fork的简要过程

Inherit from hardware-specific part of the product configuration.

$(call inherit-product, device/skyworth/sky828_8s70/device.mk)

Inherit from the common Open Source product configuration.

(callinheritproduct, (SRC_TARGET_DIR)/product/core_64_bit.mk)
(callinheritproduct, (SRC_TARGET_DIR)/product/aosp_base.mk)
$(call inherit-product-if-exists, vendor/google/products/gms.mk)

这个里面主要的内容是:

Copy the 64-bit primary, 32-bit secondary zygote startup script

PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.rc:root/init.zygote64_32.rc

Set the zygote property to select the 64-bit primary, 32-bit secondary script

This line must be parsed before the one in core_minimal.mk

PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote64_32

TARGET_SUPPORTS_32_BIT_APPS := true
TARGET_SUPPORTS_64_BIT_APPS := true

这里主要是表明编译系统support 32 , 64 apk, 还有把zygote 名字ro.zygote设置为 zygote64_32,
在L之前启动zygote 是直接在 init.rc 里面通过
service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server
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 netd
这个来启动的, 但L上由于可能有2个zygote, 所以把zygote的启动脚本抽象到一个单独的rc文件里面, 根据ro.zygote来区分。
这个单独的脚本是在init rc里面include的。 具体如下
import /init.environ.rc
import /init.usb.rc
import /init. ro.hardware.rcimport/init. {ro.zygote}.rc
import /init.trace.rc

同时在 zygote64_32 脚本这个里面做了什么了?
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 netd

service 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

这里启动了2个zygote, 其中一个是bin是 32bit的, 一个bin是64 bit的, 注意这里的socket的名字 , 一个是zygote, 一个是zygote_secondary,第一个是primary zygote。我们之前知道, 在启动apk的时候, 是从zygote出来的, 所以在L上, 启动一个process之前, 会判断是多少bit,然后向对应的zygote请求fork 子进程出来, 我们知道fork 子进程会集成父进程的属性, 所以子 进程的位数跟父进程一致,从而如果我们要看一个 apk是多少bit, 可以通过看父进程是32bit的zygote,还是 64 bit的zygote
下面我们看一下启动 process的时候, 是如何判断 apk的 指令集的, 最终start 一个app的process 都是call到activitymanagerservice里面去的,startProcessLocked

String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;==》 这个值是在安装 apk的时候拿出来的,这里这个值对于按照正常规范写的有native code的apk, 这个值就是有值的,不是空, 但是对于没有nativelib的,比如是pure Java 的apk, 这个就是null。
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
==》这里的意思是系统无法根据lib 来判断apk是多少bit的, 就会用系统support的 第一个 abi 来作为这个apk的 指令集, 这就是为什么在 系统上, 如果有pure java的 apk , 肯定会跑 64 bit,而不是32 bit。在以64 系统为主的 系统上,系统support的 abi 如下:
shell@sky828_8s70:/ # getprop ro.product.cpu.abilist
arm64-v8a,armeabi-v7a,armeabi

        String instructionSet = null;
        if (app.info.primaryCpuAbi != null) {
            instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
        }

我说一下 这里 abi 跟 instructionset的关系, 对于64 为主, 也只是 32 bit 的系统, abi就是 arm64-v8a,armeabi-v7a,armeabi

那instructionset了, 其实 是根据 abi算过来的, arm64-v8a 对应的 指令集就是 arm64, 而 armeabi-v7a,armeabi 对应的就是 arm

然后才会开始真的startprocess,这里会传进入 abi, 跟 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);
在往后看, 会call到
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); 我们看 openZygoteSocketIfNeeded , 这个里面, 由此可以看出 判断apk 跑哪个进程,还是根据前面的 abi来的。

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx(“Error connecting to primary zygote”, ioe);
}
}

    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }

    // The primary zygote didn't match. Try the secondary.
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
        secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
        }
    }

    if (secondaryZygoteState.matches(abi)) {
        return secondaryZygoteState;
    }

    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);

}

这里的 primaryZygoteState 就是连接到名字叫zygote的 primary zygote, secondaryZygoteState 代表的是第二个,
这里首先会判断apk需要的abi是否在primary zygote支持的abi里面, 如果不在 才会去secondary zygote去看。最终会根据找到对应的。
那系统是如何判断primary zygote 支持哪些 abi的了?
Matches方法主要是
boolean matches(String abi) {
return abiList.contains(abi);
} 我们看 abilist是如何获得到 ,

public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();

        try {
            zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                    LocalSocketAddress.Namespace.RESERVED));

            zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

            zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                    zygoteSocket.getOutputStream()), 256);
        } catch (IOException ex) {
            try {
                zygoteSocket.close();
            } catch (IOException ignore) {
            }

            throw ex;
        }

        String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
        Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);

        return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                Arrays.asList(abiListString.split(",")));
    }

然后getAbiList又是如何的了?

private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
throws IOException {
// Each query starts with the argument count (1 in this case)
writer.write(“1”);
// … followed by a new-line.
writer.newLine();
// … followed by our only argument.
writer.write(“–query-abi-list”);
writer.newLine();
writer.flush();

    // The response is a length prefixed stream of ASCII bytes.
    int numBytes = inputStream.readInt();
    byte[] bytes = new byte[numBytes];
    inputStream.readFully(bytes);

    return new String(bytes, StandardCharsets.US_ASCII);
}

发现这个是还是通过socket 去查询结果的。 我们去看看server端的东西。

if defined(LP64)

static const char ABI_LIST_PROPERTY[] = “ro.product.cpu.abilist64”;
static const char ZYGOTE_NICE_NAME[] = “zygote64”;

else

static const char ABI_LIST_PROPERTY[] = “ro.product.cpu.abilist32”;
static const char ZYGOTE_NICE_NAME[] = “zygote”;

endif

在以 64 位为主的系统上,这两个属性的结果如下:
127|shell@sky828_8s70:/ # getprop ro.product.cpu.abilist64
arm64-v8a
shell@sky828_8s70:/ # getprop ro.product.cpu.abilist32
armeabi-v7a,armeabi
shell@sky828_8s70:/ #

在zygote 启动的main 函数里面, 会根据这两个属性获取到自己支持的abi
int main(int argc, char* const argv[])
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
// Older kernels don’t understand PR_SET_NO_NEW_PRIVS and return
// EINVAL. Don’t die on such kernels.
if (errno != EINVAL) {
LOG_ALWAYS_FATAL(“PR_SET_NO_NEW_PRIVS failed: %s”, strerror(errno));
return 12;
}
}

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;

// Everything up to '--' or first non '-' arg goes to the vm.
//
// The first argument after the VM args is the "parent dir", which
// is currently unused.
//
// After the parent dir, we expect one or more the following internal
// arguments :
//
// --zygote : Start in zygote mode
// --start-system-server : Start the system server.
// --application : Start in application (stand alone, non zygote) mode.
// --nice-name : The nice name for this process.
//
// For non zygote starts, these arguments will be followed by
// the main class name. All remaining arguments are passed to
// the main method of this class.
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
//
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.

int i;
for (i = 0; i < argc; i++) {
    if (argv[i][0] != '-') {
        break;
    }
    if (argv[i][1] == '-' && argv[i][2] == 0) {
        ++i; // Skip --.
        break;
    }
    runtime.addOption(strdup(argv[i]));
}

// Parse runtime arguments.  Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

++i;  // Skip unused "parent dir" argument.
while (i < argc) {
    const char* arg = argv[i++];
    if (strcmp(arg, "--zygote") == 0) {
        zygote = true;
        niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) {
        startSystemServer = true;
    } else if (strcmp(arg, "--application") == 0) {
        application = true;
    } else if (strncmp(arg, "--nice-name=", 12) == 0) {
        niceName.setTo(arg + 12);
    } else if (strncmp(arg, "--", 2) != 0) {
        className.setTo(arg);
        break;
    } else {
        --i;
        break;
    }
}

Vector<String8> args;
if (!className.isEmpty()) {
    // We're not in zygote mode, the only argument we need to pass
    // to RuntimeInit is the application argument.
    //
    // The Remainder of args get passed to startup class main(). Make
    // copies of them before we overwrite them with the process name.
    args.add(application ? String8("application") : String8("tool"));
    runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
    // We're in zygote mode.
    maybeCreateDalvikCache();

    if (startSystemServer) {
        args.add(String8("start-system-server"));
    }

    char prop[PROP_VALUE_MAX];
    if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
        LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
            ABI_LIST_PROPERTY);
        return 11;
    }

    String8 abiFlag("--abi-list=");
    abiFlag.append(prop);
    args.add(abiFlag);

    // In zygote mode, pass all remaining arguments to the zygote
    // main() method.
    for (; i < argc; ++i) {
        args.add(String8(argv[i]));
    }
}

if (!niceName.isEmpty()) {
    runtime.setArgv0(niceName.string());
    set_process_name(niceName.string());
}

if (zygote) {
    runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {
    runtime.start("com.android.internal.os.RuntimeInit", args);
} else {
    fprintf(stderr, "Error: no class name or --zygote supplied.n");
    app_usage();
    LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    return 10;
}

}
Native里面最后通过 runtime.start(“com.android.internal.os.ZygoteInit”, args); call到 java层上面,也就是com.android.internal.os.ZygoteInit 这个类的main方法
在java里面就会把这里放到args里面的 指令集取出来,
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();

        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }

        registerZygoteSocket(socketName); 

我们再客户端通过socket 请求对应的socket 拿到的 abi,其实就是这里拿出来的 指,

2,apk的安装过程, 主要是packagemanagerservice里面 判断 apk 跑多少bit的这段逻辑。
Pms 是在systemserver里面启动起来的,
// Start the package manager.
Slog.i(TAG, “Package Manager”);
mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();//这里的isFirstBoot 就是判断系统是否是第一次启动,恢复出厂设置, 然后再启动,也认为是第一次,为什么第一次启动 apk 做优化,没有转圈圈,就与这个有关系
try {
mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
reportWtf(“performing boot dexopt”, e);
}

    try {
        ActivityManagerNative.getDefault().showBootMessage(
                context.getResources().getText(
                        com.android.internal.R.string.android_upgrading_starting_apps),
                false);
    } catch (RemoteException e) {
    }

我们看一下scan system app下的大概过程
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), “app”);
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

注意下这里的scanFlags,是下面这个值, 主要注意第二个参数 SCAN_DEFER_DEX,这个表示是推迟dex动作, 也就是说在在扫描这个目录的时候,并不是扫描一个apk,就优化一个apk, 而是放到一个待优化列表,等扫描结束之后, 一起来做优化动作。
// Set flag to monitor and not change apk file paths when
// scanning install directories.
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
通过这个函数会call到下面这个function
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles(); 列出这个目录下的所有file,注意其实这里不是file,而是目录, 因为L上 apk的形式多了一级目录,eg/system/app/helloworld/helloworld.apk 是这种形式
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, “No files in app dir ” + dir);
return;
}

    if (DEBUG_PACKAGE_SCANNING) {
        Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                + " flags=0x" + Integer.toHexString(parseFlags));
    }
    循环安装这个目录下的每个 apk
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }
        try {
            scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                    scanFlags, currentTime, null);
        } catch (PackageManagerException e) {
            Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());

            // Delete invalid userdata apps
            if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                    e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                if (file.isDirectory()) {
                    FileUtils.deleteContents(file);
                }
                file.delete();
            }
        }
    }
}

我们根据这个scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
在往下走,
* Scan a package and return the newly parsed package.
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, “Parsing: ” + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(); 主要用来解析apk里面AndroidManifest.xml 文件的
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);

    if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
        parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
    }

    final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(scanFile, parseFlags);真正开始解析 apk里面AndroidManifest.xml 文件的,这个过程请看后面的流程 parsePackage, 这里主要是解析mafifest文件, 把信息记录到package对象里面
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    }

    PackageSetting ps = null;
    PackageSetting updatedPkg;
    // reader
    synchronized (mPackages) {
        // Look to see if we already know about this package.
        String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
        if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
            // This package has been renamed to its original name.  Let's
            // use that.
            ps = mSettings.peekPackageLPr(oldName);
        }
        // If there was no original package, see one for the real package name.
        if (ps == null) {
            ps = mSettings.peekPackageLPr(pkg.packageName);
        }
        // Check to see if this package could be hiding/updating a system
        // package.  Must look for it either under the original or real
        // package name depending on our state.
        updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
        if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
    }
    boolean updatedPkgBetter = false;
    // First check if this is a system package that may involve an update
    if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
        if (ps != null && !ps.codePath.equals(scanFile)) {
            // The path has changed from what was last scanned...  check the
            // version of the new path against what we have stored to determine
            // what to do.
            if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
            if (pkg.mVersionCode < ps.versionCode) {
                // The system package has been updated and the code path does not match
                // Ignore entry. Skip it.
                logCriticalInfo(Log.INFO, "Package " + ps.name + " at " + scanFile
                        + " ignored: updated version " + ps.versionCode
                        + " better than this " + pkg.mVersionCode);
                if (!updatedPkg.codePath.equals(scanFile)) {
                    Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
                            + ps.name + " changing from " + updatedPkg.codePathString
                            + " to " + scanFile);
                    updatedPkg.codePath = scanFile;
                    updatedPkg.codePathString = scanFile.toString();
                    // This is the point at which we know that the system-disk APK
                    // for this package has moved during a reboot (e.g. due to an OTA),
                    // so we need to reevaluate it for privilege policy.
                    if (locationIsPrivileged(scanFile)) {
                        updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
                    }
                }
                updatedPkg.pkg = pkg;
                throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
            } else {
                // The current app on the system partition is better than
                // what we have updated to on the data partition; switch
                // back to the system partition version.
                // At this point, its safely assumed that package installation for
                // apps in system partition will go through. If not there won't be a working
                // version of the app
                // writer
                synchronized (mPackages) {
                    // Just remove the loaded entries from package lists.
                    mPackages.remove(ps.name);
                }

                logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
                        + " reverting from " + ps.codePathString
                        + ": new version " + pkg.mVersionCode
                        + " better than installed " + ps.versionCode);

                InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                        ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                        getAppDexInstructionSets(ps));
                synchronized (mInstallLock) {
                    args.cleanUpResourcesLI();
                }
                synchronized (mPackages) {
                    mSettings.enableSystemPackageLPw(ps.name);
                }
                updatedPkgBetter = true;
            }
        }
    }

    if (updatedPkg != null) {
        // An updated system app will not have the PARSE_IS_SYSTEM flag set
        // initially
        parseFlags |= PackageParser.PARSE_IS_SYSTEM;

        // An updated privileged app will not have the PARSE_IS_PRIVILEGED
        // flag set initially
        if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
            parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
        }
    }

    // Verify certificates against what was last scanned
    collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);

    /*
     * A new system app appeared, but we already had a non-system one of the
     * same name installed earlier.
     */
    boolean shouldHideSystemApp = false;
    if (updatedPkg == null && ps != null
            && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
        /*
         * Check to make sure the signatures match first. If they don't,
         * wipe the installed application and its data.
         */
        if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                != PackageManager.SIGNATURE_MATCH) {
            logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
                    + " signatures don't match existing userdata copy; removing");
            deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
            ps = null;
        } else {
            /*
             * If the newly-added system app is an older version than the
             * already installed version, hide it. It will be scanned later
             * and re-added like an update.
             */
            if (pkg.mVersionCode < ps.versionCode) {
                shouldHideSystemApp = true;
                logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
                        + " but new version " + pkg.mVersionCode + " better than installed "
                        + ps.versionCode + "; hiding system");
            } else {
                /*
                 * The newly found system app is a newer version that the
                 * one previously installed. Simply remove the
                 * already-installed application and replace it with our own
                 * while keeping the application data.
                 */
                logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
                        + " reverting from " + ps.codePathString + ": new version "
                        + pkg.mVersionCode + " better than installed " + ps.versionCode);
                InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                        ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                        getAppDexInstructionSets(ps));
                synchronized (mInstallLock) {
                    args.cleanUpResourcesLI();
                }
            }
        }
    }

    // The apk is forward locked (not public) if its code and resources
    // are kept in different files. (except for app in either system or
    // vendor path).
    // TODO grab this value from PackageSettings
    if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
        if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
            parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
        }
    }

    // TODO: extend to support forward-locked splits
    String resourcePath = null;
    String baseResourcePath = null;
    if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
        if (ps != null && ps.resourcePathString != null) {
            resourcePath = ps.resourcePathString;
            baseResourcePath = ps.resourcePathString;
        } else {
            // Should not happen at all. Just log an error.
            Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
       }
    } else {
        resourcePath = pkg.codePath;
        baseResourcePath = pkg.baseCodePath;
    }

    // Set application objects path explicitly.
    pkg.applicationInfo.setCodePath(pkg.codePath);
    pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
    pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
    pkg.applicationInfo.setResourcePath(resourcePath);
    pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
    pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);

    // Note that we invoke the following method only if we are about to unpack an application
    PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);

    /*
     * If the system app should be overridden by a previously installed
     * data, hide the system app now and let the /data/app scan pick it up
     * again.
     */
    if (shouldHideSystemApp) {
        synchronized (mPackages) {
            /*
             * We have to grant systems permissions before we hide, because
             * grantPermissions will assume the package update is trying to
             * expand its permissions.
             */
            grantPermissionsLPw(pkg, true, pkg.packageName);
            mSettings.disableSystemPackageLPw(pkg.packageName);
        }
    }

    return scannedPkg;
}
#

parsePackage:
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
注意,我们这里是目录, 而不是文件, 所以会走return parseClusterPackage(packageFile, flags); 再往下走

private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);

    if (mOnlyCoreApps && !lite.coreApp) {
        throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                "Not a coreApp: " + packageDir);
    }

    final AssetManager assets = new AssetManager();
    try {
        // Load the base and all splits into the AssetManager
        // so that resources can be overriden when parsing the manifests.
        loadApkIntoAssetManager(assets, lite.baseCodePath, flags);

        if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
            for (String path : lite.splitCodePaths) {
                loadApkIntoAssetManager(assets, path, flags);
            }
        }

        final File baseApk = new File(lite.baseCodePath);
        final Package pkg = parseBaseApk(baseApk, assets, flags);
        if (pkg == null) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                    "Failed to parse base APK: " + baseApk);
        }

        if (!ArrayUtils.isEmpty(lite.splitNames)) {
            final int num = lite.splitNames.length;
            pkg.splitNames = lite.splitNames;
            pkg.splitCodePaths = lite.splitCodePaths;
            pkg.splitFlags = new int[num];

            for (int i = 0; i < num; i++) {
                parseSplitApk(pkg, i, assets, flags);
            }
        }

        pkg.codePath = packageDir.getAbsolutePath();
        return pkg;
    } finally {
        IoUtils.closeQuietly(assets);
    }
}

这里主要看两个函数,一个是 parseClusterPackageLite, 一个是 parseBaseApk, 其中要明白两个class的含义, 其中packagelite是一个轻量级的package的信息, 主要只包含下面的信息
public static class PackageLite {
public final String packageName;
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;

    /** Names of any split APKs, ordered by parsed splitName */
    public final String[] splitNames;

    /**
     * Path where this package was found on disk. For monolithic packages
     * this is path to single base APK file; for cluster packages this is
     * path to the cluster directory.
     */
    public final String codePath;

    /** Path of base APK */
    public final String baseCodePath;
    /** Paths of any split APKs, ordered by parsed splitName */
    public final String[] splitCodePaths;

    public final boolean coreApp;
    public final boolean multiArch;

但是Package 就是一个apk的详细信息, 比如这个apk 里面的activity,service,broadcast,contentprovider 列表, 内容比较多。我只贴一部分
public final static class Package {

    public String packageName;
    /** Names of any split APKs, ordered by parsed splitName */
    public String[] splitNames;

    // TODO: work towards making these paths invariant

    /**
     * Path where this package was found on disk. For monolithic packages
     * this is path to single base APK file; for cluster packages this is
     * path to the cluster directory.
     */
    public String codePath;

    /** Path of base APK */
    public String baseCodePath;
    /** Paths of any split APKs, ordered by parsed splitName */
    public String[] splitCodePaths;

    /** Flags of any split APKs; ordered by parsed splitName */
    public int[] splitFlags;

    public boolean baseHardwareAccelerated;

    // For now we only support one application per package.
    public final ApplicationInfo applicationInfo = new ApplicationInfo();

    public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
    public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
    public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
    public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
    public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
    public final ArrayList<Service> services = new ArrayList<Service>(0);
    public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);

    public final ArrayList<String> requestedPermissions = new ArrayList<String>();
    public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();

    public ArrayList<String> protectedBroadcasts;

然后来看函数 final PackageLite lite = parseClusterPackageLite(packageDir, 0);
private static PackageLite parseClusterPackageLite(File packageDir, int flags)
throws PackageParserException {
final File[] files = packageDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
“No packages found in split”);
}

    String packageName = null;
    int versionCode = 0;

    final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
    for (File file : files) {
        if (isApkFile(file)) {
            final ApkLite lite = parseApkLite(file, flags);

            // Assert that all package names and version codes are
            // consistent with the first one we encounter.
            if (packageName == null) {
                packageName = lite.packageName;
                versionCode = lite.versionCode;
            } else {
                if (!packageName.equals(lite.packageName)) {
                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                            "Inconsistent package " + lite.packageName + " in " + file
                            + "; expected " + packageName);
                }
                if (versionCode != lite.versionCode) {
                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                            "Inconsistent version " + lite.versionCode + " in " + file
                            + "; expected " + versionCode);
                }
            }

            // Assert that each split is defined only once
            if (apks.put(lite.splitName, lite) != null) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                        "Split name " + lite.splitName
                        + " defined more than once; most recent was " + file);
            }
        }
    }

    final ApkLite baseApk = apks.remove(null);
    if (baseApk == null) {
        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                "Missing base APK in " + packageDir);
    }

    // Always apply deterministic ordering based on splitName
    final int size = apks.size();

    String[] splitNames = null;
    String[] splitCodePaths = null;
    if (size > 0) {
        splitNames = new String[size];
        splitCodePaths = new String[size];

        splitNames = apks.keySet().toArray(splitNames);
        Arrays.sort(splitNames, sSplitNameComparator);

        for (int i = 0; i < size; i++) {
            splitCodePaths[i] = apks.get(splitNames[i]).codePath;
        }
    }

    final String codePath = packageDir.getAbsolutePath();
    return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);
}

其中paseapklite 就是拿到了如下信息
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
installLocation, verifiers, signatures, coreApp, multiArch);
其中这两个packageSplit.first, packageSplit.second对于一般的apk 都是 null, 是没有拆分的,这些信息都是从manifest 文件里面parse 出来的,最后返回的 是return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);
其中codepath就是 /system/app/helloworld 这个目录, baseapk就是上面的 apklite, 另外splitNames, splitCodePaths 都是null, 这里parseapklite就讲完了。

然后我们看 final Package pkg = parseBaseApk(baseApk, assets, flags); 这里里面对四大组件的详细 解析, 最后会走到这个函数
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
这里我不多讲, 会解析manefest里面的很多东西, 主要包括权限, 四大组件等信息,
最后解析application里面四大组件的地方再这里
private boolean parseBaseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
基本的位置在下面
String tagName = parser.getName();
if (tagName.equals(“activity”)) {
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
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);

        }

这里这四个过程就是分别解析manifest里面 四大组件, 然后加到我们的package对象里面对应的四个list里面去。记录这些信息。
这样子解析manefest的大致过程就说完了。

最后

以上就是顺利铃铛为你收集整理的android 5.0后对于apk 跑32 64 的逻辑Inherit from hardware-specific part of the product configuration.Inherit from the common Open Source product configuration.Copy the 64-bit primary, 32-bit secondary zygote startup script Set the zygote property to select t的全部内容,希望文章能够帮你解决android 5.0后对于apk 跑32 64 的逻辑Inherit from hardware-specific part of the product configuration.Inherit from the common Open Source product configuration.Copy the 64-bit primary, 32-bit secondary zygote startup script Set the zygote property to select t所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(28)

评论列表共有 0 条评论

立即
投稿
返回
顶部