Merge "Load libraries directly from apk"

This commit is contained in:
Dmitriy Ivanov
2015-04-07 17:28:15 +00:00
committed by Gerrit Code Review
16 changed files with 241 additions and 30 deletions

View File

@@ -547,6 +547,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16843990; // 0x10104d6
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -8368,6 +8369,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -17515,7 +17517,7 @@ package android.net.http {
method public static android.net.http.HttpResponseCache getInstalled();
method public int getNetworkCount();
method public int getRequestCount();
method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public long maxSize();
method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
method public long size();
@@ -41519,7 +41521,7 @@ package java.lang {
method public static double nextUp(double);
method public static float nextUp(float);
method public static double pow(double, double);
method public static synchronized double random();
method public static double random();
method public static double rint(double);
method public static long round(double);
method public static int round(float);

View File

@@ -617,6 +617,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
field public static final int extractNativeLibs = 16843990; // 0x10104d6
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -8616,6 +8617,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -18843,7 +18845,7 @@ package android.net.http {
method public static android.net.http.HttpResponseCache getInstalled();
method public int getNetworkCount();
method public int getRequestCount();
method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public long maxSize();
method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
method public long size();
@@ -44055,7 +44057,7 @@ package java.lang {
method public static double nextUp(double);
method public static float nextUp(float);
method public static double pow(double, double);
method public static synchronized double random();
method public static double random();
method public static double rint(double);
method public static long round(double);
method public static int round(float);

View File

@@ -345,6 +345,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
/**
* When set installer extracts native libs from .apk files.
*/
public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28;
/**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple

View File

@@ -268,6 +268,7 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths, int[] splitRevisionCodes) {
@@ -283,6 +284,7 @@ public class PackageParser {
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
this.extractNativeLibs = baseApk.extractNativeLibs;
}
public List<String> getAllCodePaths() {
@@ -309,10 +311,12 @@ public class PackageParser {
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
Signature[] signatures, boolean coreApp, boolean multiArch) {
Signature[] signatures, boolean coreApp, boolean multiArch,
boolean extractNativeLibs) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -323,6 +327,7 @@ public class PackageParser {
this.signatures = signatures;
this.coreApp = coreApp;
this.multiArch = multiArch;
this.extractNativeLibs = extractNativeLibs;
}
}
@@ -1269,6 +1274,7 @@ public class PackageParser {
int revisionCode = 0;
boolean coreApp = false;
boolean multiArch = false;
boolean extractNativeLibs = true;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
final String attr = attrs.getAttributeName(i);
@@ -1307,14 +1313,17 @@ public class PackageParser {
final String attr = attrs.getAttributeName(i);
if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false);
break;
}
if ("extractNativeLibs".equals(attr)) {
extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
}
}
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
extractNativeLibs);
}
/**
@@ -2567,6 +2576,12 @@ public class PackageParser {
ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
}
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
true)) {
ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
}
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);

View File

@@ -33,6 +33,7 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.os.Build;
import android.os.SELinux;
import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
@@ -74,6 +75,7 @@ public class NativeLibraryHelper {
final long[] apkHandles;
final boolean multiArch;
final boolean extractNativeLibs;
public static Handle create(File packageFile) throws IOException {
try {
@@ -86,14 +88,16 @@ public class NativeLibraryHelper {
public static Handle create(Package pkg) throws IOException {
return create(pkg.getAllCodePaths(),
(pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0);
(pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
(pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0);
}
public static Handle create(PackageLite lite) throws IOException {
return create(lite.getAllCodePaths(), lite.multiArch);
return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs);
}
private static Handle create(List<String> codePaths, boolean multiArch) throws IOException {
private static Handle create(List<String> codePaths, boolean multiArch,
boolean extractNativeLibs) throws IOException {
final int size = codePaths.size();
final long[] apkHandles = new long[size];
for (int i = 0; i < size; i++) {
@@ -108,12 +112,13 @@ public class NativeLibraryHelper {
}
}
return new Handle(apkHandles, multiArch);
return new Handle(apkHandles, multiArch, extractNativeLibs);
}
Handle(long[] apkHandles, boolean multiArch) {
Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) {
this.apkHandles = apkHandles;
this.multiArch = multiArch;
this.extractNativeLibs = extractNativeLibs;
mGuard.open("close");
}
@@ -146,8 +151,8 @@ public class NativeLibraryHelper {
private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
private native static int nativeCopyNativeBinaries(long handle,
String sharedLibraryPath, String abiToCopy);
private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge);
private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
@@ -167,7 +172,8 @@ public class NativeLibraryHelper {
*/
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
for (long apkHandle : handle.apkHandles) {
int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
if (res != INSTALL_SUCCEEDED) {
return res;
}
@@ -218,7 +224,8 @@ public class NativeLibraryHelper {
/**
* Remove the native binaries of a given package. This deletes the files
*/
public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {
public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot,
boolean deleteRootDir) {
if (DEBUG_NATIVE) {
Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath());
}
@@ -247,7 +254,8 @@ public class NativeLibraryHelper {
// asked to or this will prevent installation of future updates.
if (deleteRootDir) {
if (!nativeLibraryRoot.delete()) {
Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath());
Slog.w(TAG, "Could not delete native binary directory: " +
nativeLibraryRoot.getPath());
}
}
}
@@ -416,6 +424,9 @@ public class NativeLibraryHelper {
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
private static final boolean HAS_NATIVE_BRIDGE =
!"0".equals(SystemProperties.get("ro.dalvik.vm.native.bridge", "0"));
private static native int hasRenderscriptBitcode(long apkHandle);
public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {

View File

@@ -586,6 +586,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -859,6 +860,18 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
// Dalvik-cache pruning counter.
parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
"-Xzygote-max-boot-retry=");
#if defined(__LP64__)
const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
#else
const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
#endif // defined(__LP64__)
property_get(cpu_abilist_property_name, propBuf, "");
if (propBuf[0] == '\0') {
ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
return -1;
}
snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
addOption(cpuAbiListBuf);
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();

View File

@@ -33,6 +33,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -173,7 +174,11 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char
static install_status_t
copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
{
jstring* javaNativeLibPath = (jstring*) arg;
void** args = reinterpret_cast<void**>(arg);
jstring* javaNativeLibPath = (jstring*) args[0];
jboolean extractNativeLibs = *(jboolean*) args[1];
jboolean hasNativeBridge = *(jboolean*) args[2];
ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
size_t uncompLen;
@@ -181,13 +186,31 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
long crc;
time_t modTime;
if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) {
int method;
off64_t offset;
if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
ALOGD("Couldn't read zip entry info\n");
return INSTALL_FAILED_INVALID_APK;
} else {
struct tm t;
ZipUtils::zipTimeToTimespec(when, &t);
modTime = mktime(&t);
}
if (!extractNativeLibs) {
// check if library is uncompressed and page-aligned
if (method != ZipFileRO::kCompressStored) {
ALOGD("Library '%s' is compressed - will not be able to open it directly from apk.\n",
fileName);
return INSTALL_FAILED_INVALID_APK;
}
if (offset % PAGE_SIZE != 0) {
ALOGD("Library '%s' is not page-aligned - will not be able to open it directly from"
" apk.\n", fileName);
return INSTALL_FAILED_INVALID_APK;
}
if (!hasNativeBridge) {
return INSTALL_SUCCEEDED;
}
}
// Build local file path
@@ -208,6 +231,9 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
}
// Only copy out the native file if it's different.
struct tm t;
ZipUtils::zipTimeToTimespec(when, &t);
modTime = mktime(&t);
struct stat64 st;
if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
return INSTALL_SUCCEEDED;
@@ -465,10 +491,12 @@ static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supported
static jint
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi)
jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
jboolean extractNativeLibs, jboolean hasNativeBridge)
{
void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
copyFileIfChanged, &javaNativeLibPath);
copyFileIfChanged, reinterpret_cast<void*>(args));
}
static jlong
@@ -548,7 +576,7 @@ static JNINativeMethod gMethods[] = {
"(J)V",
(void *)com_android_internal_content_NativeLibraryHelper_close},
{"nativeCopyNativeBinaries",
"(JLjava/lang/String;Ljava/lang/String;)I",
"(JLjava/lang/String;Ljava/lang/String;ZZ)I",
(void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
{"nativeSumNativeBinaries",
"(JLjava/lang/String;)J",

View File

@@ -1021,6 +1021,10 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="resumeWhilePausing" format="boolean" />
<!-- When set installer will extract native libraries. If set to false
libraries in the apk must be stored and page-aligned. -->
<attr name="extractNativeLibs" format="boolean"/>
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1151,8 +1155,8 @@
@hide -->
<attr name="usesCleartextTraffic" />
<attr name="multiArch" />
<attr name="extractNativeLibs" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
features in your package (or other packages). See the

View File

@@ -2598,4 +2598,5 @@
<public type="style" name="Theme.DeviceDefault.Dialog.Alert" />
<public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
<public type="attr" name="extractNativeLibs" />
</resources>

View File

@@ -23,6 +23,14 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper
LOCAL_MODULE := libframeworks_coretests_jni
# this does not prevent build system
# from installing library to /system/lib
LOCAL_MODULE_TAGS := tests
# .. we want to avoid that... so we put it somewhere
# bionic linker cant find it without outside help (nativetests):
LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
include $(BUILD_SHARED_LIBRARY)

View File

@@ -27,8 +27,8 @@ static JNINativeMethod sMethods[] = {
{ "checkFunction", "()I", (void*) checkFunction },
};
int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) {
return jniRegisterNativeMethods(env, "com/android/frameworks/coretests/JNITests", sMethods,
NELEM(sMethods));
}
@@ -46,7 +46,7 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
return JNI_ERR;
}
if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
if ((status = android::register_com_android_frameworks_coretests_JNITests(e)) < 0) {
return JNI_ERR;
}

View File

@@ -0,0 +1,11 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
LOCAL_JNI_SHARED_LIBRARIES_ZIP_OPTIONS := -0
LOCAL_PAGE_ALIGN_JNI_SHARED_LIBRARIES := true
include $(FrameworkCoreTests_BUILD_PACKAGE)

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.coretests.install_jni_lib_open_from_apk">
<application android:hasCode="true" android:label="@string/app_name" android:extractNativeLibs="false">
<activity android:name="com.android.frameworks.coretests.OpenFromApkActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Load From Apk Test</string>
</resources>

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2014 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.
*
*/
package com.android.frameworks.coretests;
public class JNITests {
static {
System.loadLibrary("frameworks_coretests_jni");
}
public static native int checkFunction();
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 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.
*
*/
package com.android.frameworks.coretests;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public class OpenFromApkActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
int i = JNITests.checkFunction();
tv.setText("All is well: i=" + i);
setContentView(tv);
}
}