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