Merge "Now for real unmount bind-mounts on top of /data"
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 0fb14c4..f62032d 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -85,7 +85,6 @@
#include <paths.h>
#include <pty.h>
#include <pwd.h>
-#include <sys/select.h>
#include <termios.h>
#include <memory>
@@ -141,6 +140,20 @@
return true;
}
+struct SubprocessPollfds {
+ adb_pollfd pfds[3];
+
+ adb_pollfd* data() { return pfds; }
+ size_t size() { return 3; }
+
+ adb_pollfd* begin() { return pfds; }
+ adb_pollfd* end() { return pfds + size(); }
+
+ adb_pollfd& stdinout_pfd() { return pfds[0]; }
+ adb_pollfd& stderr_pfd() { return pfds[1]; }
+ adb_pollfd& protocol_pfd() { return pfds[2]; }
+};
+
class Subprocess {
public:
Subprocess(std::string command, const char* terminal_type, SubprocessType type,
@@ -176,8 +189,7 @@
void PassDataStreams();
void WaitForExit();
- unique_fd* SelectLoop(fd_set* master_read_set_ptr,
- fd_set* master_write_set_ptr);
+ unique_fd* PollLoop(SubprocessPollfds* pfds);
// Input/output stream handlers. Success returns nullptr, failure returns
// a pointer to the failed FD.
@@ -545,23 +557,23 @@
}
// Start by trying to read from the protocol FD, stdout, and stderr.
- fd_set master_read_set, master_write_set;
- FD_ZERO(&master_read_set);
- FD_ZERO(&master_write_set);
- for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
- if (*sfd != -1) {
- FD_SET(sfd->get(), &master_read_set);
- }
- }
+ SubprocessPollfds pfds;
+ pfds.stdinout_pfd() = {.fd = stdinout_sfd_.get(), .events = POLLIN};
+ pfds.stderr_pfd() = {.fd = stderr_sfd_.get(), .events = POLLIN};
+ pfds.protocol_pfd() = {.fd = protocol_sfd_.get(), .events = POLLIN};
// Pass data until the protocol FD or both the subprocess pipes die, at
// which point we can't pass any more data.
while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
- unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
+ unique_fd* dead_sfd = PollLoop(&pfds);
if (dead_sfd) {
D("closing FD %d", dead_sfd->get());
- FD_CLR(dead_sfd->get(), &master_read_set);
- FD_CLR(dead_sfd->get(), &master_write_set);
+ auto it = std::find_if(pfds.begin(), pfds.end(), [=](const adb_pollfd& pfd) {
+ return pfd.fd == dead_sfd->get();
+ });
+ CHECK(it != pfds.end());
+ it->fd = -1;
+ it->events = 0;
if (dead_sfd == &protocol_sfd_) {
// Using SIGHUP is a decent general way to indicate that the
// controlling process is going away. If specific signals are
@@ -583,30 +595,19 @@
}
}
-namespace {
-
-inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
- return sfd != -1 && FD_ISSET(sfd.get(), set);
-}
-
-} // namespace
-
-unique_fd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
- fd_set* master_write_set_ptr) {
- fd_set read_set, write_set;
- int select_n =
- std::max(std::max(protocol_sfd_.get(), stdinout_sfd_.get()), stderr_sfd_.get()) + 1;
+unique_fd* Subprocess::PollLoop(SubprocessPollfds* pfds) {
unique_fd* dead_sfd = nullptr;
+ adb_pollfd& stdinout_pfd = pfds->stdinout_pfd();
+ adb_pollfd& stderr_pfd = pfds->stderr_pfd();
+ adb_pollfd& protocol_pfd = pfds->protocol_pfd();
- // Keep calling select() and passing data until an FD closes/errors.
+ // Keep calling poll() and passing data until an FD closes/errors.
while (!dead_sfd) {
- memcpy(&read_set, master_read_set_ptr, sizeof(read_set));
- memcpy(&write_set, master_write_set_ptr, sizeof(write_set));
- if (select(select_n, &read_set, &write_set, nullptr, nullptr) < 0) {
+ if (adb_poll(pfds->data(), pfds->size(), -1) < 0) {
if (errno == EINTR) {
continue;
} else {
- PLOG(ERROR) << "select failed, closing subprocess pipes";
+ PLOG(ERROR) << "poll failed, closing subprocess pipes";
stdinout_sfd_.reset(-1);
stderr_sfd_.reset(-1);
return nullptr;
@@ -614,34 +615,47 @@
}
// Read stdout, write to protocol FD.
- if (ValidAndInSet(stdinout_sfd_, &read_set)) {
+ if (stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLIN)) {
dead_sfd = PassOutput(&stdinout_sfd_, ShellProtocol::kIdStdout);
}
// Read stderr, write to protocol FD.
- if (!dead_sfd && ValidAndInSet(stderr_sfd_, &read_set)) {
+ if (!dead_sfd && stderr_pfd.fd != 1 && (stderr_pfd.revents & POLLIN)) {
dead_sfd = PassOutput(&stderr_sfd_, ShellProtocol::kIdStderr);
}
// Read protocol FD, write to stdin.
- if (!dead_sfd && ValidAndInSet(protocol_sfd_, &read_set)) {
+ if (!dead_sfd && protocol_pfd.fd != -1 && (protocol_pfd.revents & POLLIN)) {
dead_sfd = PassInput();
// If we didn't finish writing, block on stdin write.
if (input_bytes_left_) {
- FD_CLR(protocol_sfd_.get(), master_read_set_ptr);
- FD_SET(stdinout_sfd_.get(), master_write_set_ptr);
+ protocol_pfd.events &= ~POLLIN;
+ stdinout_pfd.events |= POLLOUT;
}
}
// Continue writing to stdin; only happens if a previous write blocked.
- if (!dead_sfd && ValidAndInSet(stdinout_sfd_, &write_set)) {
+ if (!dead_sfd && stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLOUT)) {
dead_sfd = PassInput();
// If we finished writing, go back to blocking on protocol read.
if (!input_bytes_left_) {
- FD_SET(protocol_sfd_.get(), master_read_set_ptr);
- FD_CLR(stdinout_sfd_.get(), master_write_set_ptr);
+ protocol_pfd.events |= POLLIN;
+ stdinout_pfd.events &= ~POLLOUT;
}
}
+
+ // After handling all of the events we've received, check to see if any fds have died.
+ if (stdinout_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+ return &stdinout_sfd_;
+ }
+
+ if (stderr_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+ return &stderr_sfd_;
+ }
+
+ if (protocol_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+ return &protocol_sfd_;
+ }
} // while (!dead_sfd)
return dead_sfd;
diff --git a/adb/test_device.py b/adb/test_device.py
index 57925e8..083adce 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -536,6 +536,36 @@
for i, success in result.iteritems():
self.assertTrue(success)
+ def disabled_test_parallel(self):
+ """Spawn a bunch of `adb shell` instances in parallel.
+
+ This was broken historically due to the use of select, which only works
+ for fds that are numerically less than 1024.
+
+ Bug: http://b/141955761"""
+
+ n_procs = 2048
+ procs = dict()
+ for i in xrange(0, n_procs):
+ procs[i] = subprocess.Popen(
+ ['adb', 'shell', 'read foo; echo $foo; read rc; exit $rc'],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE
+ )
+
+ for i in xrange(0, n_procs):
+ procs[i].stdin.write("%d\n" % i)
+
+ for i in xrange(0, n_procs):
+ response = procs[i].stdout.readline()
+ assert(response == "%d\n" % i)
+
+ for i in xrange(0, n_procs):
+ procs[i].stdin.write("%d\n" % (i % 256))
+
+ for i in xrange(0, n_procs):
+ assert(procs[i].wait() == i % 256)
+
class ArgumentEscapingTest(DeviceTest):
def test_shell_escaping(self):
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 0e61234..5ca1fee 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -834,6 +834,10 @@
}
static void HandleUserspaceReboot() {
+ if (!android::sysprop::InitProperties::userspace_reboot_in_progress().value_or(false)) {
+ LOG(ERROR) << "Attempted a userspace reboot on a device that doesn't support it";
+ return;
+ }
// Spinnig up a separate thread will fail the setns call later in the boot sequence.
// Fork a new process to monitor userspace reboot while we are investigating a better solution.
pid_t pid = fork();
diff --git a/init/sysprop/InitProperties.sysprop b/init/sysprop/InitProperties.sysprop
index d6a1ab6..c856358 100644
--- a/init/sysprop/InitProperties.sysprop
+++ b/init/sysprop/InitProperties.sysprop
@@ -25,3 +25,12 @@
integer_as_bool: true
}
+# Shows whenever the device supports userspace reboot or not.
+prop {
+ api_name: "is_userspace_reboot_supported"
+ type: Boolean
+ scope: System
+ access: Readonly
+ prop_name: "ro.init.userspace_reboot.is_supported"
+ integer_as_bool: true
+}
diff --git a/init/sysprop/api/com.android.sysprop.init-current.txt b/init/sysprop/api/com.android.sysprop.init-current.txt
index 8da50e0..b8bcef9 100644
--- a/init/sysprop/api/com.android.sysprop.init-current.txt
+++ b/init/sysprop/api/com.android.sysprop.init-current.txt
@@ -1,6 +1,11 @@
props {
module: "android.sysprop.InitProperties"
prop {
+ api_name: "is_userspace_reboot_supported"
+ prop_name: "ro.init.userspace_reboot.is_supported"
+ integer_as_bool: true
+ }
+ prop {
api_name: "userspace_reboot_in_progress"
access: ReadWrite
prop_name: "sys.init.userspace_reboot.in_progress"
diff --git a/libstats/Android.bp b/libstats/Android.bp
deleted file mode 100644
index 89c4048..0000000
--- a/libstats/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-subdirs = [
- "socket",
- "socket_q",
-]
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
new file mode 100644
index 0000000..465c05a
--- /dev/null
+++ b/libstats/push_compat/Android.bp
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2019 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.
+//
+
+// =========================================================================
+// Native library that toggles between the old and new statsd socket
+// protocols. This library should only be used by DNS resolver or other
+// native modules on Q that log pushed atoms to statsd.
+// =========================================================================
+cc_defaults {
+ name: "libstatspush_compat_defaults",
+ srcs: [
+ "statsd_writer.c",
+ "stats_event_list.c",
+ "StatsEventCompat.cpp"
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DWRITE_TO_STATSD=1",
+ "-DWRITE_TO_LOGD=0",
+ ],
+ header_libs: ["libstatssocket_headers"],
+ static_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "libstatspush_compat",
+ defaults: ["libstatspush_compat_defaults"],
+ export_include_dirs: ["include"],
+ static_libs: ["libgtest_prod"],
+}
+
+cc_test {
+ name: "libstatspush_compat_test",
+ defaults: ["libstatspush_compat_defaults"],
+ test_suites: ["device_tests"],
+ srcs: [
+ "tests/StatsEventCompat_test.cpp",
+ ],
+ static_libs: ["libgmock"],
+}
+
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
new file mode 100644
index 0000000..edfa070
--- /dev/null
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2019 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 "include/StatsEventCompat.h"
+#include <android-base/properties.h>
+#include <android/api-level.h>
+#include <android/log.h>
+#include <dlfcn.h>
+#include <utils/SystemClock.h>
+
+using android::base::GetProperty;
+
+const static int kStatsEventTag = 1937006964;
+
+/* Checking ro.build.version.release is fragile, as the release field is
+ * an opaque string without structural guarantees. However, testing confirms
+ * that on Q devices, the property is "10," and on R, it is "R." Until
+ * android_get_device_api_level() is updated, this is the only solution.
+ *
+ * TODO(b/146019024): migrate to android_get_device_api_level()
+ */
+const bool StatsEventCompat::mPlatformAtLeastR =
+ GetProperty("ro.build.version.codename", "") == "R" ||
+ android_get_device_api_level() > __ANDROID_API_Q__;
+
+// definitions of static class variables
+bool StatsEventCompat::mAttemptedLoad = false;
+struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
+std::mutex StatsEventCompat::mLoadLock;
+
+StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
+ // guard loading because StatsEventCompat might be called from multithreaded
+ // environment
+ {
+ std::lock_guard<std::mutex> lg(mLoadLock);
+ if (!mAttemptedLoad) {
+ void* handle = dlopen("libstatssocket.so", RTLD_NOW);
+ if (handle) {
+ mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+ } else {
+ ALOGE("dlopen failed: %s\n", dlerror());
+ }
+ }
+ mAttemptedLoad = true;
+ }
+
+ if (mStatsEventApi) {
+ mEventR = mStatsEventApi->obtain();
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << android::elapsedRealtimeNano();
+ }
+}
+
+StatsEventCompat::~StatsEventCompat() {
+ if (mStatsEventApi) mStatsEventApi->release(mEventR);
+}
+
+void StatsEventCompat::setAtomId(int32_t atomId) {
+ if (mStatsEventApi) {
+ mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << atomId;
+ }
+}
+
+void StatsEventCompat::writeInt32(int32_t value) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_int32(mEventR, value);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << value;
+ }
+}
+
+void StatsEventCompat::writeInt64(int64_t value) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_int64(mEventR, value);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << value;
+ }
+}
+
+void StatsEventCompat::writeFloat(float value) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_float(mEventR, value);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << value;
+ }
+}
+
+void StatsEventCompat::writeBool(bool value) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_bool(mEventR, value);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << value;
+ }
+}
+
+void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ.AppendCharArray(buffer, length);
+ }
+}
+
+void StatsEventCompat::writeString(const char* value) {
+ if (value == nullptr) value = "";
+
+ if (mStatsEventApi) {
+ mStatsEventApi->write_string8(mEventR, value);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ << value;
+ }
+}
+
+void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
+ const vector<const char*>& tags) {
+ if (mStatsEventApi) {
+ mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
+ (uint8_t)numUids);
+ } else if (!mPlatformAtLeastR) {
+ mEventQ.begin();
+ for (size_t i = 0; i < numUids; i++) {
+ mEventQ.begin();
+ mEventQ << uids[i];
+ const char* tag = tags[i] ? tags[i] : "";
+ mEventQ << tag;
+ mEventQ.end();
+ }
+ mEventQ.end();
+ }
+}
+
+void StatsEventCompat::writeKeyValuePairs(const map<int, int32_t>& int32Map,
+ const map<int, int64_t>& int64Map,
+ const map<int, const char*>& stringMap,
+ const map<int, float>& floatMap) {
+ if (mStatsEventApi) {
+ vector<struct key_value_pair> pairs;
+
+ for (const auto& it : int32Map) {
+ pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
+ }
+ for (const auto& it : int64Map) {
+ pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
+ }
+ for (const auto& it : stringMap) {
+ pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
+ }
+ for (const auto& it : floatMap) {
+ pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
+ }
+
+ mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
+ }
+
+ else if (!mPlatformAtLeastR) {
+ mEventQ.begin();
+ writeKeyValuePairMap(int32Map);
+ writeKeyValuePairMap(int64Map);
+ writeKeyValuePairMap(stringMap);
+ writeKeyValuePairMap(floatMap);
+ mEventQ.end();
+ }
+}
+
+template <class T>
+void StatsEventCompat::writeKeyValuePairMap(const map<int, T>& keyValuePairMap) {
+ for (const auto& it : keyValuePairMap) {
+ mEventQ.begin();
+ mEventQ << it.first;
+ mEventQ << it.second;
+ mEventQ.end();
+ }
+}
+
+// explicitly specify which types we're going to use
+template void StatsEventCompat::writeKeyValuePairMap<int32_t>(const map<int, int32_t>&);
+template void StatsEventCompat::writeKeyValuePairMap<int64_t>(const map<int, int64_t>&);
+template void StatsEventCompat::writeKeyValuePairMap<float>(const map<int, float>&);
+template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
+
+void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
+ if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+ // Don't do anything if on Q.
+}
+
+void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
+ if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+ // Don't do anything if on Q.
+}
+
+int StatsEventCompat::writeToSocket() {
+ if (mStatsEventApi) {
+ mStatsEventApi->build(mEventR);
+ return mStatsEventApi->write(mEventR);
+ }
+
+ if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
+
+ // We reach here only if we're on R, but libstatspush_compat was unable to
+ // be loaded using dlopen.
+ return -ENOLINK;
+}
+
+bool StatsEventCompat::usesNewSchema() {
+ return mStatsEventApi != nullptr;
+}
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
new file mode 100644
index 0000000..a8cde68
--- /dev/null
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include <map>
+#include <mutex>
+#include <vector>
+#include "stats_event.h"
+#include "stats_event_list.h"
+
+using std::map;
+using std::vector;
+
+class StatsEventCompat {
+ public:
+ StatsEventCompat();
+ ~StatsEventCompat();
+
+ void setAtomId(int32_t atomId);
+ void writeInt32(int32_t value);
+ void writeInt64(int64_t value);
+ void writeFloat(float value);
+ void writeBool(bool value);
+ void writeByteArray(const char* buffer, size_t length);
+ void writeString(const char* value);
+
+ // Pre-condition: numUids == tags.size()
+ void writeAttributionChain(const int32_t* uids, size_t numUids,
+ const vector<const char*>& tags);
+
+ void writeKeyValuePairs(const map<int, int32_t>& int32Map, const map<int, int64_t>& int64Map,
+ const map<int, const char*>& stringMap,
+ const map<int, float>& floatMap);
+
+ void addBoolAnnotation(uint8_t annotationId, bool value);
+ void addInt32Annotation(uint8_t annotationId, int32_t value);
+
+ int writeToSocket();
+
+ private:
+ // static member variables
+ const static bool mPlatformAtLeastR;
+ static bool mAttemptedLoad;
+ static std::mutex mLoadLock;
+ static struct stats_event_api_table* mStatsEventApi;
+
+ // non-static member variables
+ struct stats_event* mEventR = nullptr;
+ stats_event_list mEventQ;
+
+ template <class T>
+ void writeKeyValuePairMap(const map<int, T>& keyValuePairMap);
+
+ bool usesNewSchema();
+ FRIEND_TEST(StatsEventCompatTest, TestDynamicLoading);
+};
diff --git a/libstats/socket_q/include/stats_event_list.h b/libstats/push_compat/include/stats_event_list.h
similarity index 100%
rename from libstats/socket_q/include/stats_event_list.h
rename to libstats/push_compat/include/stats_event_list.h
diff --git a/libstats/socket_q/stats_event_list.c b/libstats/push_compat/stats_event_list.c
similarity index 100%
rename from libstats/socket_q/stats_event_list.c
rename to libstats/push_compat/stats_event_list.c
diff --git a/libstats/socket_q/statsd_writer.c b/libstats/push_compat/statsd_writer.c
similarity index 100%
rename from libstats/socket_q/statsd_writer.c
rename to libstats/push_compat/statsd_writer.c
diff --git a/libstats/socket_q/statsd_writer.h b/libstats/push_compat/statsd_writer.h
similarity index 100%
rename from libstats/socket_q/statsd_writer.h
rename to libstats/push_compat/statsd_writer.h
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
new file mode 100644
index 0000000..2be24ec
--- /dev/null
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 "include/StatsEventCompat.h"
+#include <android-base/properties.h>
+#include <android/api-level.h>
+#include <gtest/gtest.h>
+
+using android::base::GetProperty;
+
+/* Checking ro.build.version.release is fragile, as the release field is
+ * an opaque string without structural guarantees. However, testing confirms
+ * that on Q devices, the property is "10," and on R, it is "R." Until
+ * android_get_device_api_level() is updated, this is the only solution.
+ *
+ *
+ * TODO(b/146019024): migrate to android_get_device_api_level()
+ */
+const static bool mPlatformAtLeastR = GetProperty("ro.build.version.release", "") == "R" ||
+ android_get_device_api_level() > __ANDROID_API_Q__;
+
+TEST(StatsEventCompatTest, TestDynamicLoading) {
+ StatsEventCompat event;
+ EXPECT_EQ(mPlatformAtLeastR, event.usesNewSchema());
+}
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index b7c07b6..94c405d 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -20,7 +20,10 @@
cc_library {
name: "libstatssocket",
srcs: [
+ "stats_buffer_writer.c",
"stats_event.c",
+ // TODO(b/145573568): Remove stats_event_list once stats_event
+ // migration is complete.
"stats_event_list.c",
"statsd_writer.c",
],
@@ -38,3 +41,29 @@
"liblog",
],
}
+
+cc_library_headers {
+ name: "libstatssocket_headers",
+ export_include_dirs: ["include"],
+ host_supported: true,
+}
+
+cc_benchmark {
+ name: "libstatssocket_benchmark",
+ srcs: [
+ "benchmark/main.cpp",
+ "benchmark/stats_event_benchmark.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ static_libs: [
+ "libstatssocket",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libgtest_prod",
+ ],
+}
diff --git a/libstats/socket/benchmark/main.cpp b/libstats/socket/benchmark/main.cpp
new file mode 100644
index 0000000..5ebdf6e
--- /dev/null
+++ b/libstats/socket/benchmark/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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 <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
new file mode 100644
index 0000000..b487c4d
--- /dev/null
+++ b/libstats/socket/benchmark/stats_event_benchmark.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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 "benchmark/benchmark.h"
+#include "stats_event.h"
+
+static struct stats_event* constructStatsEvent() {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+
+ // randomly sample atom size
+ for (int i = 0; i < rand() % 800; i++) {
+ stats_event_write_int32(event, i);
+ }
+
+ return event;
+}
+
+static void BM_stats_event_truncate_buffer(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ struct stats_event* event = constructStatsEvent();
+ stats_event_build(event);
+ stats_event_write(event);
+ stats_event_release(event);
+ }
+}
+
+BENCHMARK(BM_stats_event_truncate_buffer);
+
+static void BM_stats_event_full_buffer(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ struct stats_event* event = constructStatsEvent();
+ stats_event_truncate_buffer(event, false);
+ stats_event_build(event);
+ stats_event_write(event);
+ stats_event_release(event);
+ }
+}
+
+BENCHMARK(BM_stats_event_full_buffer);
diff --git a/libstats/socket/include/stats_buffer_writer.h b/libstats/socket/include/stats_buffer_writer.h
new file mode 100644
index 0000000..de4a5e2
--- /dev/null
+++ b/libstats/socket/include/stats_buffer_writer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __CPLUSPLUS
+void stats_log_close();
+int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId);
+#ifdef __cplusplus
+}
+#endif // __CPLUSPLUS
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 89cb420..080e957 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -76,7 +76,7 @@
#ifdef __cplusplus
extern "C" {
-#endif
+#endif // __CPLUSPLUS
struct stats_event;
@@ -85,7 +85,7 @@
// The build function can be called multiple times without error. If the event
// has been built before, this function is a no-op.
void stats_event_build(struct stats_event* event);
-void stats_event_write(struct stats_event* event);
+int stats_event_write(struct stats_event* event);
void stats_event_release(struct stats_event* event);
void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
@@ -95,14 +95,14 @@
void stats_event_write_float(struct stats_event* event, float value);
void stats_event_write_bool(struct stats_event* event, bool value);
-void stats_event_write_byte_array(struct stats_event* event, uint8_t* buf, size_t numBytes);
+void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* buf);
+void stats_event_write_string8(struct stats_event* event, const char* value);
// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, uint32_t* uids,
- const char** tags, uint8_t numNodes);
+void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes);
/* key_value_pair struct can be constructed as follows:
* struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
@@ -127,11 +127,38 @@
int32_t value);
uint32_t stats_event_get_atom_id(struct stats_event* event);
+// Size is an output parameter.
uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
uint32_t stats_event_get_errors(struct stats_event* event);
+// This table is used by StatsEventCompat to access the stats_event API.
+struct stats_event_api_table {
+ struct stats_event* (*obtain)(void);
+ void (*build)(struct stats_event*);
+ int (*write)(struct stats_event*);
+ void (*release)(struct stats_event*);
+ void (*set_atom_id)(struct stats_event*, uint32_t);
+ void (*write_int32)(struct stats_event*, int32_t);
+ void (*write_int64)(struct stats_event*, int64_t);
+ void (*write_float)(struct stats_event*, float);
+ void (*write_bool)(struct stats_event*, bool);
+ void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
+ void (*write_string8)(struct stats_event*, const char*);
+ void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
+ uint8_t);
+ void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
+ void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
+ void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
+ uint32_t (*get_atom_id)(struct stats_event*);
+ uint8_t* (*get_buffer)(struct stats_event*, size_t*);
+ uint32_t (*get_errors)(struct stats_event*);
+};
+
+// exposed for benchmarking only
+void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+
#ifdef __cplusplus
}
-#endif
+#endif // __CPLUSPLUS
#endif // ANDROID_STATS_LOG_STATS_EVENT_H
diff --git a/libstats/socket/include/stats_event_list.h b/libstats/socket/include/stats_event_list.h
index b7ada0c..7a26536 100644
--- a/libstats/socket/include/stats_event_list.h
+++ b/libstats/socket/include/stats_event_list.h
@@ -24,11 +24,9 @@
#endif
void reset_log_context(android_log_context ctx);
int write_to_logger(android_log_context context, log_id_t id);
-void note_log_drop(int error, int atom_tag);
+void note_log_drop(int error, int atomId);
void stats_log_close();
int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
-extern int (*write_to_statsd)(struct iovec* vec, size_t nr);
-
#ifdef __cplusplus
}
#endif
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
new file mode 100644
index 0000000..c5c591d
--- /dev/null
+++ b/libstats/socket/stats_buffer_writer.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 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 "include/stats_buffer_writer.h"
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include "statsd_writer.h"
+
+static const uint32_t kStatsEventTag = 1937006964;
+
+extern struct android_log_transport_write statsdLoggerWrite;
+
+static int __write_to_statsd_init(struct iovec* vec, size_t nr);
+static int (*__write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
+
+void note_log_drop(int error, int atomId) {
+ statsdLoggerWrite.noteDrop(error, atomId);
+}
+
+void stats_log_close() {
+ statsd_writer_init_lock();
+ __write_to_statsd = __write_to_statsd_init;
+ if (statsdLoggerWrite.close) {
+ (*statsdLoggerWrite.close)();
+ }
+ statsd_writer_init_unlock();
+}
+
+int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
+ int ret = 1;
+
+#ifdef __ANDROID__
+ bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
+#else
+ bool statsdEnabled = false;
+#endif
+
+ if (statsdEnabled) {
+ struct iovec vecs[2];
+ vecs[0].iov_base = (void*)&kStatsEventTag;
+ vecs[0].iov_len = sizeof(kStatsEventTag);
+ vecs[1].iov_base = buffer;
+ vecs[1].iov_len = size;
+
+ ret = __write_to_statsd(vecs, 2);
+
+ if (ret < 0) {
+ note_log_drop(ret, atomId);
+ }
+ }
+
+ return ret;
+}
+
+static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
+ int save_errno;
+ struct timespec ts;
+ size_t len, i;
+
+ for (len = i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+ if (!len) {
+ return -EINVAL;
+ }
+
+ save_errno = errno;
+#if defined(__ANDROID__)
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+#endif
+
+ int ret = (int)(*statsdLoggerWrite.write)(&ts, vec, nr);
+ errno = save_errno;
+ return ret;
+}
+
+static int __write_to_statsd_initialize_locked() {
+ if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
+ if (statsdLoggerWrite.close) {
+ (*statsdLoggerWrite.close)();
+ return -ENODEV;
+ }
+ }
+ return 1;
+}
+
+static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
+ int ret, save_errno = errno;
+
+ statsd_writer_init_lock();
+
+ if (__write_to_statsd == __write_to_statsd_init) {
+ ret = __write_to_statsd_initialize_locked();
+ if (ret < 0) {
+ statsd_writer_init_unlock();
+ errno = save_errno;
+ return ret;
+ }
+
+ __write_to_statsd = __write_to_stats_daemon;
+ }
+
+ statsd_writer_init_unlock();
+
+ ret = __write_to_statsd(vec, nr);
+ errno = save_errno;
+ return ret;
+}
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 35081dc..551b392 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -18,9 +18,8 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "include/stats_event_list.h"
+#include "stats_buffer_writer.h"
-#define STATS_EVENT_TAG 1937006964
#define LOGGER_ENTRY_MAX_PAYLOAD 4068
// Max payload size is 4 bytes less as 4 bytes are reserved for stats_eventTag.
// See android_util_Stats_Log.cpp
@@ -39,13 +38,13 @@
// The stats_event struct holds the serialized encoding of an event
// within a buf. Also includes other required fields.
struct stats_event {
- uint8_t buf[MAX_EVENT_PAYLOAD];
+ uint8_t* buf;
size_t lastFieldPos; // location of last field within the buf
size_t size; // number of valid bytes within buffer
uint32_t numElements;
uint32_t atomId;
uint32_t errors;
- uint32_t tag;
+ bool truncate;
bool built;
};
@@ -58,12 +57,11 @@
struct stats_event* stats_event_obtain() {
struct stats_event* event = malloc(sizeof(struct stats_event));
-
- memset(event->buf, 0, MAX_EVENT_PAYLOAD);
+ event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
event->buf[0] = OBJECT_TYPE;
event->atomId = 0;
event->errors = 0;
- event->tag = STATS_EVENT_TAG;
+ event->truncate = true; // truncate for both pulled and pushed atoms
event->built = false;
// place the timestamp
@@ -79,6 +77,7 @@
}
void stats_event_release(struct stats_event* event) {
+ free(event->buf);
free(event);
}
@@ -132,7 +131,7 @@
}
}
-static void append_byte_array(struct stats_event* event, uint8_t* buf, size_t size) {
+static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
if (!overflows(event, size)) {
memcpy(&event->buf[event->size], buf, size);
event->size += size;
@@ -185,7 +184,7 @@
append_bool(event, value);
}
-void stats_event_write_byte_array(struct stats_event* event, uint8_t* buf, size_t numBytes) {
+void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
if (event->errors) return;
start_field(event, BYTE_ARRAY_TYPE);
@@ -193,17 +192,17 @@
append_byte_array(event, buf, numBytes);
}
-// Buf is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* buf) {
+// Value is assumed to be encoded using UTF8
+void stats_event_write_string8(struct stats_event* event, const char* value) {
if (event->errors) return;
start_field(event, STRING_TYPE);
- append_string(event, buf);
+ append_string(event, value);
}
// Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, uint32_t* uids,
- const char** tags, uint8_t numNodes) {
+void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes) {
if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
if (event->errors) return;
@@ -297,6 +296,10 @@
return event->errors;
}
+void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
+ event->truncate = truncate;
+}
+
void stats_event_build(struct stats_event* event) {
if (event->built) return;
@@ -317,17 +320,35 @@
event->size = POS_FIRST_FIELD + sizeof(uint8_t) + sizeof(uint32_t);
}
+ // Truncate the buffer to the appropriate length in order to limit our
+ // memory usage.
+ if (event->truncate) event->buf = (uint8_t*)realloc(event->buf, event->size);
+
event->built = true;
}
-void stats_event_write(struct stats_event* event) {
+int stats_event_write(struct stats_event* event) {
stats_event_build(event);
-
- // Prepare iovecs for write to statsd.
- struct iovec vecs[2];
- vecs[0].iov_base = &event->tag;
- vecs[0].iov_len = sizeof(event->tag);
- vecs[1].iov_base = &event->buf;
- vecs[1].iov_len = event->size;
- write_to_statsd(vecs, 2);
+ return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
}
+
+struct stats_event_api_table table = {
+ stats_event_obtain,
+ stats_event_build,
+ stats_event_write,
+ stats_event_release,
+ stats_event_set_atom_id,
+ stats_event_write_int32,
+ stats_event_write_int64,
+ stats_event_write_float,
+ stats_event_write_bool,
+ stats_event_write_byte_array,
+ stats_event_write_string8,
+ stats_event_write_attribution_chain,
+ stats_event_write_key_value_pairs,
+ stats_event_add_bool_annotation,
+ stats_event_add_int32_annotation,
+ stats_event_get_atom_id,
+ stats_event_get_buffer,
+ stats_event_get_errors,
+};
diff --git a/libstats/socket/stats_event_list.c b/libstats/socket/stats_event_list.c
index ae12cbe..661a223 100644
--- a/libstats/socket/stats_event_list.c
+++ b/libstats/socket/stats_event_list.c
@@ -18,7 +18,7 @@
#include <string.h>
#include <sys/time.h>
-#include "statsd_writer.h"
+#include "stats_buffer_writer.h"
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
@@ -38,11 +38,6 @@
uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
} android_log_context_internal;
-extern struct android_log_transport_write statsdLoggerWrite;
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr);
-int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
-
// Similar to create_android_logger(), but instead of allocation a new buffer,
// this function resets the buffer for resuse.
void reset_log_context(android_log_context ctx) {
@@ -92,12 +87,7 @@
msg += sizeof(uint8_t) + sizeof(uint8_t);
}
- struct iovec vec[2];
- vec[0].iov_base = &context->tag;
- vec[0].iov_len = sizeof(context->tag);
- vec[1].iov_base = (void*)msg;
- vec[1].iov_len = len;
- return write_to_statsd(vec, 2);
+ return write_buffer_to_statsd((void*)msg, len, 0);
}
int write_to_logger(android_log_context ctx, log_id_t id) {
@@ -120,80 +110,6 @@
return retValue;
}
-void note_log_drop(int error, int tag) {
- statsdLoggerWrite.noteDrop(error, tag);
-}
-
-void stats_log_close() {
- statsd_writer_init_lock();
- write_to_statsd = __write_to_statsd_init;
- if (statsdLoggerWrite.close) {
- (*statsdLoggerWrite.close)();
- }
- statsd_writer_init_unlock();
-}
-
-/* log_init_lock assumed */
-static int __write_to_statsd_initialize_locked() {
- if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
- if (statsdLoggerWrite.close) {
- (*statsdLoggerWrite.close)();
- return -ENODEV;
- }
- }
- return 1;
-}
-
-static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
- int save_errno;
- struct timespec ts;
- size_t len, i;
-
- for (len = i = 0; i < nr; ++i) {
- len += vec[i].iov_len;
- }
- if (!len) {
- return -EINVAL;
- }
-
- save_errno = errno;
-#if defined(__ANDROID__)
- clock_gettime(CLOCK_REALTIME, &ts);
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
-#endif
-
- int ret = (int)(*statsdLoggerWrite.write)(&ts, vec, nr);
- errno = save_errno;
- return ret;
-}
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
- int ret, save_errno = errno;
-
- statsd_writer_init_lock();
-
- if (write_to_statsd == __write_to_statsd_init) {
- ret = __write_to_statsd_initialize_locked();
- if (ret < 0) {
- statsd_writer_init_unlock();
- errno = save_errno;
- return ret;
- }
-
- write_to_statsd = __write_to_stats_daemon;
- }
-
- statsd_writer_init_unlock();
-
- ret = write_to_statsd(vec, nr);
- errno = save_errno;
- return ret;
-}
-
static inline void copy4LE(uint8_t* buf, uint32_t val) {
buf[0] = val & 0xFF;
buf[1] = (val >> 8) & 0xFF;
diff --git a/libstats/socket_q/Android.bp b/libstats/socket_q/Android.bp
deleted file mode 100644
index 6c0c65c..0000000
--- a/libstats/socket_q/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// 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.
-//
-
-// ============================================================================
-// Native library to write stats log to statsd socket on Android Q and earlier.
-// This library is only meant to be used by libstatssocket_compat.
-// ============================================================================
-cc_library {
- name: "libstatssocket_q",
- srcs: [
- "stats_event_list.c",
- "statsd_writer.c",
- ],
- host_supported: true,
- cflags: [
- "-Wall",
- "-Werror",
- "-DLIBLOG_LOG_TAG=1006",
- "-DWRITE_TO_STATSD=1",
- "-DWRITE_TO_LOGD=0",
- ],
- export_include_dirs: ["include"],
- shared_libs: [
- "libcutils",
- "liblog",
- ],
-}