1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "AaptAssets.h" 18 #include "ApkBuilder.h" 19 20 using namespace android; 21 22 ApkBuilder::ApkBuilder(const sp<WeakResourceFilter>& configFilter) 23 : mConfigFilter(configFilter) 24 , mDefaultFilter(new AndResourceFilter()) { 25 // Add the default split, which is present for all APKs. 26 mDefaultFilter->addFilter(mConfigFilter); 27 mSplits.add(new ApkSplit(std::set<ConfigDescription>(), mDefaultFilter, true)); 28 } 29 30 status_t ApkBuilder::createSplitForConfigs(const std::set<ConfigDescription>& configs) { 31 const size_t N = mSplits.size(); 32 for (size_t i = 0; i < N; i++) { 33 const std::set<ConfigDescription>& splitConfigs = mSplits[i]->getConfigs(); 34 std::set<ConfigDescription>::const_iterator iter = configs.begin(); 35 for (; iter != configs.end(); iter++) { 36 if (splitConfigs.count(*iter) > 0) { 37 // Can't have overlapping configurations. 38 fprintf(stderr, "ERROR: Split configuration '%s' is already defined " 39 "in another split.\n", iter->toString().string()); 40 return ALREADY_EXISTS; 41 } 42 } 43 } 44 45 sp<StrongResourceFilter> splitFilter = new StrongResourceFilter(configs); 46 47 // Add the inverse filter of this split filter to the base apk filter so it will 48 // omit resources that belong in this split. 49 mDefaultFilter->addFilter(new InverseResourceFilter(splitFilter)); 50 51 // Now add the apk-wide config filter to our split filter. 52 sp<AndResourceFilter> filter = new AndResourceFilter(); 53 filter->addFilter(splitFilter); 54 filter->addFilter(mConfigFilter); 55 mSplits.add(new ApkSplit(configs, filter)); 56 return NO_ERROR; 57 } 58 59 status_t ApkBuilder::addEntry(const String8& path, const sp<AaptFile>& file) { 60 const size_t N = mSplits.size(); 61 for (size_t i = 0; i < N; i++) { 62 if (mSplits[i]->matches(file)) { 63 return mSplits.editItemAt(i)->addEntry(path, file); 64 } 65 } 66 // Entry can be dropped if it doesn't match any split. This will only happen 67 // if the enry doesn't mConfigFilter. 68 return NO_ERROR; 69 } 70 71 void ApkBuilder::print() const { 72 fprintf(stderr, "APK Builder\n"); 73 fprintf(stderr, "-----------\n"); 74 const size_t N = mSplits.size(); 75 for (size_t i = 0; i < N; i++) { 76 mSplits[i]->print(); 77 fprintf(stderr, "\n"); 78 } 79 } 80 81 ApkSplit::ApkSplit(const std::set<ConfigDescription>& configs, const sp<ResourceFilter>& filter, bool isBase) 82 : mConfigs(configs), mFilter(filter), mIsBase(isBase) { 83 std::set<ConfigDescription>::const_iterator iter = configs.begin(); 84 for (; iter != configs.end(); iter++) { 85 if (mName.size() > 0) { 86 mName.append(","); 87 mDirName.append("_"); 88 mPackageSafeName.append("."); 89 } 90 91 String8 configStr = iter->toString(); 92 String8 packageConfigStr(configStr); 93 size_t len = packageConfigStr.length(); 94 if (len > 0) { 95 char* buf = packageConfigStr.lockBuffer(len); 96 for (char* end = buf + len; buf < end; ++buf) { 97 if (*buf == '-') { 98 *buf = '_'; 99 } 100 } 101 packageConfigStr.unlockBuffer(len); 102 } 103 mName.append(configStr); 104 mDirName.append(configStr); 105 mPackageSafeName.append(packageConfigStr); 106 } 107 } 108 109 status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) { 110 if (!mFiles.insert(OutputEntry(path, file)).second) { 111 // Duplicate file. 112 return ALREADY_EXISTS; 113 } 114 return NO_ERROR; 115 } 116 117 void ApkSplit::print() const { 118 fprintf(stderr, "APK Split '%s'\n", mName.string()); 119 120 std::set<OutputEntry>::const_iterator iter = mFiles.begin(); 121 for (; iter != mFiles.end(); iter++) { 122 fprintf(stderr, " %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string()); 123 } 124 } 125