Shared library resource support

Shared libraries can now export resources for applications
to use.

Exporting resources works the same way the framework exports
resources, by defining the public symbols in res/values/public.xml.

Building a shared library requires aapt to be invoked with the
--shared-lib option. Shared libraries will be assigned a package
ID of 0x00 at build-time. At runtime, all loaded shared libraries
will be assigned a new package ID.

Currently, shared libraries should not import other shared libraries,
as those dependencies will not be loaded at runtime.

At runtime, reflection is used to update the package ID of resource
symbols in the shared library's R class file. The package name of
the R class file is assumed to be the same as the shared library's
package name declared in its manifest. This will be customizable in
a future commit.

See /tests/SharedLibrary/ for examples of a shared library and its
client.

Bug:12724178
Change-Id: I60c0cb8ab87849f8f8a1a13431562fe8603020a7
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9dde701a..4147608 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -73,6 +73,13 @@
     jfieldID mObject;
 } gAssetManagerOffsets;
 
+static struct sparsearray_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jmethodID put;
+} gSparseArrayOffsets;
+
 jclass g_stringClass = NULL;
 
 // ----------------------------------------------------------------------------
@@ -905,6 +912,26 @@
     return str;
 }
 
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const ResTable& res = am->getResources();
+
+    jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+            gSparseArrayOffsets.constructor);
+    const size_t N = res.getBasePackageCount();
+    for (size_t i = 0; i < N; i++) {
+        const String16 name = res.getBasePackageName(i);
+        env->CallVoidMethod(sparseArray, gSparseArrayOffsets.put, (jint) res.getBasePackageId(i),
+                env->NewString(name, name.size()));
+    }
+    return sparseArray;
+}
+
 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
 {
     AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -1675,16 +1702,19 @@
         return 0;
     }
 
-    Asset* a = cookie
-        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_BUFFER)
-        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
+    int32_t assetCookie = static_cast<int32_t>(cookie);
+    Asset* a = assetCookie
+        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
 
     if (a == NULL) {
         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return 0;
     }
 
-    ResXMLTree* block = new ResXMLTree();
+    const DynamicRefTable* dynamicRefTable =
+            am->getResources().getDynamicRefTableForCookie(assetCookie);
+    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
     a->close();
     delete a;
@@ -1972,6 +2002,8 @@
         (void*) android_content_AssetManager_getNativeStringBlock },
     { "getCookieName","(I)Ljava/lang/String;",
         (void*) android_content_AssetManager_getCookieName },
+    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
 
     // Themes.
     { "newTheme", "()J",
@@ -2068,6 +2100,16 @@
     g_stringClass = (jclass)env->NewGlobalRef(stringClass);
     LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
 
+    jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
+    LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
+    gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
+    gSparseArrayOffsets.constructor =
+            env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
+    LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
+    gSparseArrayOffsets.put =
+            env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+    LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
+
     return AndroidRuntime::registerNativeMethods(env,
             "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
 }