Merge "Load app resource as shared library."

This commit is contained in:
Tao Bai
2015-09-09 16:08:12 +00:00
committed by Android (Google) Code Review
12 changed files with 169 additions and 42 deletions

View File

@@ -610,14 +610,28 @@ public final class AssetManager implements AutoCloseable {
* {@hide}
*/
public final int addAssetPath(String path) {
return addAssetPathInternal(path, false);
}
/**
* Add an application assets to the asset manager and loading it as shared library.
* This can be either a directory or ZIP file. Not for use by applications. Returns
* the cookie of the added asset, or 0 on failure.
* {@hide}
*/
public final int addAssetPathAsSharedLibrary(String path) {
return addAssetPathInternal(path, true);
}
private final int addAssetPathInternal(String path, boolean appAsLib) {
synchronized (this) {
int res = addAssetPathNative(path);
int res = addAssetPathNative(path, appAsLib);
makeStringBlocks(mStringBlocks);
return res;
}
}
private native final int addAssetPathNative(String path);
private native final int addAssetPathNative(String path, boolean appAsLib);
/**
* Add a set of assets to overlay an already added set of assets.

View File

@@ -510,7 +510,7 @@ static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, j
}
static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
jstring path)
jstring path, jboolean appAsLib)
{
ScopedUtfChars path8(env, path);
if (path8.c_str() == NULL) {
@@ -523,7 +523,7 @@ static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz
}
int32_t cookie;
bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
return (res) ? static_cast<jint>(cookie) : 0;
}
@@ -2138,7 +2138,7 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_getAssetLength },
{ "getAssetRemainingLength", "(J)J",
(void*) android_content_AssetManager_getAssetRemainingLength },
{ "addAssetPathNative", "(Ljava/lang/String;)I",
{ "addAssetPathNative", "(Ljava/lang/String;Z)I",
(void*) android_content_AssetManager_addAssetPath },
{ "addOverlayPathNative", "(Ljava/lang/String;)I",
(void*) android_content_AssetManager_addOverlayPath },

View File

@@ -93,13 +93,14 @@ public:
* look in multiple places for assets. It can be either a directory (for
* finding assets as raw files on the disk) or a ZIP file. This newly
* added asset path will be examined first when searching for assets,
* before any that were previously added.
* before any that were previously added, the assets are added as shared
* library if appAsLib is true.
*
* Returns "true" on success, "false" on failure. If 'cookie' is non-NULL,
* then on success, *cookie is set to the value corresponding to the
* newly-added asset source.
*/
bool addAssetPath(const String8& path, int32_t* cookie);
bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
bool addOverlayPath(const String8& path, int32_t* cookie);
/*
@@ -280,7 +281,7 @@ private:
const ResTable* getResTable(bool required = true) const;
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
bool appendPathToResTable(const asset_path& ap) const;
bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const;
Asset* openIdmapLocked(const struct asset_path& ap) const;

View File

@@ -1505,7 +1505,7 @@ struct ResTable_lib_entry
class DynamicRefTable
{
public:
DynamicRefTable(uint8_t packageId);
DynamicRefTable(uint8_t packageId, bool appAsLib);
// Loads an unmapped reference table from the package.
status_t load(const ResTable_lib_header* const header);
@@ -1530,6 +1530,7 @@ private:
const uint8_t mAssignedPackageId;
uint8_t mLookupTable[256];
KeyedVector<String16, uint8_t> mEntries;
bool mAppAsLib;
};
bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
@@ -1547,10 +1548,11 @@ public:
status_t add(const void* data, size_t size, const int32_t cookie=-1, bool copyData=false);
status_t add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
const int32_t cookie=-1, bool copyData=false);
const int32_t cookie=-1, bool copyData=false, bool appAsLib=false);
status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false);
status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
bool appAsLib=false);
status_t add(ResTable* src);
status_t addEmpty(const int32_t cookie);
@@ -1858,7 +1860,7 @@ private:
typedef Vector<Type*> TypeList;
status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
const int32_t cookie, bool copyData);
bool appAsLib, const int32_t cookie, bool copyData);
ssize_t getResourcePackageIndex(uint32_t resID) const;
@@ -1871,7 +1873,7 @@ private:
size_t nameLen, uint32_t* outTypeSpecFlags) const;
status_t parsePackage(
const ResTable_package* const pkg, const Header* const header);
const ResTable_package* const pkg, const Header* const header, bool appAsLib);
void print_value(const Package* pkg, const Res_value& value) const;

View File

@@ -176,7 +176,7 @@ AssetManager::~AssetManager(void)
delete[] mVendor;
}
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
{
AutoMutex _l(mLock);
@@ -238,7 +238,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
#endif
if (mResources != NULL) {
appendPathToResTable(ap);
appendPathToResTable(ap, appAsLib);
}
return true;
@@ -610,7 +610,7 @@ FileType AssetManager::getFileType(const char* fileName)
return kFileTypeRegular;
}
bool AssetManager::appendPathToResTable(const asset_path& ap) const {
bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
// skip those ap's that correspond to system overlays
if (ap.isSystemOverlay) {
return true;
@@ -685,7 +685,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const {
mResources->add(sharedRes);
} else {
ALOGV("Parsing resources for %s", ap.path.string());
mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
}
onlyEmptyResources = false;

View File

@@ -3080,13 +3080,13 @@ struct ResTable::Package
// table that defined the package); the ones after are skins on top of it.
struct ResTable::PackageGroup
{
PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
: owner(_owner)
, name(_name)
, id(_id)
, largestTypeId(0)
, bags(NULL)
, dynamicRefTable(static_cast<uint8_t>(_id))
, dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
{ }
~PackageGroup() {
@@ -3532,7 +3532,7 @@ ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool cop
{
memset(&mParams, 0, sizeof(mParams));
memset(mPackageMap, 0, sizeof(mPackageMap));
addInternal(data, size, NULL, 0, cookie, copyData);
addInternal(data, size, NULL, 0, false, cookie, copyData);
LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
if (kDebugTableSuperNoisy) {
ALOGI("Creating ResTable %p\n", this);
@@ -3553,12 +3553,12 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
}
status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
return addInternal(data, size, NULL, 0, cookie, copyData);
return addInternal(data, size, NULL, 0, false, cookie, copyData);
}
status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
const int32_t cookie, bool copyData) {
return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
const int32_t cookie, bool copyData, bool appAsLib) {
return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
}
status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
@@ -3568,10 +3568,12 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
return UNKNOWN_ERROR;
}
return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, false, 0, cookie,
copyData);
}
status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
bool appAsLib) {
const void* data = asset->getBuffer(true);
if (data == NULL) {
ALOGW("Unable to get buffer of resource asset file");
@@ -3590,7 +3592,7 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo
}
return addInternal(data, static_cast<size_t>(asset->getLength()),
idmapData, idmapSize, cookie, copyData);
idmapData, idmapSize, appAsLib, cookie, copyData);
}
status_t ResTable::add(ResTable* src)
@@ -3603,7 +3605,7 @@ status_t ResTable::add(ResTable* src)
for (size_t i=0; i<src->mPackageGroups.size(); i++) {
PackageGroup* srcPg = src->mPackageGroups[i];
PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
for (size_t j=0; j<srcPg->packages.size(); j++) {
pg->packages.add(srcPg->packages[j]);
}
@@ -3644,7 +3646,7 @@ status_t ResTable::addEmpty(const int32_t cookie) {
}
status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
const int32_t cookie, bool copyData)
bool appAsLib, const int32_t cookie, bool copyData)
{
if (!data) {
return NO_ERROR;
@@ -3747,7 +3749,7 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id
return (mError=BAD_TYPE);
}
if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -5935,7 +5937,7 @@ status_t ResTable::getEntry(
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
const Header* const header)
const Header* const header, bool appAsLib)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5983,7 +5985,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
} else if (id == 0) {
} else if (id == 0 || appAsLib) {
// This is a library so assign an ID
id = mNextPackageId++;
}
@@ -6016,7 +6018,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
group = new PackageGroup(this, String16(tmpName), id);
group = new PackageGroup(this, String16(tmpName), id, appAsLib);
if (group == NULL) {
delete package;
return (mError=NO_MEMORY);
@@ -6228,8 +6230,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return NO_ERROR;
}
DynamicRefTable::DynamicRefTable(uint8_t packageId)
DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
: mAssignedPackageId(packageId)
, mAppAsLib(appAsLib)
{
memset(mLookupTable, 0, sizeof(mLookupTable));
@@ -6314,16 +6317,18 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
uint32_t res = *resId;
size_t packageId = Res_GETPACKAGE(res) + 1;
if (packageId == APP_PACKAGE_ID) {
if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
// No lookup needs to be done, app package IDs are absolute.
return NO_ERROR;
}
if (packageId == 0) {
if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
// The package ID is 0x00. That means that a shared library is accessing
// its own local resource, so we fix up the resource with the calling
// package ID.
*resId |= ((uint32_t) mAssignedPackageId) << 24;
// its own local resource.
// Or if app resource is loaded as shared library, the resource which has
// app package Id is local resources.
// so we fix up those resources with the calling package ID.
*resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24);
return NO_ERROR;
}
@@ -6345,7 +6350,10 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
}
status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) {
if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE &&
(value->dataType != Res_value::TYPE_REFERENCE || !mAppAsLib)) {
// If the package is loaded as shared library, the resource reference
// also need to be fixed.
return NO_ERROR;
}

View File

@@ -21,6 +21,7 @@
LOCAL_PATH:= $(call my-dir)
testFiles := \
AppAsLib_test.cpp \
AttributeFinder_test.cpp \
ByteBucketArray_test.cpp \
Config_test.cpp \

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <androidfw/ResourceTypes.h>
#include "data/basic/R.h"
#include "data/appaslib/R.h"
#include <gtest/gtest.h>
using namespace android;
namespace {
#include "data/basic/basic_arsc.h"
TEST(AppAsLibTest, loadedAsApp) {
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
Res_value val;
ssize_t block = table.getResource(base::R::integer::number2, &val);
ASSERT_GE(block, 0);
ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
ASSERT_EQ(base::R::array::integerArray1, val.data);
}
TEST(AppAsLibTest, loadedAsSharedLib) {
ResTable table;
// Load as shared library.
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len, NULL, 0, -1, false, true));
Res_value val;
ssize_t block = table.getResource(appaslib::R::integer::number2, &val);
ASSERT_GE(block, 0);
ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
ASSERT_EQ(appaslib::R::array::integerArray1, val.data);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __APPASLIB_R_H
#define __APPASLIB_R_H
namespace appaslib {
namespace R {
namespace integer {
enum {
number2 = 0x02040001, // default
};
}
namespace array {
enum {
integerArray1 = 0x02060000, // default
};
}
} // namespace R
} // namespace appaslib
#endif // __APPASLIB_R_H

View File

@@ -66,6 +66,7 @@ public:
mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
mBuildSharedLibrary(false),
mBuildAppAsSharedLibrary(false),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -206,6 +207,8 @@ public:
void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
bool getBuildSharedLibrary() const { return mBuildSharedLibrary; }
void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; }
bool getBuildAppAsSharedLibrary() const { return mBuildAppAsSharedLibrary; }
void setBuildAppAsSharedLibrary(bool val) { mBuildAppAsSharedLibrary = val; }
void setNoVersionVectors(bool val) { mNoVersionVectors = val; }
bool getNoVersionVectors() const { return mNoVersionVectors; }
@@ -327,6 +330,7 @@ private:
const char* mSingleCrunchInputFile;
const char* mSingleCrunchOutputFile;
bool mBuildSharedLibrary;
bool mBuildAppAsSharedLibrary;
android::String8 mPlatformVersionCode;
android::String8 mPlatformVersionName;

View File

@@ -2395,11 +2395,11 @@ int doPackage(Bundle* bundle)
// Write the R.java file into the appropriate class directory
// e.g. gen/com/foo/app/R.java
err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
bundle->getBuildSharedLibrary());
bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
} else {
const String8 customPkg(bundle->getCustomPackage());
err = writeResourceSymbols(bundle, assets, customPkg, true,
bundle->getBuildSharedLibrary());
bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
}
if (err < 0) {
goto bail;
@@ -2414,7 +2414,7 @@ int doPackage(Bundle* bundle)
while (packageString != NULL) {
// Write the R.java file out with the correct package name
err = writeResourceSymbols(bundle, assets, String8(packageString), true,
bundle->getBuildSharedLibrary());
bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
if (err < 0) {
goto bail;
}

View File

@@ -200,6 +200,9 @@ void usage(void)
" --shared-lib\n"
" Make a shared library resource package that can be loaded by an application\n"
" at runtime to access the libraries resources. Implies --non-constant-id.\n"
" --app-as-shared-lib\n"
" Make an app resource package that also can be loaded as shared library at runtime.\n"
" Implies --non-constant-id.\n"
" --error-on-failed-insert\n"
" Forces aapt to return an error if it fails to insert values into the manifest\n"
" with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
@@ -668,6 +671,9 @@ int main(int argc, char* const argv[])
} else if (strcmp(cp, "-shared-lib") == 0) {
bundle.setNonConstantId(true);
bundle.setBuildSharedLibrary(true);
} else if (strcmp(cp, "-app-as-shared-lib") == 0) {
bundle.setNonConstantId(true);
bundle.setBuildAppAsSharedLibrary(true);
} else if (strcmp(cp, "-no-crunch") == 0) {
bundle.setUseCrunchCache(true);
} else if (strcmp(cp, "-ignore-assets") == 0) {