Merge "Fix typo cpu6 -> cpu7"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index dcb4bf7..fb00508 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -138,6 +138,12 @@
chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+ # filemap events for iorapd
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
write /sys/kernel/tracing/tracing_on 0
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index f4e5b98..acc62c0 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -5,6 +5,12 @@
# Access control to these files is now entirely in selinux policy.
on post-fs
+ # On userdebug allow to enable any event via the generic
+ # set_event interface:
+ # echo sched/foo > set_event == echo 1 > events/sched/foo/enable.
+ chmod 0666 /sys/kernel/tracing/set_event
+ chmod 0666 /sys/kernel/debug/tracing/set_event
+
chmod 0666 /sys/kernel/tracing/events/workqueue/enable
chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
chmod 0666 /sys/kernel/tracing/events/regulator/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 712f861..2824c82 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -475,47 +475,6 @@
return false;
}
-static void dump_systrace() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
- return;
- }
- std::string systrace_path = ds.GetPath("-systrace.txt");
- if (systrace_path.empty()) {
- MYLOGE("Not dumping systrace because path is empty\n");
- return;
- }
- const char* path = "/sys/kernel/debug/tracing/tracing_on";
- long int is_tracing;
- if (read_file_as_long(path, &is_tracing)) {
- return; // error already logged
- }
- if (is_tracing <= 0) {
- MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
- return;
- }
-
- MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
- systrace_path.c_str());
- if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
- CommandOptions::WithTimeout(120).Build())) {
- MYLOGE("systrace timed out, its zip entry will be incomplete\n");
- // TODO: RunCommand tries to kill the process, but atrace doesn't die
- // peacefully; ideally, we should call strace to stop itself, but there is no such option
- // yet (just a --async_stop, which stops and dump
- // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
- // MYLOGE("could not stop systrace ");
- // }
- }
- if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
- MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
- } else {
- if (remove(systrace_path.c_str())) {
- MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -1440,12 +1399,8 @@
/* Dumps state for the default case. Returns true if everything went fine. */
static bool DumpstateDefault() {
- // Dumps systrace right away, otherwise it will be filled with unnecessary events.
- // First try to dump anrd trace if the daemon is running. Otherwise, dump
- // the raw trace.
- if (!dump_anrd_trace()) {
- dump_systrace();
- }
+ // Try to dump anrd trace if the daemon is running.
+ dump_anrd_trace();
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
@@ -2256,6 +2211,28 @@
options_ = std::move(options);
}
+Dumpstate::RunStatus Dumpstate::Run() {
+ Dumpstate::RunStatus status = RunInternal();
+ if (listener_ != nullptr) {
+ switch (status) {
+ case Dumpstate::RunStatus::OK:
+ // TODO(b/111441001): duration argument does not make sense. Remove.
+ listener_->onFinished(0 /* duration */, options_->notification_title,
+ options_->notification_description);
+ break;
+ case Dumpstate::RunStatus::HELP:
+ break;
+ case Dumpstate::RunStatus::INVALID_INPUT:
+ listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+ break;
+ case Dumpstate::RunStatus::ERROR:
+ listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+ break;
+ }
+ }
+ return status;
+}
+
/*
* Dumps relevant information to a bugreport based on the given options.
*
@@ -2277,7 +2254,7 @@
* Bugreports are first generated in a local directory and later copied to the caller's fd or
* directory.
*/
-Dumpstate::RunStatus Dumpstate::Run() {
+Dumpstate::RunStatus Dumpstate::RunInternal() {
LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
@@ -2482,6 +2459,7 @@
/* tell activity manager we're done */
if (options_->do_broadcast) {
SendBugreportFinishedBroadcast();
+ // Note that listener_ is notified in Run();
}
MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 529111e..c620c07 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -449,6 +449,8 @@
std::vector<DumpData> anr_data_;
private:
+ RunStatus RunInternal();
+
// Used by GetInstance() only.
explicit Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 98ee1b0..cd9b97f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -656,8 +656,9 @@
}
if (update_progress) {
- message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
- listener_name.c_str(), progress, max);
+ message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+ listener_name.c_str(), progress, max,
+ (100 * progress / max));
}
return message;
@@ -816,12 +817,14 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(20));
+ EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
EXPECT_CALL(*listener, onProgressUpdated(30));
+ EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -830,6 +833,7 @@
// Run a command that will increase maximum timeout.
EXPECT_CALL(*listener, onProgressUpdated(31));
EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+ EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -838,6 +842,7 @@
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
EXPECT_CALL(*listener, onProgressUpdated(35));
+ EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
EXPECT_THAT(out, IsEmpty());
@@ -854,6 +859,7 @@
// First update should always be sent.
EXPECT_CALL(*listener, onProgressUpdated(1));
+ EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -866,6 +872,7 @@
// Third update should be sent because it reaches threshold (6 - 1 = 5).
EXPECT_CALL(*listener, onProgressUpdated(6));
+ EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -1105,6 +1112,7 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(5));
+ EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 990fd43..528e43d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -949,16 +949,22 @@
fsync(control_socket_fd_);
}
+ int percent = 100 * progress / max;
if (listener_ != nullptr) {
- if (progress % 100 == 0) {
- // We don't want to spam logcat, so only log multiples of 100.
- MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ if (percent % 5 == 0) {
+ // We don't want to spam logcat, so only log multiples of 5.
+ MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+ percent);
} else {
// stderr is ignored on normal invocations, but useful when calling
// /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+ progress, max, percent);
}
+ // TODO(b/111441001): Remove in favor of onProgress
listener_->onProgressUpdated(progress);
+
+ listener_->onProgress(percent);
}
}
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/cmds/surfacereplayer/OWNERS
@@ -0,0 +1,2 @@
+mathias@google.com
+racarr@google.com
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 05d96ff..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -112,15 +112,25 @@
#if __ANDROID_API__ >= 29
+/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
enum ResNsendFlags : uint32_t {
- // Send a single request to a single resolver and fail on timeout or network errors
+ /**
+ * Send a single request to a single resolver and fail on timeout or network errors
+ */
ANDROID_RESOLV_NO_RETRY = 1 << 0,
- // Do not cache the result of the lookup. The lookup may return a result that is already
- // in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ /**
+ * Do not cache the result of the lookup. The lookup may return a result that is already
+ * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ */
ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
- // Don't lookup the request in cache, do not write back the response into the cache
+ /**
+ * Don't lookup the request in cache.
+ */
ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
};
@@ -136,8 +146,7 @@
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nquery(net_handle_t network,
- const char *dname, int ns_class, int ns_type,
- enum ResNsendFlags flags) __INTRODUCED_IN(29);
+ const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
/**
* Issue the query |msg| on the given |network|.
@@ -148,10 +157,11 @@
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nsend(net_handle_t network,
- const uint8_t *msg, size_t msglen, enum ResNsendFlags flags) __INTRODUCED_IN(29);
+ const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
/**
* Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
*
* Returns:
* < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 17e8f6b..784e2c8 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -23,7 +23,7 @@
namespace android {
-class NativeLoaderNamespace;
+struct NativeLoaderNamespace;
class GraphicsEnv {
public:
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index a7c7e79..73150dc 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,8 +1,7 @@
-brianderson@google.com
jessehall@google.com
jwcai@google.com
+lpy@google.com
+marissaw@google.com
mathias@google.com
-olv@google.com
-pceballos@google.com
racarr@google.com
stoza@google.com
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..b377a41 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -40,13 +40,14 @@
#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define ATRACE_BUFFER_INDEX(index) \
- if (ATRACE_ENABLED()) { \
- char ___traceBuf[1024]; \
- snprintf(___traceBuf, 1024, "%s: %d", \
- mCore->mConsumerName.string(), (index)); \
- android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
- }
+#define ATRACE_BUFFER_INDEX(index) \
+ do { \
+ if (ATRACE_ENABLED()) { \
+ char ___traceBuf[1024]; \
+ snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+ android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
+ } \
+ } while (false)
namespace android {
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
new file mode 100644
index 0000000..6fb149a
--- /dev/null
+++ b/libs/math/OWNERS
@@ -0,0 +1,6 @@
+jaesoo@google.com
+jiyong@google.com
+mathias@google.com
+pawin@google.com
+randolphs@google.com
+romainguy@google.com
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 6926f7f..324d443 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -57,15 +57,15 @@
uint8_t b[16];
int64_t i64[2];
};
- uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+ explicit uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
uuid_t() : b{0} {}
};
Sensor(const Sensor&) = default;
Sensor& operator=(const Sensor&) = default;
- Sensor(const char * name = "");
- Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+ explicit Sensor(const char * name = "");
+ explicit Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
~Sensor();
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index baed2ee..8176578 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -64,7 +64,7 @@
// Default sensor sample period
static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
- SensorEventQueue(const sp<ISensorEventConnection>& connection);
+ explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
virtual ~SensorEventQueue();
virtual void onFirstRef();
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 23f7a91..f09c9c6 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -71,7 +71,7 @@
void sensorManagerDied();
static status_t waitForSensorService(sp<ISensorServer> *server);
- SensorManager(const String16& opPackageName);
+ explicit SensorManager(const String16& opPackageName);
status_t assertStateLocked();
private:
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
new file mode 100644
index 0000000..3938e4f
--- /dev/null
+++ b/libs/ui/OWNERS
@@ -0,0 +1,5 @@
+jiyong@google.com
+mathias@google.com
+olv@google.com
+romainguy@google.com
+stoza@google.com
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
new file mode 100644
index 0000000..7a3e4c2
--- /dev/null
+++ b/services/displayservice/OWNERS
@@ -0,0 +1,2 @@
+smoreland@google.com
+lpy@google.com
diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
index 5a35410..031744a 100644
--- a/services/sensorservice/SensorRecord.h
+++ b/services/sensorservice/SensorRecord.h
@@ -25,7 +25,7 @@
class SensorService::SensorRecord {
public:
- SensorRecord(const sp<const SensorEventConnection>& connection);
+ explicit SensorRecord(const sp<const SensorEventConnection>& connection);
bool addConnection(const sp<const SensorEventConnection>& connection);
bool removeConnection(const wp<const SensorEventConnection>& connection);
size_t getNumConnections() const { return mConnections.size(); }
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index ddcee28..8d7a05b 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -43,7 +43,7 @@
struct SensorManager final : public ISensorManager {
- SensorManager(JavaVM* vm);
+ explicit SensorManager(JavaVM* vm);
~SensorManager();
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 495c14e..934ae58 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
mat() { }
mat(const mat& rhs) : base(rhs) { }
- mat(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ mat(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
// sets the diagonal to the value, off-diagonal to zero
- mat(pTYPE rhs) { // NOLINT(implicit)
+ mat(pTYPE rhs) { // NOLINT(google-explicit-constructor)
helpers::doAssign(*this, rhs);
}
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 9e5d280..c195434 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
vec() { }
vec(const vec& rhs) : base(rhs) { }
- vec(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ vec(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
- vec(pTYPE rhs) { // NOLINT(implicit)
+ vec(pTYPE rhs) { // NOLINT(google-explicit-constructor)
for (size_t i=0 ; i<SIZE ; i++)
base::operator[](i) = rhs;
}
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 009b257..ba4cf00 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -139,12 +139,12 @@
auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace &&
!android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
- std::string error_msg;
- dlhandle_ = OpenNativeLibrary(
+ char* error_msg = nullptr;
+ dlhandle_ = OpenNativeLibraryInNamespace(
app_namespace, path_.c_str(), &native_bridge_, &error_msg);
if (!dlhandle_) {
- ALOGE("failed to load layer library '%s': %s", path_.c_str(),
- error_msg.c_str());
+ ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_ = 0;
return false;
}
@@ -165,9 +165,10 @@
std::lock_guard<std::mutex> lock(mutex_);
if (--refcount_ == 0) {
ALOGV("closing layer library '%s'", path_.c_str());
- std::string error_msg;
+ char* error_msg = nullptr;
if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
- ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+ ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_++;
} else {
dlhandle_ = nullptr;