140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski/* 240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * Copyright (C) 2014 The Android Open Source Project 340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * 440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * you may not use this file except in compliance with the License. 640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * You may obtain a copy of the License at 740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * 840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * 1040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * Unless required by applicable law or agreed to in writing, software 1140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 1240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * See the License for the specific language governing permissions and 1440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski * limitations under the License. 1540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski */ 1640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 1740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <algorithm> 1840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <cstdio> 1940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 2040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include "aapt/AaptUtil.h" 2140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 2240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include "Grouper.h" 2340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include "Rule.h" 2440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include "RuleGenerator.h" 2540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include "SplitDescription.h" 2642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski#include "SplitSelector.h" 2740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 2840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <androidfw/AssetManager.h> 2940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <androidfw/ResourceTypes.h> 3040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <utils/KeyedVector.h> 3140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski#include <utils/Vector.h> 3240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 3340e8eefbedcafc51948945647d746daaee092f16Adam Lesinskiusing namespace android; 3440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 3540e8eefbedcafc51948945647d746daaee092f16Adam Lesinskinamespace split { 3640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 3740e8eefbedcafc51948945647d746daaee092f16Adam Lesinskistatic void usage() { 3840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski fprintf(stderr, 3940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski "split-select --help\n" 4042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski "split-select --target <config> --base <path/to/apk> [--split <path/to/apk> [...]]\n" 4142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski "split-select --generate --base <path/to/apk> [--split <path/to/apk> [...]]\n" 4240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski "\n" 4340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " --help Displays more information about this program.\n" 4440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " --target <config> Performs the Split APK selection on the given configuration.\n" 4540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " --generate Generates the logic for selecting the Split APK, in JSON format.\n" 4642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski " --base <path/to/apk> Specifies the base APK, from which all Split APKs must be based off.\n" 4740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " --split <path/to/apk> Includes a Split APK in the selection process.\n" 4840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski "\n" 4940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " Where <config> is an extended AAPT resource qualifier of the form\n" 5040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " 'resource-qualifiers:extended-qualifiers', where 'resource-qualifiers' is an AAPT resource\n" 5140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " qualifier (ex: en-rUS-sw600dp-xhdpi), and 'extended-qualifiers' is an ordered list of one\n" 5240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " qualifier (or none) from each category:\n" 5340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " Architecture: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips\n"); 5440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 5540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 5640e8eefbedcafc51948945647d746daaee092f16Adam Lesinskistatic void help() { 5740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 5840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski fprintf(stderr, "\n" 5940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " Generates the logic for selecting a Split APK given some target Android device configuration.\n" 6040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " Using the flag --generate will emit a JSON encoded tree of rules that must be satisfied in order\n" 6140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " to install the given Split APK. Using the flag --target along with the device configuration\n" 6240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " will emit the set of Split APKs to install, following the same logic that would have been emitted\n" 6340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski " via JSON.\n"); 6440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 6540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 6640e8eefbedcafc51948945647d746daaee092f16Adam LesinskiVector<SplitDescription> select(const SplitDescription& target, const Vector<SplitDescription>& splits) { 6740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const SplitSelector selector(splits); 6840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return selector.getBestSplits(target); 6940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 7040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 7142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinskivoid generate(const KeyedVector<String8, Vector<SplitDescription> >& splits, const String8& base) { 7240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<SplitDescription> allSplits; 7340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t apkSplitCount = splits.size(); 7440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < apkSplitCount; i++) { 7540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski allSplits.appendVector(splits[i]); 7640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 7740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const SplitSelector selector(allSplits); 7842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski KeyedVector<SplitDescription, sp<Rule> > rules(selector.getRules()); 7940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 8042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski bool first = true; 8140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski fprintf(stdout, "[\n"); 8240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < apkSplitCount; i++) { 8342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (splits.keyAt(i) == base) { 8442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski // Skip the base. 8542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski continue; 8642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 8742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 8842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (!first) { 8942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stdout, ",\n"); 9042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 9142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski first = false; 9242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 9340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski sp<Rule> masterRule = new Rule(); 9440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski masterRule->op = Rule::OR_SUBRULES; 9540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const Vector<SplitDescription>& splitDescriptions = splits[i]; 9640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t splitDescriptionCount = splitDescriptions.size(); 9740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t j = 0; j < splitDescriptionCount; j++) { 9840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski masterRule->subrules.add(rules.valueFor(splitDescriptions[j])); 9940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 10040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski masterRule = Rule::simplify(masterRule); 10142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stdout, " {\n \"path\": \"%s\",\n \"rules\": %s\n }", 10240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splits.keyAt(i).string(), 10342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski masterRule->toJson(2).string()); 10440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 10542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stdout, "\n]\n"); 10640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 10740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 10840e8eefbedcafc51948945647d746daaee092f16Adam Lesinskistatic void removeRuntimeQualifiers(ConfigDescription* outConfig) { 10940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski outConfig->imsi = 0; 11040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski outConfig->orientation = ResTable_config::ORIENTATION_ANY; 11140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski outConfig->screenWidth = ResTable_config::SCREENWIDTH_ANY; 11240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski outConfig->screenHeight = ResTable_config::SCREENHEIGHT_ANY; 11340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski outConfig->uiMode &= ResTable_config::UI_MODE_NIGHT_ANY; 11440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 11540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 11642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinskistruct AppInfo { 11742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski int versionCode; 11842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski int minSdkVersion; 11942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski bool multiArch; 12042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski}; 12142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 12242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinskistatic bool getAppInfo(const String8& path, AppInfo& outInfo) { 12342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski memset(&outInfo, 0, sizeof(outInfo)); 12442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 12542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski AssetManager assetManager; 12642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski int32_t cookie = 0; 12742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (!assetManager.addAssetPath(path, &cookie)) { 12842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return false; 12942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 13042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 13142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski Asset* asset = assetManager.openNonAsset(cookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); 13242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (asset == NULL) { 13342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return false; 13442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 13542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 13642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski ResXMLTree xml; 13742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (xml.setTo(asset->getBuffer(true), asset->getLength(), false) != NO_ERROR) { 13842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski delete asset; 13942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return false; 14042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 14142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 14242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kAndroidNamespace("http://schemas.android.com/apk/res/android"); 14342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kManifestTag("manifest"); 14442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kApplicationTag("application"); 14542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kUsesSdkTag("uses-sdk"); 14642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kVersionCodeAttr("versionCode"); 14742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kMultiArchAttr("multiArch"); 14842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const String16 kMinSdkVersionAttr("minSdkVersion"); 14942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 15042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski ResXMLParser::event_code_t event; 15142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski while ((event = xml.next()) != ResXMLParser::BAD_DOCUMENT && 15242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski event != ResXMLParser::END_DOCUMENT) { 15342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (event != ResXMLParser::START_TAG) { 15442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski continue; 15542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 15642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 15742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski size_t len; 15842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski const char16_t* name = xml.getElementName(&len); 15942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski String16 name16(name, len); 16042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (name16 == kManifestTag) { 16142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski ssize_t idx = xml.indexOfAttribute( 16242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kAndroidNamespace.string(), kAndroidNamespace.size(), 16342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kVersionCodeAttr.string(), kVersionCodeAttr.size()); 16442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (idx >= 0) { 16542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski outInfo.versionCode = xml.getAttributeData(idx); 16642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 16742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 16842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else if (name16 == kApplicationTag) { 16942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski ssize_t idx = xml.indexOfAttribute( 17042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kAndroidNamespace.string(), kAndroidNamespace.size(), 17142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kMultiArchAttr.string(), kMultiArchAttr.size()); 17242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (idx >= 0) { 17342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski outInfo.multiArch = xml.getAttributeData(idx) != 0; 17442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 17542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 17642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else if (name16 == kUsesSdkTag) { 17742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski ssize_t idx = xml.indexOfAttribute( 17842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kAndroidNamespace.string(), kAndroidNamespace.size(), 17942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski kMinSdkVersionAttr.string(), kMinSdkVersionAttr.size()); 18042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (idx >= 0) { 18142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski uint16_t type = xml.getAttributeDataType(idx); 18242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) { 18342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski outInfo.minSdkVersion = xml.getAttributeData(idx); 18442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else if (type == Res_value::TYPE_STRING) { 18542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski String8 minSdk8(xml.getStrings().string8ObjectAt(idx)); 18642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski char* endPtr; 18742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski int minSdk = strtol(minSdk8.string(), &endPtr, 10); 18842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (endPtr != minSdk8.string() + minSdk8.size()) { 18942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n", 19042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski minSdk8.string()); 19142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else { 19242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski outInfo.minSdkVersion = minSdk; 19342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 19442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else { 19542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n"); 19642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 19742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 19842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 19942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 20042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 20142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski delete asset; 20242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return true; 20342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski} 20442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 20540e8eefbedcafc51948945647d746daaee092f16Adam Lesinskistatic Vector<SplitDescription> extractSplitDescriptionsFromApk(const String8& path) { 20640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski AssetManager assetManager; 20740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<SplitDescription> splits; 20840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski int32_t cookie = 0; 20940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (!assetManager.addAssetPath(path, &cookie)) { 21040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return splits; 21140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 21240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 21340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const ResTable& res = assetManager.getResources(false); 21440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (res.getError() == NO_ERROR) { 21540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<ResTable_config> configs; 21642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski res.getConfigurations(&configs, true); 21740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t configCount = configs.size(); 21840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < configCount; i++) { 21940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splits.add(); 22040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splits.editTop().config = configs[i]; 22140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 22240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 22340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 22440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski AssetDir* dir = assetManager.openNonAssetDir(cookie, "lib"); 22540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (dir != NULL) { 22640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t fileCount = dir->getFileCount(); 22740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < fileCount; i++) { 22840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splits.add(); 22940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-'); 23040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (parseAbi(parts, 0, &splits.editTop()) < 0) { 23140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string()); 23240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splits.pop(); 23340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 23440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 23540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski delete dir; 23640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 23740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return splits; 23840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 23940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 24040e8eefbedcafc51948945647d746daaee092f16Adam Lesinskistatic int main(int argc, char** argv) { 24140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski // Skip over the first argument. 24240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argc--; 24340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argv++; 24440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 24540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski bool generateFlag = false; 24640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski String8 targetConfigStr; 24740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<String8> splitApkPaths; 24842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski String8 baseApkPath; 24940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski while (argc > 0) { 25040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const String8 arg(*argv); 25140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (arg == "--target") { 25240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argc--; 25340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argv++; 25440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (argc < 1) { 25542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: missing parameter for --target.\n"); 25640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 25740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 25840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 25940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski targetConfigStr.setTo(*argv); 26040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } else if (arg == "--split") { 26140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argc--; 26240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argv++; 26340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (argc < 1) { 26442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: missing parameter for --split.\n"); 26540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 26640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 26740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 26840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splitApkPaths.add(String8(*argv)); 26942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } else if (arg == "--base") { 27042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski argc--; 27142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski argv++; 27242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (argc < 1) { 27342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: missing parameter for --base.\n"); 27442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski usage(); 27542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return 1; 27642eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 27742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 27842eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (baseApkPath.size() > 0) { 27942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: multiple --base flags not allowed.\n"); 28042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski usage(); 28142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return 1; 28242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 28342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski baseApkPath.setTo(*argv); 28440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } else if (arg == "--generate") { 28540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski generateFlag = true; 28640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } else if (arg == "--help") { 28740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski help(); 28840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 0; 28940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } else { 29042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: unknown argument '%s'.\n", arg.string()); 29140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 29240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 29340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 29440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argc--; 29540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski argv++; 29640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 29740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 29840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (!generateFlag && targetConfigStr == "") { 29940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 30040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 30140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 30240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 30342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (baseApkPath.size() == 0) { 30442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: missing --base argument.\n"); 30540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 30640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 30740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 30840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 30942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski // Find out some details about the base APK. 31042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski AppInfo baseAppInfo; 31142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (!getAppInfo(baseApkPath, baseAppInfo)) { 31242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.string()); 31342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski return 1; 31442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 31542eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 31640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski SplitDescription targetSplit; 31740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (!generateFlag) { 31840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (!SplitDescription::parse(targetConfigStr, &targetSplit)) { 31942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: invalid --target config: '%s'.\n", 32040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski targetConfigStr.string()); 32140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 32240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 32340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 32440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 32540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski // We don't want to match on things that will change at run-time 32640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski // (orientation, w/h, etc.). 32740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski removeRuntimeQualifiers(&targetSplit.config); 32840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 32940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 33042eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski splitApkPaths.add(baseApkPath); 33142eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski 33240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski KeyedVector<String8, Vector<SplitDescription> > apkPathSplitMap; 33340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski KeyedVector<SplitDescription, String8> splitApkPathMap; 33440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<SplitDescription> splitConfigs; 33540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t splitCount = splitApkPaths.size(); 33640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < splitCount; i++) { 33740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]); 33840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (splits.isEmpty()) { 33942eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stderr, "error: invalid --split path: '%s'. No splits found.\n", 34040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splitApkPaths[i].string()); 34140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski usage(); 34240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 1; 34340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 34440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski apkPathSplitMap.replaceValueFor(splitApkPaths[i], splits); 34540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t apkSplitDescriptionCount = splits.size(); 34640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t j = 0; j < apkSplitDescriptionCount; j++) { 34740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splitApkPathMap.replaceValueFor(splits[j], splitApkPaths[i]); 34840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 34940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski splitConfigs.appendVector(splits); 35040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 35140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 35240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski if (!generateFlag) { 35340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski Vector<SplitDescription> matchingConfigs = select(targetSplit, splitConfigs); 35440e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t matchingConfigCount = matchingConfigs.size(); 35540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski SortedVector<String8> matchingSplitPaths; 35640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < matchingConfigCount; i++) { 35740e8eefbedcafc51948945647d746daaee092f16Adam Lesinski matchingSplitPaths.add(splitApkPathMap.valueFor(matchingConfigs[i])); 35840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 35940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 36040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski const size_t matchingSplitApkPathCount = matchingSplitPaths.size(); 36140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski for (size_t i = 0; i < matchingSplitApkPathCount; i++) { 36242eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski if (matchingSplitPaths[i] != baseApkPath) { 36342eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski fprintf(stdout, "%s\n", matchingSplitPaths[i].string()); 36442eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski } 36540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 36640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } else { 36742eea270a0a2bc54f454312817c41ac357e3a884Adam Lesinski generate(apkPathSplitMap, baseApkPath); 36840e8eefbedcafc51948945647d746daaee092f16Adam Lesinski } 36940e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return 0; 37040e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 37140e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 37240e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} // namespace split 37340e8eefbedcafc51948945647d746daaee092f16Adam Lesinski 37440e8eefbedcafc51948945647d746daaee092f16Adam Lesinskiint main(int argc, char** argv) { 37540e8eefbedcafc51948945647d746daaee092f16Adam Lesinski return split::main(argc, argv); 37640e8eefbedcafc51948945647d746daaee092f16Adam Lesinski} 377