static int main(int argc, char** argv) { // Skip over the first argument. argc--; argv++; bool generateFlag = false; String8 targetConfigStr; Vector<String8> splitApkPaths; String8 baseApkPath; while (argc > 0) { const String8 arg(*argv); if (arg == "--target") { argc--; argv++; if (argc < 1) { fprintf(stderr, "error: missing parameter for --target.\n"); usage(); return 1; } targetConfigStr.setTo(*argv); } else if (arg == "--split") { argc--; argv++; if (argc < 1) { fprintf(stderr, "error: missing parameter for --split.\n"); usage(); return 1; } splitApkPaths.add(String8(*argv)); } else if (arg == "--base") { argc--; argv++; if (argc < 1) { fprintf(stderr, "error: missing parameter for --base.\n"); usage(); return 1; } if (baseApkPath.size() > 0) { fprintf(stderr, "error: multiple --base flags not allowed.\n"); usage(); return 1; } baseApkPath.setTo(*argv); } else if (arg == "--generate") { generateFlag = true; } else if (arg == "--help") { help(); return 0; } else { fprintf(stderr, "error: unknown argument '%s'.\n", arg.string()); usage(); return 1; } argc--; argv++; } if (!generateFlag && targetConfigStr == "") { usage(); return 1; } if (baseApkPath.size() == 0) { fprintf(stderr, "error: missing --base argument.\n"); usage(); return 1; } // Find out some details about the base APK. AppInfo baseAppInfo; if (!getAppInfo(baseApkPath, baseAppInfo)) { fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.string()); return 1; } SplitDescription targetSplit; if (!generateFlag) { if (!SplitDescription::parse(targetConfigStr, &targetSplit)) { fprintf(stderr, "error: invalid --target config: '%s'.\n", targetConfigStr.string()); usage(); return 1; } // We don't want to match on things that will change at run-time // (orientation, w/h, etc.). removeRuntimeQualifiers(&targetSplit.config); } splitApkPaths.add(baseApkPath); KeyedVector<String8, Vector<SplitDescription> > apkPathSplitMap; KeyedVector<SplitDescription, String8> splitApkPathMap; Vector<SplitDescription> splitConfigs; const size_t splitCount = splitApkPaths.size(); for (size_t i = 0; i < splitCount; i++) { Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]); if (splits.isEmpty()) { fprintf(stderr, "error: invalid --split path: '%s'. No splits found.\n", splitApkPaths[i].string()); usage(); return 1; } apkPathSplitMap.replaceValueFor(splitApkPaths[i], splits); const size_t apkSplitDescriptionCount = splits.size(); for (size_t j = 0; j < apkSplitDescriptionCount; j++) { splitApkPathMap.replaceValueFor(splits[j], splitApkPaths[i]); } splitConfigs.appendVector(splits); } if (!generateFlag) { Vector<SplitDescription> matchingConfigs = select(targetSplit, splitConfigs); const size_t matchingConfigCount = matchingConfigs.size(); SortedVector<String8> matchingSplitPaths; for (size_t i = 0; i < matchingConfigCount; i++) { matchingSplitPaths.add(splitApkPathMap.valueFor(matchingConfigs[i])); } const size_t matchingSplitApkPathCount = matchingSplitPaths.size(); for (size_t i = 0; i < matchingSplitApkPathCount; i++) { if (matchingSplitPaths[i] != baseApkPath) { fprintf(stdout, "%s\n", matchingSplitPaths[i].string()); } } } else { generate(apkPathSplitMap, baseApkPath); } return 0; }