Adam Lesinski | fab5087 | 2014-04-16 14:40:42 -0700 | [diff] [blame] | 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("_"); |
Adam Lesinski | 6240840 | 2014-08-07 21:26:53 -0700 | [diff] [blame] | 88 | mPackageSafeName.append("."); |
Adam Lesinski | fab5087 | 2014-04-16 14:40:42 -0700 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | String8 configStr = iter->toString(); |
Adam Lesinski | 6240840 | 2014-08-07 21:26:53 -0700 | [diff] [blame] | 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 | } |
Adam Lesinski | fab5087 | 2014-04-16 14:40:42 -0700 | [diff] [blame] | 103 | mName.append(configStr); |
| 104 | mDirName.append(configStr); |
Adam Lesinski | 6240840 | 2014-08-07 21:26:53 -0700 | [diff] [blame] | 105 | mPackageSafeName.append(packageConfigStr); |
Adam Lesinski | fab5087 | 2014-04-16 14:40:42 -0700 | [diff] [blame] | 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 | } |