Merge "Load app resource as shared library."
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index c248a9e..04c690b 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -610,14 +610,28 @@
      * {@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.
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9aa544f..7ca0654 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -510,7 +510,7 @@
 }
 
 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 @@
     }
 
     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 @@
         (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 },
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 0cfd2b1..3d4e47d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -93,13 +93,14 @@
      * 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 @@
     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;
 
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index eff1f5f..49b6333 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1505,7 +1505,7 @@
 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 @@
     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 @@
 
     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 @@
     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 @@
             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;
     
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 623ea89..8a03b94 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,7 @@
     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 @@
 #endif
 
     if (mResources != NULL) {
-        appendPathToResTable(ap);
+        appendPathToResTable(ap, appAsLib);
     }
 
     return true;
@@ -610,7 +610,7 @@
         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 @@
             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;
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 37de89a..21b543e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,13 @@
 // 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 @@
 {
     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 @@
 }
 
 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 @@
         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 @@
     }
 
     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 @@
 
     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::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 @@
                 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::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 @@
     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 @@
 
         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 @@
     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 @@
     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::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;
     }
 
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index a353575..2bc026b7 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -21,6 +21,7 @@
 LOCAL_PATH:= $(call my-dir)
 
 testFiles := \
+    AppAsLib_test.cpp \
     AttributeFinder_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
diff --git a/libs/androidfw/tests/AppAsLib_test.cpp b/libs/androidfw/tests/AppAsLib_test.cpp
new file mode 100644
index 0000000..bdb0c3d
--- /dev/null
+++ b/libs/androidfw/tests/AppAsLib_test.cpp
@@ -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);
+}
+
+}
diff --git a/libs/androidfw/tests/data/appaslib/R.h b/libs/androidfw/tests/data/appaslib/R.h
new file mode 100644
index 0000000..f89d4bf
--- /dev/null
+++ b/libs/androidfw/tests/data/appaslib/R.h
@@ -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
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cbe7c5d..c29bb48 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -66,6 +66,7 @@
           mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
           mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
           mBuildSharedLibrary(false),
+          mBuildAppAsSharedLibrary(false),
           mArgc(0), mArgv(NULL)
         {}
     ~Bundle(void) {}
@@ -206,6 +207,8 @@
     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 @@
     const char* mSingleCrunchInputFile;
     const char* mSingleCrunchOutputFile;
     bool        mBuildSharedLibrary;
+    bool        mBuildAppAsSharedLibrary;
     android::String8 mPlatformVersionCode;
     android::String8 mPlatformVersionName;
 
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index d12ab3b..21f47bc2 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2395,11 +2395,11 @@
             // 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 @@
             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;
                 }
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index bcf0d5e..6411286 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -200,6 +200,9 @@
         "   --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 @@
                 } 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) {