2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "AaptAssets.h"
18 #include "ApkBuilder.h"
20 using namespace android;
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));
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;
45 sp<StrongResourceFilter> splitFilter = new StrongResourceFilter(configs);
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));
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));
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);
66 // Entry can be dropped if it doesn't match any split. This will only happen
67 // if the enry doesn't mConfigFilter.
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++) {
77 fprintf(stderr, "\n");
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) {
88 mPackageSafeName.append(".");
91 String8 configStr = iter->toString();
92 String8 packageConfigStr(configStr);
93 size_t len = packageConfigStr.length();
95 char* buf = packageConfigStr.lockBuffer(len);
96 for (char* end = buf + len; buf < end; ++buf) {
101 packageConfigStr.unlockBuffer(len);
103 mName.append(configStr);
104 mDirName.append(configStr);
105 mPackageSafeName.append(packageConfigStr);
109 status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) {
110 if (!mFiles.insert(OutputEntry(path, file)).second) {
112 return ALREADY_EXISTS;
117 void ApkSplit::print() const {
118 fprintf(stderr, "APK Split '%s'\n", mName.string());
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());