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