Merge "Add UID parameter to authentication token"
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index ae0a401..a1fe6ed 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -281,6 +281,10 @@
{"warm_reset_0x80", 141},
{"pon_reason_0xb0", 142},
{"reboot_download", 143},
+ {"reboot_recovery_mode", 144},
+ {"oem_sdi_err_fatal", 145},
+ {"pmic_watchdog", 146},
+ {"software_master", 147},
};
// Converts a string value representing the reason the system booted to an
diff --git a/init/property_service.cpp b/init/property_service.cpp
index fa28fa3..ecd5baa 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -762,12 +762,20 @@
// Don't check for failure here, so we always have a sane list of properties.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// still need the system / platform properties to function.
- LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts", &property_infos);
+ if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
+ &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
+ &property_infos);
+ }
} else {
if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
return;
}
- LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+ if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
+ // Fallback to nonplat_* if vendor_* doesn't exist.
+ LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
+ }
}
auto serialized_contexts = std::string();
diff --git a/init/selinux.cpp b/init/selinux.cpp
index d3ce236..6aba9c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -423,12 +423,16 @@
selinux_android_restorecon("/vendor_file_contexts", 0);
selinux_android_restorecon("/plat_property_contexts", 0);
selinux_android_restorecon("/nonplat_property_contexts", 0);
+ selinux_android_restorecon("/vendor_property_contexts", 0);
selinux_android_restorecon("/plat_seapp_contexts", 0);
selinux_android_restorecon("/nonplat_seapp_contexts", 0);
+ selinux_android_restorecon("/vendor_seapp_contexts", 0);
selinux_android_restorecon("/plat_service_contexts", 0);
selinux_android_restorecon("/nonplat_service_contexts", 0);
+ selinux_android_restorecon("/vendor_service_contexts", 0);
selinux_android_restorecon("/plat_hwservice_contexts", 0);
selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
+ selinux_android_restorecon("/vendor_hwservice_contexts", 0);
selinux_android_restorecon("/sepolicy", 0);
selinux_android_restorecon("/vndservice_contexts", 0);
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 91bcc66..c5d498c 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -128,11 +128,30 @@
}
frames->resize(total_frames);
size_t cur_frame = 0;
- for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) {
+ for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
auto frame = &unwinder_frames[i];
+
+ // Inject extra 'virtual' frame that represents the dex pc data.
+ // The dex pc is magic register defined in the Mterp interpreter,
+ // and thus it will be restored/observed in the frame after it.
+ // Adding the dex frame first here will create something like:
+ // #7 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
+ // #8 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
+ // #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
+ if (frame->dex_pc != 0) {
+ backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
+ dex_frame->num = cur_frame++;
+ dex_frame->pc = frame->dex_pc;
+ dex_frame->rel_pc = frame->dex_pc;
+ dex_frame->sp = frame->sp;
+ dex_frame->stack_size = 0;
+ dex_frame->func_offset = 0;
+ FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
+ }
+
backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
- back_frame->num = cur_frame;
+ back_frame->num = cur_frame++;
back_frame->rel_pc = frame->rel_pc;
back_frame->pc = frame->pc;
@@ -147,19 +166,6 @@
back_frame->map.offset = frame->map_offset;
back_frame->map.load_bias = frame->map_load_bias;
back_frame->map.flags = frame->map_flags;
-
- // Inject a frame that represents the dex pc data.
- if (frame->dex_pc != 0) {
- cur_frame++;
- backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
- dex_frame->num = cur_frame;
- dex_frame->pc = frame->dex_pc;
- dex_frame->rel_pc = frame->dex_pc;
- dex_frame->sp = back_frame->sp;
- dex_frame->stack_size = 0;
- dex_frame->func_offset = 0;
- FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
- }
}
return true;
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 5753e49..fc354f1 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -125,6 +125,7 @@
#define AID_RESERVED_DISK 1065 /* GID that has access to reserved disk space */
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
+#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 15fba8b..ade2821 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -34,9 +34,11 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/*
- * Support routines to send messages to the Android in-kernel log buffer,
- * which can later be accessed through the 'logcat' utility.
+/**
+ * \file
+ *
+ * Support routines to send messages to the Android log buffer,
+ * which can later be accessed through the `logcat` utility.
*
* Each log message must have
* - a priority
@@ -47,24 +49,22 @@
* and should be reasonably small.
*
* Log message text may be truncated to less than an implementation-specific
- * limit (e.g. 1023 characters max).
+ * limit (1023 bytes).
*
* Note that a newline character ("\n") will be appended automatically to your
* log message, if not already there. It is not possible to send several
* messages and have them appear on a single line in logcat.
*
- * PLEASE USE LOGS WITH MODERATION:
+ * Please use logging in moderation:
*
* - Sending log messages eats CPU and slow down your application and the
* system.
*
- * - The circular log buffer is pretty small (<64KB), sending many messages
- * might push off other important log messages from the rest of the system.
+ * - The circular log buffer is pretty small, so sending many messages
+ * will hide other important log messages.
*
* - In release builds, only send log messages to account for exceptional
* conditions.
- *
- * NOTE: These functions MUST be implemented by /system/lib/liblog.so
*/
#include <stdarg.h>
@@ -73,28 +73,40 @@
extern "C" {
#endif
-/*
- * Android log priority values, in ascending priority order.
+/**
+ * Android log priority values, in increasing order of priority.
*/
typedef enum android_LogPriority {
+ /** For internal use only. */
ANDROID_LOG_UNKNOWN = 0,
+ /** The default priority, for internal use only. */
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ /** Verbose logging. Should typically be disabled for a release apk. */
ANDROID_LOG_VERBOSE,
+ /** Debug logging. Should typically be disabled for a release apk. */
ANDROID_LOG_DEBUG,
+ /** Informational logging. Should typically be disabled for a release apk. */
ANDROID_LOG_INFO,
+ /** Warning logging. For use with recoverable failures. */
ANDROID_LOG_WARN,
+ /** Error logging. For use with unrecoverable failures. */
ANDROID_LOG_ERROR,
+ /** Fatal logging. For use when aborting. */
ANDROID_LOG_FATAL,
+ /** For internal use only. */
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
-/*
- * Send a simple string to the log.
+/**
+ * Writes the constant string `text` to the log, with priority `prio` and tag
+ * `tag`.
*/
int __android_log_write(int prio, const char* tag, const char* text);
-/*
- * Send a formatted string to the log, used like printf(fmt,...)
+/**
+ * Writes a formatted string to the log, with priority `prio` and tag `tag`.
+ * The details of formatting are the same as for
+ * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*/
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#if defined(__GNUC__)
@@ -110,9 +122,9 @@
#endif
;
-/*
- * A variant of __android_log_print() that takes a va_list to list
- * additional parameters.
+/**
+ * Equivalent to `__android_log_print`, but taking a `va_list`.
+ * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
*/
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
#if defined(__GNUC__)
@@ -128,9 +140,20 @@
#endif
;
-/*
- * Log an assertion failure and abort the process to have a chance
- * to inspect it if a debugger is attached. This uses the FATAL priority.
+/**
+ * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
+ * stderr, before calling
+ * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
+ *
+ * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
+ * `Assertion failed: %s` is used with `cond` as the string argument.
+ * If both `fmt` and `cond` are null, a default string is provided.
+ *
+ * Most callers should use
+ * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
+ * `<assert.h>` instead, or the `__assert` and `__assert2` functions provided by
+ * bionic if more control is needed. They support automatically including the
+ * source filename and line number more conveniently than this function.
*/
void __android_log_assert(const char* cond, const char* tag, const char* fmt,
...)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 6ddec4d..0ebb226 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -236,6 +236,10 @@
// Different name is useful for debugging
namespace_name = kVendorClassloaderNamespaceName;
ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
+ } else if (!oem_public_libraries_.empty()) {
+ // oem_public_libraries are NOT available to vendor apks, otherwise it
+ // would be system->vendor violation.
+ system_exposed_libraries = system_exposed_libraries + ":" + oem_public_libraries_.c_str();
}
NativeLoaderNamespace native_loader_ns;
@@ -353,9 +357,36 @@
"Error reading public native library list from \"%s\": %s",
public_native_libraries_system_config.c_str(), error_msg.c_str());
+ // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+ // variable to add libraries to the list. This is intended for platform tests only.
+ if (is_debuggable()) {
+ const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+ if (additional_libs != nullptr && additional_libs[0] != '\0') {
+ std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+ std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
+ std::back_inserter(sonames));
+ }
+ }
+
+ // android_init_namespaces() expects all the public libraries
+ // to be loaded so that they can be found by soname alone.
+ //
+ // TODO(dimitry): this is a bit misleading since we do not know
+ // if the vendor public library is going to be opened from /vendor/lib
+ // we might as well end up loading them from /system/lib
+ // For now we rely on CTS test to catch things like this but
+ // it should probably be addressed in the future.
+ for (const auto& soname : sonames) {
+ LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+ "Error preloading public library %s: %s", soname.c_str(), dlerror());
+ }
+
+ system_public_libraries_ = base::Join(sonames, ':');
+
// read /system/etc/public.libraries-<companyname>.txt which contain partner defined
// system libs that are exposed to apps. The libs in the txt files must be
// named as lib<name>.<companyname>.so.
+ sonames.clear();
std::string dirname = base::Dirname(public_native_libraries_system_config);
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
if (dir != nullptr) {
@@ -396,39 +427,12 @@
}
}
}
+ oem_public_libraries_ = base::Join(sonames, ':');
// Insert VNDK version to llndk and vndksp config file names.
insert_vndk_version_str(&llndk_native_libraries_system_config);
insert_vndk_version_str(&vndksp_native_libraries_system_config);
- // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
- // variable to add libraries to the list. This is intended for platform tests only.
- if (is_debuggable()) {
- const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
- if (additional_libs != nullptr && additional_libs[0] != '\0') {
- std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
- std::copy(additional_libs_vector.begin(),
- additional_libs_vector.end(),
- std::back_inserter(sonames));
- }
- }
-
- // android_init_namespaces() expects all the public libraries
- // to be loaded so that they can be found by soname alone.
- //
- // TODO(dimitry): this is a bit misleading since we do not know
- // if the vendor public library is going to be opened from /vendor/lib
- // we might as well end up loading them from /system/lib
- // For now we rely on CTS test to catch things like this but
- // it should probably be addressed in the future.
- for (const auto& soname : sonames) {
- LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
- "Error preloading public library %s: %s",
- soname.c_str(), dlerror());
- }
-
- system_public_libraries_ = base::Join(sonames, ':');
-
sonames.clear();
ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
system_llndk_libraries_ = base::Join(sonames, ':');
@@ -554,6 +558,7 @@
std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string system_public_libraries_;
std::string vendor_public_libraries_;
+ std::string oem_public_libraries_;
std::string system_llndk_libraries_;
std::string system_vndksp_libraries_;
diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk
index 4c3da4a..e625454 100644
--- a/libnativeloader/test/Android.mk
+++ b/libnativeloader/test/Android.mk
@@ -28,3 +28,23 @@
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-system
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := oemlibrarytest-vendor
+LOCAL_MODULE_TAGS := tests
+LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS)
+include $(BUILD_PACKAGE)
diff --git a/libnativeloader/test/runtest.sh b/libnativeloader/test/runtest.sh
new file mode 100755
index 0000000..40beb5b
--- /dev/null
+++ b/libnativeloader/test/runtest.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+adb root
+adb remount
+adb sync
+adb shell stop
+adb shell start
+sleep 5 # wait until device reboots
+adb logcat -c;
+adb shell am start -n android.test.app.system/android.test.app.TestActivity
+adb shell am start -n android.test.app.vendor/android.test.app.TestActivity
+adb logcat | grep android.test.app
diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java
new file mode 100644
index 0000000..214892d
--- /dev/null
+++ b/libnativeloader/test/src/android/test/app/TestActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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 android.test.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ tryLoadingLib("foo.oem1");
+ tryLoadingLib("bar.oem1");
+ tryLoadingLib("foo.oem2");
+ tryLoadingLib("bar.oem2");
+ }
+
+ private void tryLoadingLib(String name) {
+ try {
+ System.loadLibrary(name);
+ Log.d(getPackageName(), "library " + name + " is successfully loaded");
+ } catch (UnsatisfiedLinkError e) {
+ Log.d(getPackageName(), "failed to load libarary " + name, e);
+ }
+ }
+}
diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/system/AndroidManifest.xml
new file mode 100644
index 0000000..c304889
--- /dev/null
+++ b/libnativeloader/test/system/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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="android.test.app.system">
+
+ <application>
+ <activity android:name="android.test.app.TestActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+
diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/vendor/AndroidManifest.xml
new file mode 100644
index 0000000..c4c1a9c
--- /dev/null
+++ b/libnativeloader/test/vendor/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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="android.test.app.vendor">
+
+ <application>
+ <activity android:name="android.test.app.TestActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8dae956..28d7e64 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -124,6 +124,7 @@
"tests/DwarfOpTest.cpp",
"tests/DwarfSectionTest.cpp",
"tests/DwarfSectionImplTest.cpp",
+ "tests/ElfCacheTest.cpp",
"tests/ElfFake.cpp",
"tests/ElfInterfaceArmTest.cpp",
"tests/ElfInterfaceTest.cpp",
diff --git a/libunwindstack/AsmGetRegsX86.S b/libunwindstack/AsmGetRegsX86.S
index 14927a3..021e628 100644
--- a/libunwindstack/AsmGetRegsX86.S
+++ b/libunwindstack/AsmGetRegsX86.S
@@ -50,12 +50,12 @@
movl (%esp), %ecx
movl %ecx, 32(%eax)
- movl %cs, 36(%eax)
- movl %ss, 40(%eax)
- movl %ds, 44(%eax)
- movl %es, 48(%eax)
- movl %fs, 52(%eax)
- movl %gs, 56(%eax)
+ mov %cs, 36(%eax)
+ mov %ss, 40(%eax)
+ mov %ds, 44(%eax)
+ mov %es, 48(%eax)
+ mov %fs, 52(%eax)
+ mov %gs, 56(%eax)
ret
.cfi_endproc
diff --git a/libunwindstack/DwarfError.h b/libunwindstack/DwarfError.h
deleted file mode 100644
index d3cdd4d..0000000
--- a/libunwindstack/DwarfError.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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 _LIBUNWINDSTACK_DWARF_ERROR_H
-#define _LIBUNWINDSTACK_DWARF_ERROR_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum DwarfError : uint8_t {
- DWARF_ERROR_NONE,
- DWARF_ERROR_MEMORY_INVALID,
- DWARF_ERROR_ILLEGAL_VALUE,
- DWARF_ERROR_ILLEGAL_STATE,
- DWARF_ERROR_STACK_INDEX_NOT_VALID,
- DWARF_ERROR_NOT_IMPLEMENTED,
- DWARF_ERROR_TOO_MANY_ITERATIONS,
- DWARF_ERROR_CFA_NOT_DEFINED,
- DWARF_ERROR_UNSUPPORTED_VERSION,
- DWARF_ERROR_NO_FDES,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index f120da2..dbf772e 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,6 +35,10 @@
namespace unwindstack {
+bool Elf::cache_enabled_;
+std::unordered_map<std::string, std::shared_ptr<Elf>>* Elf::cache_;
+std::mutex* Elf::cache_lock_;
+
bool Elf::Init(bool init_gnu_debugdata) {
load_bias_ = 0;
if (!memory_) {
@@ -301,4 +305,42 @@
return 0;
}
+void Elf::SetCachingEnabled(bool enable) {
+ if (!cache_enabled_ && enable) {
+ cache_enabled_ = true;
+ cache_ = new std::unordered_map<std::string, std::shared_ptr<Elf>>;
+ cache_lock_ = new std::mutex;
+ } else if (cache_enabled_ && !enable) {
+ cache_enabled_ = false;
+ delete cache_;
+ delete cache_lock_;
+ }
+}
+
+void Elf::CacheLock() {
+ cache_lock_->lock();
+}
+
+void Elf::CacheUnlock() {
+ cache_lock_->unlock();
+}
+
+void Elf::CacheAdd(MapInfo* info) {
+ if (info->offset == 0) {
+ (*cache_)[info->name] = info->elf;
+ } else {
+ std::string name(info->name + ':' + std::to_string(info->offset));
+ (*cache_)[name] = info->elf;
+ }
+}
+
+bool Elf::CacheGet(const std::string& name, std::shared_ptr<Elf>* elf) {
+ auto entry = cache_->find(name);
+ if (entry != cache_->end()) {
+ *elf = entry->second;
+ return true;
+ }
+ return false;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 89fe038..0c15335 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -109,16 +109,46 @@
// Make sure no other thread is trying to add the elf to this map.
std::lock_guard<std::mutex> guard(mutex_);
- if (elf) {
- return elf;
+ if (elf.get() != nullptr) {
+ return elf.get();
}
- elf = new Elf(CreateMemory(process_memory));
- elf->Init(init_gnu_debugdata);
+ bool locked = false;
+ if (Elf::CachingEnabled() && !name.empty()) {
+ Elf::CacheLock();
+ locked = true;
+ if (offset != 0) {
+ std::string hash(name + ':' + std::to_string(offset));
+ if (Elf::CacheGet(hash, &elf)) {
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ } else if (Elf::CacheGet(name, &elf)) {
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ }
+ Memory* memory = CreateMemory(process_memory);
+ if (locked && offset != 0 && elf_offset != 0) {
+ // In this case, the whole file is the elf, need to see if the elf
+ // data was cached.
+ if (Elf::CacheGet(name, &elf)) {
+ delete memory;
+ Elf::CacheUnlock();
+ return elf.get();
+ }
+ }
+ elf.reset(new Elf(memory));
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
- return elf;
+ elf->Init(init_gnu_debugdata);
+
+ if (locked) {
+ Elf::CacheAdd(this);
+ Elf::CacheUnlock();
+ }
+ return elf.get();
}
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index e562d6d..a874709 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -22,6 +22,7 @@
#include <memory>
#include <mutex>
#include <string>
+#include <unordered_map>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Memory.h>
@@ -96,6 +97,14 @@
static uint64_t GetLoadBias(Memory* memory);
+ static void SetCachingEnabled(bool enable);
+ static bool CachingEnabled() { return cache_enabled_; }
+
+ static void CacheLock();
+ static void CacheUnlock();
+ static void CacheAdd(MapInfo* info);
+ static bool CacheGet(const std::string& name, std::shared_ptr<Elf>* elf);
+
protected:
bool valid_ = false;
uint64_t load_bias_ = 0;
@@ -109,6 +118,10 @@
std::unique_ptr<Memory> gnu_debugdata_memory_;
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
+
+ static bool cache_enabled_;
+ static std::unordered_map<std::string, std::shared_ptr<Elf>>* cache_;
+ static std::mutex* cache_lock_;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 22e48f7..a57fe68 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <atomic>
+#include <memory>
#include <mutex>
#include <string>
@@ -40,14 +41,14 @@
flags(flags),
name(name),
load_bias(static_cast<uint64_t>(-1)) {}
- ~MapInfo() { delete elf; }
+ ~MapInfo() = default;
uint64_t start = 0;
uint64_t end = 0;
uint64_t offset = 0;
uint16_t flags = 0;
std::string name;
- Elf* elf = nullptr;
+ std::shared_ptr<Elf> elf;
// This value is only non-zero if the offset is non-zero but there is
// no elf signature found at that offset. This indicates that the
// entire file is represented by the Memory object returned by CreateMemory,
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
new file mode 100644
index 0000000..0086c9e
--- /dev/null
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 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 <elf.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class ElfCacheTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() { memory_.reset(new MemoryFake); }
+
+ void SetUp() override { Elf::SetCachingEnabled(true); }
+
+ void TearDown() override { Elf::SetCachingEnabled(false); }
+
+ void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
+ ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
+ size_t ehdr_size;
+ Elf32_Ehdr ehdr32;
+ Elf64_Ehdr ehdr64;
+ void* ptr;
+ if (type == EM_ARM || type == EM_386) {
+ ehdr_size = sizeof(ehdr32);
+ ptr = &ehdr32;
+ TestInitEhdr(&ehdr32, ELFCLASS32, type);
+ } else {
+ ehdr_size = sizeof(ehdr64);
+ ptr = &ehdr64;
+ TestInitEhdr(&ehdr64, ELFCLASS64, type);
+ }
+
+ ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
+ ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
+ }
+
+ void VerifyWithinSameMap(bool cache_enabled);
+ void VerifySameMap(bool cache_enabled);
+
+ static std::shared_ptr<Memory> memory_;
+};
+
+std::shared_ptr<Memory> ElfCacheTest::memory_;
+
+void ElfCacheTest::VerifySameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
+
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ close(tf.fd);
+
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ MapInfo info1(start, end, 0, 0x5, tf.path);
+ MapInfo info2(start, end, 0, 0x5, tf.path);
+
+ Elf* elf1 = info1.GetElf(memory_, true);
+ ASSERT_TRUE(elf1->valid());
+ Elf* elf2 = info2.GetElf(memory_, true);
+ ASSERT_TRUE(elf2->valid());
+
+ if (cache_enabled) {
+ EXPECT_EQ(elf1, elf2);
+ } else {
+ EXPECT_NE(elf1, elf2);
+ }
+}
+
+TEST_F(ElfCacheTest, no_caching) {
+ VerifySameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_invalid_elf) {
+ VerifySameMap(true);
+}
+
+void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
+ if (!cache_enabled) {
+ Elf::SetCachingEnabled(false);
+ }
+
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ WriteElfFile(0, &tf, EM_ARM);
+ WriteElfFile(0x100, &tf, EM_386);
+ WriteElfFile(0x200, &tf, EM_X86_64);
+ lseek(tf.fd, 0x500, SEEK_SET);
+ uint8_t value = 0;
+ write(tf.fd, &value, 1);
+ close(tf.fd);
+
+ uint64_t start = 0x1000;
+ uint64_t end = 0x20000;
+ // Will have an elf at offset 0 in file.
+ MapInfo info0_1(start, end, 0, 0x5, tf.path);
+ MapInfo info0_2(start, end, 0, 0x5, tf.path);
+ // Will have an elf at offset 0x100 in file.
+ MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
+ MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
+ // Will have an elf at offset 0x200 in file.
+ MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
+ MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
+ // Will have an elf at offset 0 in file.
+ MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
+ MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
+
+ Elf* elf0_1 = info0_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf0_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_1->arch());
+ Elf* elf0_2 = info0_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf0_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf0_2->arch());
+ EXPECT_EQ(0U, info0_1.elf_offset);
+ EXPECT_EQ(0U, info0_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf0_1, elf0_2);
+ } else {
+ EXPECT_NE(elf0_1, elf0_2);
+ }
+
+ Elf* elf100_1 = info100_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf100_1->valid());
+ EXPECT_EQ(ARCH_X86, elf100_1->arch());
+ Elf* elf100_2 = info100_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf100_2->valid());
+ EXPECT_EQ(ARCH_X86, elf100_2->arch());
+ EXPECT_EQ(0U, info100_1.elf_offset);
+ EXPECT_EQ(0U, info100_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf100_1, elf100_2);
+ } else {
+ EXPECT_NE(elf100_1, elf100_2);
+ }
+
+ Elf* elf200_1 = info200_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf200_1->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
+ Elf* elf200_2 = info200_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf200_2->valid());
+ EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
+ EXPECT_EQ(0U, info200_1.elf_offset);
+ EXPECT_EQ(0U, info200_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf200_1, elf200_2);
+ } else {
+ EXPECT_NE(elf200_1, elf200_2);
+ }
+
+ Elf* elf300_1 = info300_1.GetElf(memory_, true);
+ ASSERT_TRUE(elf300_1->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_1->arch());
+ Elf* elf300_2 = info300_2.GetElf(memory_, true);
+ ASSERT_TRUE(elf300_2->valid());
+ EXPECT_EQ(ARCH_ARM, elf300_2->arch());
+ EXPECT_EQ(0x300U, info300_1.elf_offset);
+ EXPECT_EQ(0x300U, info300_2.elf_offset);
+ if (cache_enabled) {
+ EXPECT_EQ(elf300_1, elf300_2);
+ EXPECT_EQ(elf0_1, elf300_1);
+ } else {
+ EXPECT_NE(elf300_1, elf300_2);
+ EXPECT_NE(elf0_1, elf300_1);
+ }
+}
+
+TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(false);
+}
+
+TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
+ VerifyWithinSameMap(true);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 1a50989..37628f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -62,7 +62,7 @@
ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
@@ -72,7 +72,7 @@
interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
map_info = maps_->Get(6);
ASSERT_TRUE(map_info != nullptr);
@@ -82,7 +82,7 @@
interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
- map_info->elf = elf;
+ map_info->elf.reset(elf);
}
template <typename EhdrType, typename ShdrType>
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 948597b..f599503 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -180,16 +180,14 @@
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.end = 0xfff;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.end = 0x2000;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf != nullptr);
@@ -328,8 +326,7 @@
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
@@ -352,15 +349,13 @@
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.name = "";
elf = info.GetElf(process_memory_, false);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
- delete info.elf;
- info.elf = nullptr;
+ info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_, false);
ASSERT_TRUE(elf->valid());
@@ -403,7 +398,7 @@
}
// Now verify that all of the elf files are exactly the same and valid.
- Elf* elf = info.elf;
+ Elf* elf = info.elf.get();
ASSERT_TRUE(elf != nullptr);
EXPECT_TRUE(elf->valid());
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index 631036b..7e64a8a 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -69,7 +69,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -79,7 +79,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0);
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
@@ -122,7 +122,7 @@
}
TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
- map_info_->elf = elf_container_.release();
+ map_info_->elf.reset(elf_container_.release());
elf_->FakeSetLoadBias(0x1000);
MultipleThreadTest(0x1000);
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 15d5458..7c06373 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -184,7 +184,7 @@
RegsMips64 regs_mips64;
MapInfo map_info(0x1000, 0x2000);
Elf* invalid_elf = new Elf(new MemoryFake);
- map_info.elf = invalid_elf;
+ map_info.elf.reset(invalid_elf);
regs_arm.set_pc(0x1500);
EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index bf2c1d8..45cf907 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -60,7 +60,7 @@
maps_.FakeClear();
MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
ElfFake* elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
@@ -73,25 +73,25 @@
info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
elf = new ElfFake(new MemoryFake);
- info->elf = elf;
+ info->elf.reset(elf);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
maps_.FakeAddMapInfo(info);
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index 00d3379..c8d87c8 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -291,10 +291,12 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the system namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = system
+namespace.vndk.links = system,default
namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.vndk.link.default.allow_all_shared_libs = true
+
###############################################################################
# "system" namespace
#