Merge "Add eSE AID."
diff --git a/.clang-format b/.clang-format
new file mode 120000
index 0000000..9b45e0a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+.clang-format-4
\ No newline at end of file
diff --git a/base/.clang-format b/.clang-format-2
similarity index 67%
copy from base/.clang-format
copy to .clang-format-2
index 2b83a1f..aab4665 100644
--- a/base/.clang-format
+++ b/.clang-format-2
@@ -1,7 +1,5 @@
BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
-
+ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
diff --git a/adb/.clang-format b/.clang-format-4
similarity index 72%
rename from adb/.clang-format
rename to .clang-format-4
index fc4eb1b..1497447 100644
--- a/adb/.clang-format
+++ b/.clang-format-4
@@ -1,7 +1,4 @@
BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
-
AccessModifierOffset: -2
ColumnLimit: 100
CommentPragmas: NOLINT:.*
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..c8dbf77
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,5 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
diff --git a/adb/.clang-format b/adb/.clang-format
new file mode 120000
index 0000000..1af4f51
--- /dev/null
+++ b/adb/.clang-format
@@ -0,0 +1 @@
+../.clang-format-4
\ No newline at end of file
diff --git a/adb/Android.mk b/adb/Android.mk
index b444afa..8a43e37 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -124,11 +124,12 @@
adbd_auth.cpp \
jdwp_service.cpp \
+LOCAL_C_INCLUDES := system/core/qemu_pipe/include
LOCAL_SANITIZE := $(adb_target_sanitize)
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libqemu_pipe libbase
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd_usb
@@ -144,6 +145,7 @@
LOCAL_SRC_FILES := \
$(LIBADB_SRC_FILES) \
adb_auth_host.cpp \
+ transport_mdns.cpp \
LOCAL_SRC_FILES_darwin := $(LIBADB_darwin_SRC_FILES)
LOCAL_SRC_FILES_linux := $(LIBADB_linux_SRC_FILES)
@@ -153,7 +155,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
@@ -175,7 +177,7 @@
shell_service_test.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto libusb
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto libusb libmdnssd
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
include $(BUILD_NATIVE_TEST)
@@ -223,7 +225,8 @@
libcrypto \
libcutils \
libdiagnose_usb \
- libgmock_host \
+ libmdnssd \
+ libgmock_host
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
@@ -291,6 +294,7 @@
libcrypto \
libdiagnose_usb \
liblog \
+ libmdnssd
# Don't use libcutils on Windows.
LOCAL_STATIC_LIBRARIES_darwin := libcutils
@@ -324,6 +328,7 @@
LOCAL_SRC_FILES := \
daemon/main.cpp \
+ daemon/mdns.cpp \
services.cpp \
file_sync_service.cpp \
framebuffer_service.cpp \
@@ -357,6 +362,7 @@
LOCAL_STATIC_LIBRARIES := \
libadbd \
libbase \
+ libqemu_pipe \
libbootloader_message \
libfs_mgr \
libfec \
@@ -370,6 +376,7 @@
libcrypto_utils \
libcrypto \
libminijail \
+ libmdnssd \
libdebuggerd_handler \
include $(BUILD_EXECUTABLE)
diff --git a/adb/NOTICE b/adb/NOTICE
index 9ffcc08..ff47c95 100644
--- a/adb/NOTICE
+++ b/adb/NOTICE
@@ -189,3 +189,63 @@
END OF TERMS AND CONDITIONS
+------------------------------------------------------------
+libwinpthread license:
+------------------------------------------------------------
+Copyright (c) 2011 mingw-w64 project
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+/*
+ * Parts of this library are derived by:
+ *
+ * Posix Threads library for Microsoft Windows
+ *
+ * Use at own risk, there is no implied warranty to this code.
+ * It uses undocumented features of Microsoft Windows that can change
+ * at any time in the future.
+ *
+ * (C) 2010 Lockless Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Lockless Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ece143c..577e9b9 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1129,6 +1129,18 @@
return 0;
}
+#if ADB_HOST
+ if (!strcmp(service, "host-features")) {
+ FeatureSet features = supported_features();
+ // Abuse features to report libusb status.
+ if (should_use_libusb()) {
+ features.insert(kFeatureLibusb);
+ }
+ SendOkay(reply_fd, FeatureSetToString(features));
+ return 0;
+ }
+#endif
+
// remove TCP transport
if (!strncmp(service, "disconnect:", 11)) {
const std::string address(service + 11);
diff --git a/adb/adb.h b/adb/adb.h
index 6a38f18..aea5fb8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -34,6 +34,8 @@
constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024;
constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
+constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
+
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
#define A_OPEN 0x4e45504f
@@ -52,7 +54,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 38
+#define ADB_SERVER_VERSION 39
class atransport;
diff --git a/bootstat/histogram_logger.h b/adb/adb_mdns.h
similarity index 70%
copy from bootstat/histogram_logger.h
copy to adb/adb_mdns.h
index 60c7776..2e544d7 100644
--- a/bootstat/histogram_logger.h
+++ b/adb/adb_mdns.h
@@ -14,13 +14,9 @@
* limitations under the License.
*/
-#include <cstdint>
-#include <string>
+#ifndef _ADB_MDNS_H_
+#define _ADB_MDNS_H_
-namespace bootstat {
+const char* kADBServiceType = "_adb._tcp";
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+#endif
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 7afa616..7058acb 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -19,16 +19,15 @@
#include "adb_utils.h"
#include "adb_unique_fd.h"
-#include <libgen.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
-#include <mutex>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
@@ -100,52 +99,6 @@
return result;
}
-std::string adb_basename(const std::string& path) {
- static std::mutex& basename_lock = *new std::mutex();
-
- // Copy path because basename may modify the string passed in.
- std::string result(path);
-
- // Use lock because basename() may write to a process global and return a
- // pointer to that. Note that this locking strategy only works if all other
- // callers to basename in the process also grab this same lock.
- std::lock_guard<std::mutex> lock(basename_lock);
-
- // Note that if std::string uses copy-on-write strings, &str[0] will cause
- // the copy to be made, so there is no chance of us accidentally writing to
- // the storage for 'path'.
- char* name = basename(&result[0]);
-
- // In case dirname returned a pointer to a process global, copy that string
- // before leaving the lock.
- result.assign(name);
-
- return result;
-}
-
-std::string adb_dirname(const std::string& path) {
- static std::mutex& dirname_lock = *new std::mutex();
-
- // Copy path because dirname may modify the string passed in.
- std::string result(path);
-
- // Use lock because dirname() may write to a process global and return a
- // pointer to that. Note that this locking strategy only works if all other
- // callers to dirname in the process also grab this same lock.
- std::lock_guard<std::mutex> lock(dirname_lock);
-
- // Note that if std::string uses copy-on-write strings, &str[0] will cause
- // the copy to be made, so there is no chance of us accidentally writing to
- // the storage for 'path'.
- char* parent = dirname(&result[0]);
-
- // In case dirname returned a pointer to a process global, copy that string
- // before leaving the lock.
- result.assign(parent);
-
- return result;
-}
-
// Given a relative or absolute filepath, create the directory hierarchy
// as needed. Returns true if the hierarchy is/was setup.
bool mkdirs(const std::string& path) {
@@ -171,7 +124,7 @@
return true;
}
- const std::string parent(adb_dirname(path));
+ const std::string parent(android::base::Dirname(path));
// If dirname returned the same path as what we passed in, don't go recursive.
// This can happen on Windows when walking up the directory hierarchy and not
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 2b59034..e0ad103 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -28,11 +28,6 @@
bool getcwd(std::string* cwd);
bool directory_exists(const std::string& path);
-// Like the regular basename and dirname, but thread-safe on all
-// platforms and capable of correctly handling exotic Windows paths.
-std::string adb_basename(const std::string& path);
-std::string adb_dirname(const std::string& path);
-
// Return the user's home directory.
std::string adb_get_homedir_path();
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 4cac485..a3bc445 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -109,18 +109,6 @@
ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
}
-TEST(adb_utils, adb_basename) {
- EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
- EXPECT_EQ("sh", adb_basename("sh"));
- EXPECT_EQ("sh", adb_basename("/system/bin/sh/"));
-}
-
-TEST(adb_utils, adb_dirname) {
- EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh"));
- EXPECT_EQ(".", adb_dirname("sh"));
- EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
-}
-
void test_mkdirs(const std::string& basepath) {
// Test creating a directory hierarchy.
ASSERT_TRUE(mkdirs(basepath));
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index b7e76a6..a5c312b 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/strings.h>
#include "sysdeps.h"
@@ -113,14 +114,14 @@
private:
void SetLineMessage(const std::string& action) {
- line_message_ = action + " " + adb_basename(dest_file_);
+ line_message_ = action + " " + android::base::Basename(dest_file_);
}
void SetSrcFile(const std::string path) {
src_file_ = path;
if (!dest_dir_.empty()) {
// Only uses device-provided name when user passed a directory.
- dest_file_ = adb_basename(path);
+ dest_file_ = android::base::Basename(path);
SetLineMessage("generating");
}
}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 97a54fd..606203c 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -117,6 +117,8 @@
init_transport_registration();
+ init_mdns_transport_discovery();
+
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index f02dccf..bfc8e16 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -17,11 +17,6 @@
#include <android-base/logging.h>
#include "usb.h"
-static bool should_use_libusb() {
- static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
- return enable;
-}
-
void usb_init() {
if (should_use_libusb()) {
LOG(DEBUG) << "using libusb backend";
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 3b2df2e..3de7be6 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1929,8 +1929,7 @@
else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
fprintf(stdout, "%s", adb_version().c_str());
return 0;
- }
- else if (!strcmp(argv[0], "features")) {
+ } else if (!strcmp(argv[0], "features")) {
// Only list the features common to both the adb client and the device.
FeatureSet features;
std::string error;
@@ -1945,6 +1944,8 @@
}
}
return 0;
+ } else if (!strcmp(argv[0], "host-features")) {
+ return adb_query_command("host:host-features");
} else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) {
return adb_query_command("host:reconnect");
@@ -2114,7 +2115,8 @@
std::string cmd = android::base::StringPrintf(
"%s install-write -S %" PRIu64 " %d %d_%s -",
- install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
+ install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i,
+ android::base::Basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
@@ -2232,7 +2234,7 @@
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
std::string apk_dest = android::base::StringPrintf(
- where, adb_basename(argv[last_apk]).c_str());
+ where, android::base::Basename(argv[last_apk]).c_str());
if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
result = pm_command(transport, serial, argc, argv);
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 6382b67..7da94ce 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -45,6 +45,8 @@
#include "adb_utils.h"
#include "transport.h"
+#include "mdns.h"
+
static const char* root_seclabel = nullptr;
static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
@@ -140,6 +142,11 @@
}
}
+static void setup_port(int port) {
+ local_init(port);
+ setup_mdns(port);
+}
+
int adbd_main(int server_port) {
umask(0);
@@ -188,10 +195,10 @@
if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
D("using port=%d", port);
// Listen on TCP port specified by service.adb.tcp.port property.
- local_init(port);
+ setup_port(port);
} else if (!is_usb) {
// Listen on default port.
- local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
}
D("adbd_main(): pre init_jdwp()");
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
new file mode 100644
index 0000000..7811143
--- /dev/null
+++ b/adb/daemon/mdns.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#include "adb_mdns.h"
+#include "sysdeps.h"
+
+#include <chrono>
+#include <dns_sd.h>
+#include <endian.h>
+#include <mutex>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+using namespace std::chrono_literals;
+
+static std::mutex& mdns_lock = *new std::mutex();
+static int port;
+static DNSServiceRef mdns_ref;
+static bool mdns_registered = false;
+
+static void start_mdns() {
+ if (android::base::GetProperty("init.svc.mdnsd", "") == "running") {
+ return;
+ }
+
+ android::base::SetProperty("ctl.start", "mdnsd");
+
+ if (! android::base::WaitForProperty("init.svc.mdnsd", "running", 5s)) {
+ LOG(ERROR) << "Could not start mdnsd.";
+ }
+}
+
+static void mdns_callback(DNSServiceRef /*ref*/,
+ DNSServiceFlags /*flags*/,
+ DNSServiceErrorType errorCode,
+ const char* /*name*/,
+ const char* /*regtype*/,
+ const char* /*domain*/,
+ void* /*context*/) {
+ if (errorCode != kDNSServiceErr_NoError) {
+ LOG(ERROR) << "Encountered mDNS registration error ("
+ << errorCode << ").";
+ }
+}
+
+static void setup_mdns_thread(void* /* unused */) {
+ start_mdns();
+ std::lock_guard<std::mutex> lock(mdns_lock);
+
+ std::string hostname = "adb-";
+ hostname += android::base::GetProperty("ro.serialno", "unidentified");
+
+ auto error = DNSServiceRegister(&mdns_ref, 0, 0, hostname.c_str(),
+ kADBServiceType, nullptr, nullptr,
+ htobe16((uint16_t)port), 0, nullptr,
+ mdns_callback, nullptr);
+
+ if (error != kDNSServiceErr_NoError) {
+ LOG(ERROR) << "Could not register mDNS service (" << error << ").";
+ mdns_registered = false;
+ }
+
+ mdns_registered = true;
+}
+
+static void teardown_mdns() {
+ std::lock_guard<std::mutex> lock(mdns_lock);
+
+ if (mdns_registered) {
+ DNSServiceRefDeallocate(mdns_ref);
+ }
+}
+
+void setup_mdns(int port_in) {
+ port = port_in;
+ adb_thread_create(setup_mdns_thread, nullptr, nullptr);
+
+ // TODO: Make this more robust against a hard kill.
+ atexit(teardown_mdns);
+}
diff --git a/bootstat/histogram_logger.h b/adb/daemon/mdns.h
similarity index 70%
copy from bootstat/histogram_logger.h
copy to adb/daemon/mdns.h
index 60c7776..4c6b1ca 100644
--- a/bootstat/histogram_logger.h
+++ b/adb/daemon/mdns.h
@@ -14,13 +14,9 @@
* limitations under the License.
*/
-#include <cstdint>
-#include <string>
+#ifndef _DAEMON_MDNS_H_
+#define _DAEMON_MDNS_H_
-namespace bootstat {
+void setup_mdns(int port);
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+#endif // _DAEMON_MDNS_H_
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a35c210..92e9039 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -49,16 +49,23 @@
#define MAX_PACKET_SIZE_HS 512
#define MAX_PACKET_SIZE_SS 1024
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
+// Kernels before 3.3 have a 16KiB transfer limit That limit was replaced
+// with a 16MiB global limit in 3.3, but each URB submitted required a
+// contiguous kernel allocation, so you would get ENOMEM if you tried to
+// send something larger than the biggest available contiguous kernel
+// memory region. Large contiguous allocations could be unreliable
+// on a device kernel that has been running for a while fragmenting its
+// memory so we start with a larger allocation, and shrink the amount if
+// necessary.
+#define USB_FFS_BULK_SIZE 16384
#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)
+#define FUNCTIONFS_ENDPOINT_ALLOC _IOR('g', 231, __u32)
+
+static constexpr size_t ENDPOINT_ALLOC_RETRIES = 2;
+
static int dummy_fd = -1;
struct func_desc {
@@ -173,6 +180,7 @@
.source_comp = {
.bLength = sizeof(ss_descriptors.source_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 4,
},
.sink = {
.bLength = sizeof(ss_descriptors.sink),
@@ -184,6 +192,7 @@
.sink_comp = {
.bLength = sizeof(ss_descriptors.sink_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 4,
},
};
@@ -229,6 +238,7 @@
ssize_t ret;
struct desc_v1 v1_descriptor;
struct desc_v2 v2_descriptor;
+ size_t retries = 0;
v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
@@ -273,6 +283,8 @@
D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
goto err;
}
+ //Signal only when writing the descriptors to ffs
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
}
h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR);
@@ -287,6 +299,29 @@
goto err;
}
+ h->max_rw = MAX_PAYLOAD;
+ while (h->max_rw >= USB_FFS_BULK_SIZE && retries < ENDPOINT_ALLOC_RETRIES) {
+ int ret_in = ioctl(h->bulk_in, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
+ int errno_in = errno;
+ int ret_out = ioctl(h->bulk_out, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
+ int errno_out = errno;
+
+ if (ret_in || ret_out) {
+ if (errno_in == ENODEV || errno_out == ENODEV) {
+ std::this_thread::sleep_for(100ms);
+ retries += 1;
+ continue;
+ }
+ h->max_rw /= 2;
+ } else {
+ return true;
+ }
+ }
+
+ D("[ adb: cannot call endpoint alloc: errno=%d ]", errno);
+ // Kernel pre-allocation could have failed for recoverable reasons.
+ // Continue running with a safe max rw size.
+ h->max_rw = USB_FFS_BULK_SIZE;
return true;
err:
@@ -325,7 +360,6 @@
}
std::this_thread::sleep_for(1s);
}
- android::base::SetProperty("sys.usb.ffs.ready", "1");
D("[ usb_thread - registering device ]");
register_usb_transport(usb, 0, 0, 1);
@@ -340,7 +374,7 @@
const char* buf = static_cast<const char*>(data);
while (len > 0) {
- int write_len = std::min(USB_FFS_MAX_WRITE, len);
+ int write_len = std::min(h->max_rw, len);
int n = adb_write(h->bulk_in, buf, write_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
@@ -359,7 +393,7 @@
char* buf = static_cast<char*>(data);
while (len > 0) {
- int read_len = std::min(USB_FFS_MAX_READ, len);
+ int read_len = std::min(h->max_rw, len);
int n = adb_read(h->bulk_out, buf, read_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
diff --git a/adb/daemon/usb.h b/adb/daemon/usb.h
index 1d85405..55b5995 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/usb.h
@@ -20,13 +20,6 @@
#include <condition_variable>
#include <mutex>
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
-
struct usb_handle {
usb_handle() : kicked(false) {
}
@@ -45,6 +38,8 @@
int control = -1;
int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
int bulk_in = -1; /* "in" from the host's perspective => sink for adbd */
+
+ int max_rw;
};
bool init_functionfs(struct usb_handle* h);
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 271943d..22bd2f2 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -844,7 +844,8 @@
// TODO(b/25566053): Make pushing empty directories work.
// TODO(b/25457350): We don't preserve permissions on directories.
sc.Warning("skipping empty directory '%s'", lpath.c_str());
- copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
+ copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
+ android::base::Basename(lpath), S_IFDIR);
ci.skip = true;
file_list->push_back(ci);
return true;
@@ -977,7 +978,7 @@
if (dst_dir.back() != '/') {
dst_dir.push_back('/');
}
- dst_dir.append(adb_basename(src_path));
+ dst_dir.append(android::base::Basename(src_path));
}
success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(), false, false);
@@ -995,7 +996,7 @@
if (path_holder.back() != '/') {
path_holder.push_back('/');
}
- path_holder += adb_basename(src_path);
+ path_holder += android::base::Basename(src_path);
dst_path = path_holder.c_str();
}
@@ -1015,7 +1016,8 @@
std::vector<copyinfo> linklist;
// Add an entry for the current directory to ensure it gets created before pulling its contents.
- copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
+ copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
+ android::base::Basename(lpath), S_IFDIR);
file_list->push_back(ci);
// Put the files/dirs in rpath on the lists.
@@ -1149,7 +1151,7 @@
if (srcs.size() == 1 && errno == ENOENT) {
// However, its parent must exist.
struct stat parent_st;
- if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
+ if (stat(android::base::Dirname(dst).c_str(), &parent_st) == -1) {
sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
return false;
}
@@ -1204,7 +1206,7 @@
if (!adb_is_separator(dst_dir.back())) {
dst_dir.push_back(OS_PATH_SEPARATOR);
}
- dst_dir.append(adb_basename(src_path));
+ dst_dir.append(android::base::Basename(src_path));
}
success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
@@ -1220,7 +1222,7 @@
// really want to copy to local_dir + OS_PATH_SEPARATOR +
// basename(remote).
path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
- adb_basename(src_path).c_str());
+ android::base::Basename(src_path).c_str());
dst_path = path_holder.c_str();
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index e667bf8..2acf661 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <utime.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <private/android_filesystem_config.h>
@@ -206,7 +207,7 @@
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
if (fd < 0 && errno == ENOENT) {
- if (!secure_mkdirs(adb_dirname(path))) {
+ if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
goto fail;
}
@@ -333,7 +334,7 @@
ret = symlink(&buffer[0], path.c_str());
if (ret && errno == ENOENT) {
- if (!secure_mkdirs(adb_dirname(path))) {
+ if (!secure_mkdirs(android::base::Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
return false;
}
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 3135aa4..9589d88 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -571,7 +571,8 @@
remove_socket(s);
auto pred = [s](const auto& tracker) { return tracker.get() == s; };
- std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred);
+ _jdwp_trackers.erase(std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred),
+ _jdwp_trackers.end());
}
static void jdwp_tracker_ready(asocket* s) {
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 5ca73cc..32ed28f 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -54,12 +54,10 @@
// Returns the device used to mount a directory in the fstab.
static std::string find_fstab_mount(const char* dir) {
- std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
- struct fstab* fstab = fs_mgr_read_fstab(fstab_filename.c_str());
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, dir);
- std::string dev = rec ? std::string(rec->blk_device) : "";
- fs_mgr_free_fstab(fstab);
- return dev;
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), dir);
+ return rec ? rec->blk_device : "";
}
// The proc entry for / is full of lies, so check fstab instead.
diff --git a/adb/services.cpp b/adb/services.cpp
index df1b134..47f0a03 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -242,6 +242,15 @@
}
D("socketpair: (%d,%d)", s[0], s[1]);
+#if !ADB_HOST
+ if (func == &file_sync_service) {
+ // Set file sync service socket to maximum size
+ int max_buf = LINUX_MAX_SOCKET_SIZE;
+ adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+ adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+ }
+#endif // !ADB_HOST
+
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if (sti == nullptr) {
fatal("cannot allocate stinfo");
@@ -368,45 +377,6 @@
D("wait_for_state is done");
}
-static void connect_device(const std::string& address, std::string* response) {
- if (address.empty()) {
- *response = "empty address";
- return;
- }
-
- std::string serial;
- std::string host;
- int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
- if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
- return;
- }
-
- std::string error;
- int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error);
- if (fd == -1) {
- *response = android::base::StringPrintf("unable to connect to %s: %s",
- serial.c_str(), error.c_str());
- return;
- }
-
- D("client: connected %s remote on fd %d", serial.c_str(), fd);
- close_on_exec(fd);
- disable_tcp_nagle(fd);
-
- // Send a TCP keepalive ping to the device every second so we can detect disconnects.
- if (!set_tcp_keepalive(fd, 1)) {
- D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
- }
-
- int ret = register_socket_transport(fd, serial.c_str(), port, 0);
- if (ret < 0) {
- adb_close(fd);
- *response = android::base::StringPrintf("already connected to %s", serial.c_str());
- } else {
- *response = android::base::StringPrintf("connected to %s", serial.c_str());
- }
-}
-
void connect_emulator(const std::string& port_spec, std::string* response) {
std::vector<std::string> pieces = android::base::Split(port_spec, ",");
if (pieces.size() != 2) {
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index f9e028b..76b156d 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -108,11 +108,10 @@
return;
}
- std::string fstab_filename = "/fstab." + android::base::GetProperty("ro.hardware", "");
-
- fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+ // read all fstab entries at once from all sources
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename.c_str());
+ WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
return;
}
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 4975fab..d4f334b 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -320,6 +320,10 @@
parent_error_sfd.reset(-1);
close_on_exec(child_error_sfd);
+ // adbd sets SIGPIPE to SIG_IGN to get EPIPE instead, and Linux propagates that to child
+ // processes, so we need to manually reset back to SIG_DFL here (http://b/35209888).
+ signal(SIGPIPE, SIG_DFL);
+
if (command_.empty()) {
execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
} else {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 654072c..f195b4e 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -197,6 +197,7 @@
extern int adb_lseek(int fd, int pos, int where);
extern int adb_shutdown(int fd);
extern int adb_close(int fd);
+extern int adb_register_socket(SOCKET s);
// See the comments for the !defined(_WIN32) version of unix_close().
static __inline__ int unix_close(int fd)
@@ -523,6 +524,12 @@
#undef close
#define close ____xxx_close
+// On Windows, ADB has an indirection layer for file descriptors. If we get a
+// Win32 SOCKET object from an external library, we have to map it in to that
+// indirection layer, which this does.
+__inline__ int adb_register_socket(int s) {
+ return s;
+}
static __inline__ int adb_read(int fd, void* buf, size_t len)
{
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a4b5e69..f997e6b 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -126,10 +126,7 @@
SOCKET socket;
} u;
- int mask;
-
char name[32];
-
} FHRec;
#define fh_handle u.handle
@@ -577,7 +574,6 @@
static void _fh_socket_init(FH f) {
f->fh_socket = INVALID_SOCKET;
- f->mask = 0;
}
static int _fh_socket_close( FH f ) {
@@ -598,7 +594,6 @@
}
f->fh_socket = INVALID_SOCKET;
}
- f->mask = 0;
return 0;
}
@@ -913,6 +908,12 @@
return fd;
}
+int adb_register_socket(SOCKET s) {
+ FH f = _fh_alloc( &_fh_socket_class );
+ f->fh_socket = s;
+ return _fh_to_int(f);
+}
+
#undef accept
int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{
@@ -1113,18 +1114,22 @@
if (!fh || !fh->used) {
errno = EBADF;
+ D("Setting nonblocking on bad file descriptor %d", fd);
return false;
}
if (fh->clazz == &_fh_socket_class) {
u_long x = !block;
if (ioctlsocket(fh->u.socket, FIONBIO, &x) != 0) {
- _socket_set_errno(WSAGetLastError());
+ int error = WSAGetLastError();
+ _socket_set_errno(error);
+ D("Setting %d nonblocking failed (%d)", fd, error);
return false;
}
return true;
} else {
errno = ENOTSOCK;
+ D("Setting nonblocking on non-socket %d", fd);
return false;
}
}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 60f3b5c..c951f5b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -51,6 +51,7 @@
const char* const kFeatureShell2 = "shell_v2";
const char* const kFeatureCmd = "cmd";
const char* const kFeatureStat2 = "stat_v2";
+const char* const kFeatureLibusb = "libusb";
static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
diff --git a/adb/transport.h b/adb/transport.h
index 3306388..4d97fc7 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -47,6 +47,8 @@
// The 'cmd' command is available
extern const char* const kFeatureCmd;
extern const char* const kFeatureStat2;
+// The server is running with libusb enabled.
+extern const char* const kFeatureLibusb;
class atransport {
public:
@@ -185,6 +187,7 @@
void update_transports(void);
void init_transport_registration(void);
+void init_mdns_transport_discovery(void);
std::string list_transports(bool long_listing);
atransport* find_transport(const char* serial);
void kick_all_tcp_devices();
@@ -192,6 +195,9 @@
void register_usb_transport(usb_handle* h, const char* serial,
const char* devpath, unsigned writeable);
+/* Connect to a network address and register it as a device */
+void connect_device(const std::string& address, std::string* response);
+
/* cause new transports to be init'd and added to the list */
int register_socket_transport(int s, const char* serial, int port, int local);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index c17f869..12b98ba 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -30,6 +30,7 @@
#include <thread>
#include <vector>
+#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
@@ -101,6 +102,46 @@
return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
}
+void connect_device(const std::string& address, std::string* response) {
+ if (address.empty()) {
+ *response = "empty address";
+ return;
+ }
+
+ std::string serial;
+ std::string host;
+ int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+ if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
+ return;
+ }
+
+ std::string error;
+ int fd = network_connect(host.c_str(), port, SOCK_STREAM, 10, &error);
+ if (fd == -1) {
+ *response = android::base::StringPrintf("unable to connect to %s: %s",
+ serial.c_str(), error.c_str());
+ return;
+ }
+
+ D("client: connected %s remote on fd %d", serial.c_str(), fd);
+ close_on_exec(fd);
+ disable_tcp_nagle(fd);
+
+ // Send a TCP keepalive ping to the device every second so we can detect disconnects.
+ if (!set_tcp_keepalive(fd, 1)) {
+ D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
+ }
+
+ int ret = register_socket_transport(fd, serial.c_str(), port, 0);
+ if (ret < 0) {
+ adb_close(fd);
+ *response = android::base::StringPrintf("already connected to %s", serial.c_str());
+ } else {
+ *response = android::base::StringPrintf("connected to %s", serial.c_str());
+ }
+}
+
+
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) {
int fd = -1;
@@ -248,7 +289,7 @@
#define open adb_open
#define read adb_read
#define write adb_write
-#include <system/qemu_pipe.h>
+#include <qemu_pipe.h>
#undef open
#undef read
#undef write
diff --git a/adb/transport_mdns.cpp b/adb/transport_mdns.cpp
new file mode 100644
index 0000000..e49b1c6
--- /dev/null
+++ b/adb/transport_mdns.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRANSPORT
+
+#include "transport.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include <android-base/stringprintf.h>
+#include <dns_sd.h>
+
+#include "adb_mdns.h"
+#include "adb_trace.h"
+#include "fdevent.h"
+#include "sysdeps.h"
+
+static DNSServiceRef service_ref;
+static fdevent service_ref_fde;
+
+// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
+// directly so that the socket is put through the appropriate compatibility
+// layers to work with the rest of ADB's internal APIs.
+static inline int adb_DNSServiceRefSockFD(DNSServiceRef ref) {
+ return adb_register_socket(DNSServiceRefSockFD(ref));
+}
+#define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD
+
+static void DNSSD_API register_service_ip(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* hostname,
+ const sockaddr* address,
+ uint32_t ttl,
+ void* context);
+
+static void pump_service_ref(int /*fd*/, unsigned ev, void* data) {
+ DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data);
+
+ if (ev & FDE_READ)
+ DNSServiceProcessResult(*ref);
+}
+
+class AsyncServiceRef {
+ public:
+ bool Initialized() {
+ return initialized_;
+ }
+
+ virtual ~AsyncServiceRef() {
+ if (! initialized_) {
+ return;
+ }
+
+ DNSServiceRefDeallocate(sdRef_);
+ fdevent_remove(&fde_);
+ }
+
+ protected:
+ DNSServiceRef sdRef_;
+
+ void Initialize() {
+ fdevent_install(&fde_, adb_DNSServiceRefSockFD(sdRef_),
+ pump_service_ref, &sdRef_);
+ fdevent_set(&fde_, FDE_READ);
+ initialized_ = true;
+ }
+
+ private:
+ bool initialized_;
+ fdevent fde_;
+};
+
+class ResolvedService : public AsyncServiceRef {
+ public:
+ virtual ~ResolvedService() = default;
+
+ ResolvedService(std::string name, uint32_t interfaceIndex,
+ const char* hosttarget, uint16_t port) :
+ name_(name),
+ port_(port) {
+
+ /* TODO: We should be able to get IPv6 support by adding
+ * kDNSServiceProtocol_IPv6 to the flags below. However, when we do
+ * this, we get served link-local addresses that are usually useless to
+ * connect to. What's more, we seem to /only/ get those and nothing else.
+ * If we want IPv6 in the future we'll have to figure out why.
+ */
+ DNSServiceErrorType ret =
+ DNSServiceGetAddrInfo(
+ &sdRef_, 0, interfaceIndex,
+ kDNSServiceProtocol_IPv4, hosttarget,
+ register_service_ip, reinterpret_cast<void*>(this));
+
+ if (ret != kDNSServiceErr_NoError) {
+ D("Got %d from DNSServiceGetAddrInfo.", ret);
+ } else {
+ Initialize();
+ }
+ }
+
+ void Connect(const sockaddr* address) {
+ char ip_addr[INET6_ADDRSTRLEN];
+ const void* ip_addr_data;
+ const char* addr_format;
+
+ if (address->sa_family == AF_INET) {
+ ip_addr_data =
+ &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
+ addr_format = "%s:%hu";
+ } else if (address->sa_family == AF_INET6) {
+ ip_addr_data =
+ &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
+ addr_format = "[%s]:%hu";
+ } else { // Should be impossible
+ D("mDNS resolved non-IP address.");
+ return;
+ }
+
+ // Winsock version requires the const cast Because Microsoft.
+ if (!inet_ntop(address->sa_family, const_cast<void*>(ip_addr_data),
+ ip_addr, INET6_ADDRSTRLEN)) {
+ D("Could not convert IP address to string.");
+ return;
+ }
+
+ std::string response;
+ connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
+ &response);
+ D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
+ response.c_str());
+ }
+
+ private:
+ std::string name_;
+ const uint16_t port_;
+};
+
+static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
+ DNSServiceFlags /*flags*/,
+ uint32_t /*interfaceIndex*/,
+ DNSServiceErrorType /*errorCode*/,
+ const char* /*hostname*/,
+ const sockaddr* address,
+ uint32_t /*ttl*/,
+ void* context) {
+ D("Got IP for service.");
+ std::unique_ptr<ResolvedService> data(
+ reinterpret_cast<ResolvedService*>(context));
+ data->Connect(address);
+}
+
+static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* fullname,
+ const char* hosttarget,
+ uint16_t port,
+ uint16_t txtLen,
+ const unsigned char* txtRecord,
+ void* context);
+
+class DiscoveredService : public AsyncServiceRef {
+ public:
+ DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
+ const char* regtype, const char* domain)
+ : serviceName_(serviceName) {
+
+ DNSServiceErrorType ret =
+ DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
+ domain, register_resolved_mdns_service,
+ reinterpret_cast<void*>(this));
+
+ if (ret != kDNSServiceErr_NoError) {
+ D("Got %d from DNSServiceResolve.", ret);
+ } else {
+ Initialize();
+ }
+ }
+
+ const char* ServiceName() {
+ return serviceName_.c_str();
+ }
+
+ private:
+ std::string serviceName_;
+};
+
+static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* fullname,
+ const char* hosttarget,
+ uint16_t port,
+ uint16_t /*txtLen*/,
+ const unsigned char* /*txtRecord*/,
+ void* context) {
+ D("Resolved a service.");
+ std::unique_ptr<DiscoveredService> discovered(
+ reinterpret_cast<DiscoveredService*>(context));
+
+ if (errorCode != kDNSServiceErr_NoError) {
+ D("Got error %d resolving service.", errorCode);
+ return;
+ }
+
+
+ auto resolved =
+ new ResolvedService(discovered->ServiceName(),
+ interfaceIndex, hosttarget, ntohs(port));
+
+ if (! resolved->Initialized()) {
+ delete resolved;
+ }
+
+ if (flags) { /* Only ever equals MoreComing or 0 */
+ discovered.release();
+ }
+}
+
+static void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* serviceName,
+ const char* regtype,
+ const char* domain,
+ void* /*context*/) {
+ D("Registering a transport.");
+ if (errorCode != kDNSServiceErr_NoError) {
+ D("Got error %d during mDNS browse.", errorCode);
+ DNSServiceRefDeallocate(sdRef);
+ fdevent_remove(&service_ref_fde);
+ return;
+ }
+
+ auto discovered = new DiscoveredService(interfaceIndex, serviceName,
+ regtype, domain);
+
+ if (! discovered->Initialized()) {
+ delete discovered;
+ }
+}
+
+void init_mdns_transport_discovery(void) {
+ DNSServiceErrorType errorCode =
+ DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
+ register_mdns_transport, nullptr);
+
+ if (errorCode != kDNSServiceErr_NoError) {
+ D("Got %d initiating mDNS browse.", errorCode);
+ return;
+ }
+
+ fdevent_install(&service_ref_fde,
+ adb_DNSServiceRefSockFD(service_ref),
+ pump_service_ref,
+ &service_ref);
+ fdevent_set(&service_ref_fde, FDE_READ);
+}
diff --git a/bootstat/histogram_logger.h b/adb/transport_mdns_unsupported.cpp
similarity index 70%
copy from bootstat/histogram_logger.h
copy to adb/transport_mdns_unsupported.cpp
index 60c7776..387d341 100644
--- a/bootstat/histogram_logger.h
+++ b/adb/transport_mdns_unsupported.cpp
@@ -14,13 +14,5 @@
* limitations under the License.
*/
-#include <cstdint>
-#include <string>
-
-namespace bootstat {
-
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+/* For when mDNS discovery is unsupported */
+void init_mdns_transport_discovery(void) {}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3d6cc99..516b4f2 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -97,3 +97,12 @@
{
return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
}
+
+bool should_use_libusb() {
+#if defined(_WIN32) || !ADB_HOST
+ return false;
+#else
+ static bool disable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "0") == 0;
+ return !disable;
+#endif
+}
diff --git a/adb/usb.h b/adb/usb.h
index 879bacc..ba70de4 100644
--- a/adb/usb.h
+++ b/adb/usb.h
@@ -55,3 +55,5 @@
// USB device detection.
int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
+
+bool should_use_libusb();
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
index 1a81a49..c276c53 100644
--- a/adf/libadf/Android.bp
+++ b/adf/libadf/Android.bp
@@ -14,7 +14,7 @@
cc_library_static {
name: "libadf",
- srcs: ["adf.c"],
+ srcs: ["adf.cpp"],
cflags: ["-Werror"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.cpp
similarity index 68%
rename from adf/libadf/adf.c
rename to adf/libadf/adf.cpp
index c4d6681..60d8ef0 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.cpp
@@ -23,6 +23,10 @@
#include <string.h>
#include <unistd.h>
+#include <algorithm>
+#include <memory>
+#include <vector>
+
#include <linux/limits.h>
#include <sys/ioctl.h>
@@ -31,52 +35,44 @@
#define ADF_BASE_PATH "/dev/"
-static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids)
+static ssize_t adf_id_vector_to_array(const std::vector<adf_id_t> &in,
+ adf_id_t **out)
{
- DIR *dir;
- struct dirent *dirent;
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto size = sizeof(in[0]) * in.size();
+ // We can't use new[] since the existing API says the caller should free()
+ // the returned array
+ auto ret = static_cast<adf_id_t *>(malloc(size));
+ if (!ret)
+ return -ENOMEM;
- dir = opendir(ADF_BASE_PATH);
+ std::copy(in.begin(), in.end(), ret);
+ *out = ret;
+ return in.size();
+}
+
+static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids_out)
+{
+ struct dirent *dirent;
+ std::unique_ptr<DIR, decltype(&closedir)>
+ dir{opendir(ADF_BASE_PATH), closedir};
if (!dir)
return -errno;
+ std::vector<adf_id_t> ids;
errno = 0;
- while ((dirent = readdir(dir))) {
+ while ((dirent = readdir(dir.get()))) {
adf_id_t id;
int matched = sscanf(dirent->d_name, pattern, &id);
- if (matched < 0) {
- ret = -errno;
- goto done;
- } else if (matched != 1) {
- continue;
- }
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = id;
- n++;
+ if (matched < 0)
+ return -errno;
+ else if (matched == 1)
+ ids.push_back(id);
}
if (errno)
- ret = -errno;
- else
- ret = n;
+ return -errno;
-done:
- closedir(dir);
- if (ret < 0)
- free(ids_ret);
- else
- *ids = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, ids_out);
}
ssize_t adf_devices(adf_id_t **ids)
@@ -115,46 +111,29 @@
if (err < 0)
return -ENOMEM;
- if (data->n_attachments) {
- data->attachments = malloc(sizeof(data->attachments[0]) *
- data->n_attachments);
- if (!data->attachments)
- return -ENOMEM;
- }
+ if (data->n_attachments)
+ data->attachments = new adf_attachment_config[data->n_attachments];
- if (data->n_allowed_attachments) {
+ if (data->n_allowed_attachments)
data->allowed_attachments =
- malloc(sizeof(data->allowed_attachments[0]) *
- data->n_allowed_attachments);
- if (!data->allowed_attachments) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ new adf_attachment_config[data->n_allowed_attachments];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_device_data(data);
+ }
return ret;
}
void adf_free_device_data(struct adf_device_data *data)
{
- free(data->attachments);
- free(data->allowed_attachments);
- free(data->custom_data);
+ delete [] data->attachments;
+ delete [] data->allowed_attachments;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_device_post(struct adf_device *dev,
@@ -180,6 +159,37 @@
return (int)data.complete_fence;
}
+int adf_device_post_v2(struct adf_device *dev,
+ adf_id_t *interfaces, __u32 n_interfaces,
+ struct adf_buffer_config *bufs, __u32 n_bufs,
+ void *custom_data, __u64 custom_data_size,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence)
+{
+ int err;
+ struct adf_post_config_v2 data;
+
+ memset(&data, 0, sizeof(data));
+ data.interfaces = (uintptr_t)interfaces;
+ data.n_interfaces = n_interfaces;
+ data.bufs = (uintptr_t)bufs;
+ data.n_bufs = n_bufs;
+ data.custom_data = (uintptr_t)custom_data;
+ data.custom_data_size = custom_data_size;
+ data.complete_fence_type = complete_fence_type;
+
+ err = ioctl(dev->fd, ADF_POST_CONFIG_V2, &data);
+ if (err < 0)
+ return -errno;
+
+ if (complete_fence)
+ *complete_fence = data.complete_fence;
+ else if (data.complete_fence >= 0)
+ close(data.complete_fence);
+
+ return 0;
+}
+
static int adf_device_attachment(struct adf_device *dev,
adf_id_t overlay_engine, adf_id_t interface, bool attach)
{
@@ -221,39 +231,17 @@
adf_id_t overlay_engine, adf_id_t **interfaces)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].overlay_engine == overlay_engine)
+ ids.push_back(data.allowed_attachments[i].interface);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].overlay_engine != overlay_engine)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].interface;
- n++;
- }
-
- ret = n;
-
-done:
adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *interfaces = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, interfaces);
}
static ssize_t adf_interfaces_filter(struct adf_device *dev,
@@ -261,46 +249,23 @@
bool (*filter)(struct adf_interface_data *data, __u32 match),
__u32 match)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
- size_t i;
- for (i = 0; i < n_in; i++) {
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < n_in; i++) {
int fd = adf_interface_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_interface_data data;
- ret = adf_get_interface_data(fd, &data);
+ auto ret = adf_get_interface_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, match))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, match))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
static bool adf_interface_type_filter(struct adf_interface_data *data,
@@ -354,35 +319,24 @@
if (err < 0)
return -errno;
- if (data->n_available_modes) {
- data->available_modes = malloc(sizeof(data->available_modes[0]) *
- data->n_available_modes);
- if (!data->available_modes)
- return -ENOMEM;
- }
+ if (data->n_available_modes)
+ data->available_modes = new drm_mode_modeinfo[data->n_available_modes];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_INTERFACE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_interface_data(data);
+ }
return ret;
}
void adf_free_interface_data(struct adf_interface_data *data)
{
- free(data->available_modes);
- free(data->custom_data);
+ delete [] data->available_modes;
+ delete [] static_cast<char *>(data->custom_data);
}
int adf_interface_blank(int fd, __u8 mode)
@@ -421,6 +375,21 @@
return (int)data.fd;
}
+static void adf_interface_simple_post_config_buf(struct adf_buffer_config *buf,
+ __u32 overlay_engine, __u32 w, __u32 h, __u32 format, int buf_fd,
+ __u32 offset, __u32 pitch, int acquire_fence)
+{
+ buf->overlay_engine = overlay_engine;
+ buf->w = w;
+ buf->h = h;
+ buf->format = format;
+ buf->fd[0] = buf_fd;
+ buf->offset[0] = offset;
+ buf->pitch[0] = pitch;
+ buf->n_planes = 1;
+ buf->acquire_fence = acquire_fence;
+}
+
int adf_interface_simple_post(int fd, __u32 overlay_engine,
__u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
__u32 pitch, int acquire_fence)
@@ -429,16 +398,8 @@
struct adf_simple_post_config data;
memset(&data, 0, sizeof(data));
- data.buf.overlay_engine = overlay_engine;
- data.buf.w = w;
- data.buf.h = h;
- data.buf.format = format;
- data.buf.fd[0] = buf_fd;
- data.buf.offset[0] = offset;
- data.buf.pitch[0] = pitch;
- data.buf.n_planes = 1;
- data.buf.acquire_fence = acquire_fence;
-
+ adf_interface_simple_post_config_buf(&data.buf, overlay_engine, w, h, format,
+ buf_fd, offset, pitch, acquire_fence);
ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG, &data);
if (ret < 0)
return -errno;
@@ -446,6 +407,32 @@
return (int)data.complete_fence;
}
+int adf_interface_simple_post_v2(int fd, adf_id_t overlay_engine,
+ __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+ __u32 pitch, int acquire_fence,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence)
+{
+ int ret;
+ struct adf_simple_post_config_v2 data;
+
+ memset(&data, 0, sizeof(data));
+ adf_interface_simple_post_config_buf(&data.buf, overlay_engine, w, h, format,
+ buf_fd, offset, pitch, acquire_fence);
+ data.complete_fence_type = complete_fence_type;
+
+ ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG_V2, &data);
+ if (ret < 0)
+ return -errno;
+
+ if (complete_fence)
+ *complete_fence = data.complete_fence;
+ else if (data.complete_fence >= 0)
+ close(data.complete_fence);
+
+ return 0;
+}
+
ssize_t adf_overlay_engines(struct adf_device *dev, adf_id_t **overlay_engines)
{
char pattern[64];
@@ -458,39 +445,16 @@
adf_id_t interface, adf_id_t **overlay_engines)
{
struct adf_device_data data;
- ssize_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
+ auto err = adf_get_device_data(dev, &data);
+ if (err < 0)
+ return err;
- ret = adf_get_device_data(dev, &data);
- if (ret < 0)
- return ret;
+ std::vector<adf_id_t> ids;
+ for (size_t i = 0; i < data.n_allowed_attachments; i++)
+ if (data.allowed_attachments[i].interface == interface)
+ ids.push_back(data.allowed_attachments[i].overlay_engine);
- size_t i;
- for (i = 0; i < data.n_allowed_attachments; i++) {
- if (data.allowed_attachments[i].interface != interface)
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = data.allowed_attachments[i].overlay_engine;
- n++;
- }
-
- ret = n;
-
-done:
- adf_free_device_data(&data);
- if (ret < 0)
- free(ids_ret);
- else
- *overlay_engines = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, overlay_engines);
}
static ssize_t adf_overlay_engines_filter(struct adf_device *dev,
@@ -498,46 +462,24 @@
bool (*filter)(struct adf_overlay_engine_data *data, void *cookie),
void *cookie)
{
- size_t n = 0;
- ssize_t ret;
- adf_id_t *ids_ret = NULL;
-
+ std::vector<adf_id_t> ids;
size_t i;
for (i = 0; i < n_in; i++) {
int fd = adf_overlay_engine_open(dev, in[i], O_RDONLY);
- if (fd < 0) {
- ret = fd;
- goto done;
- }
+ if (fd < 0)
+ return fd;
struct adf_overlay_engine_data data;
- ret = adf_get_overlay_engine_data(fd, &data);
+ auto ret = adf_get_overlay_engine_data(fd, &data);
close(fd);
if (ret < 0)
- goto done;
+ return ret;
- if (!filter(&data, cookie))
- continue;
-
- adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
- if (!new_ids) {
- ret = -ENOMEM;
- goto done;
- }
-
- ids_ret = new_ids;
- ids_ret[n] = in[i];
- n++;
+ if (filter(&data, cookie))
+ ids.push_back(in[i]);
}
- ret = n;
-
-done:
- if (ret < 0)
- free(ids_ret);
- else
- *out = ids_ret;
- return ret;
+ return adf_id_vector_to_array(ids, out);
}
struct format_filter_cookie {
@@ -548,7 +490,7 @@
static bool adf_overlay_engine_format_filter(
struct adf_overlay_engine_data *data, void *cookie)
{
- struct format_filter_cookie *c = cookie;
+ auto c = static_cast<format_filter_cookie *>(cookie);
size_t i;
for (i = 0; i < data->n_supported_formats; i++) {
size_t j;
@@ -592,35 +534,24 @@
if (err < 0)
return -errno;
- if (data->n_supported_formats) {
- data->supported_formats = malloc(sizeof(data->supported_formats[0]) *
- data->n_supported_formats);
- if (!data->supported_formats)
- return -ENOMEM;
- }
+ if (data->n_supported_formats)
+ data->supported_formats = new __u32[data->n_supported_formats];
- if (data->custom_data_size) {
- data->custom_data = malloc(data->custom_data_size);
- if (!data->custom_data) {
- ret = -ENOMEM;
- goto done;
- }
- }
+ if (data->custom_data_size)
+ data->custom_data = new char[data->custom_data_size];
err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data);
- if (err < 0)
+ if (err < 0) {
ret = -errno;
-
-done:
- if (ret < 0)
adf_free_overlay_engine_data(data);
+ }
return ret;
}
void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data)
{
- free(data->supported_formats);
- free(data->custom_data);
+ delete [] data->supported_formats;
+ delete [] static_cast<char *>(data->custom_data);
}
bool adf_overlay_engine_supports_format(int fd, __u32 format)
@@ -660,12 +591,12 @@
int adf_read_event(int fd, struct adf_event **event)
{
struct adf_event header;
- struct {
+ struct event_with_data {
struct adf_event base;
uint8_t data[0];
- } *event_ret;
+ };
+ using unique_event = std::unique_ptr<event_with_data, decltype(&free)>;
size_t data_size;
- int ret = 0;
int err = read(fd, &header, sizeof(header));
if (err < 0)
@@ -675,28 +606,23 @@
if (header.length < sizeof(header))
return -EIO;
- event_ret = malloc(header.length);
+ // Again, we can't use new[] since the existing API says the caller should
+ // free() the returned event
+ auto event_ptr = static_cast<event_with_data *>(malloc(header.length));
+ unique_event event_ret{event_ptr, free};
if (!event_ret)
return -ENOMEM;
data_size = header.length - sizeof(header);
- memcpy(event_ret, &header, sizeof(header));
+ memcpy(event_ret.get(), &header, sizeof(header));
ssize_t read_size = read(fd, &event_ret->data, data_size);
- if (read_size < 0) {
- ret = -errno;
- goto done;
- }
- if ((size_t)read_size < data_size) {
- ret = -EIO;
- goto done;
- }
+ if (read_size < 0)
+ return -errno;
+ if ((size_t)read_size < data_size)
+ return -EIO;
- *event = &event_ret->base;
-
-done:
- if (ret < 0)
- free(event_ret);
- return ret;
+ *event = &event_ret.release()->base;
+ return 0;
}
void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE])
diff --git a/adf/libadf/include/adf/adf.h b/adf/libadf/include/adf/adf.h
index b6bda34..e4c7b28 100644
--- a/adf/libadf/include/adf/adf.h
+++ b/adf/libadf/include/adf/adf.h
@@ -75,6 +75,29 @@
struct adf_buffer_config *bufs, size_t n_bufs,
void *custom_data, size_t custom_data_size);
/**
+ * Atomically posts a new display configuration to the specified interfaces.
+ *
+ * Compared to adf_device_post(), adf_device_post_v2():
+ *
+ * (*) allows the client to choose the kind of sync fence returned
+ * (through complete_fence_type)
+ *
+ * (*) stores the returned sync fence fd in a provided buffer, so the client
+ * can distinguish between a permission error (ret = -1) and a successful
+ * call that returns no fence (*complete_fence = -1)
+ *
+ * On error, returns -errno.
+ *
+ * On devices without the corresponding kernel support, returns -ENOTTY.
+ */
+int adf_device_post_v2(struct adf_device *dev,
+ adf_id_t *interfaces, __u32 n_interfaces,
+ struct adf_buffer_config *bufs, __u32 n_bufs,
+ void *custom_data, __u64 custom_data_size,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence);
+
+/**
* Attaches the specified interface and overlay engine.
*/
int adf_device_attach(struct adf_device *dev, adf_id_t overlay_engine,
@@ -163,6 +186,28 @@
int adf_interface_simple_post(int fd, adf_id_t overlay_engine,
__u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
__u32 pitch, int acquire_fence);
+/**
+ * Posts a single-plane RGB buffer to the display using the specified
+ * overlay engine.
+ *
+ * Compared to adf_interface_simple_post(), adf_interface_simple_post_v2():
+ *
+ * (*) allows the client to choose the kind of sync fence returned
+ * (through complete_fence_type)
+ *
+ * (*) stores the returned sync fence fd in a provided buffer, so the client
+ * can distinguish between a permission error (ret = -1) and a successful
+ * call that returns no fence (*complete_fence = -1)
+ *
+ * On error, returns -errno.
+ *
+ * On devices without the corresponding kernel support, returns -ENOTTY.
+ */
+int adf_interface_simple_post_v2(int fd, adf_id_t overlay_engine,
+ __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+ __u32 pitch, int acquire_fence,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence);
/**
* Enumerates all overlay engines belonging to an ADF device.
diff --git a/adf/libadf/include/video/adf.h b/adf/libadf/include/video/adf.h
index 77203a5..692a425 100644
--- a/adf/libadf/include/video/adf.h
+++ b/adf/libadf/include/video/adf.h
@@ -49,69 +49,94 @@
ADF_EVENT_DEVICE_CUSTOM = 128,
ADF_EVENT_TYPE_MAX = 255,
};
-struct adf_set_event {
+enum adf_complete_fence_type {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ ADF_COMPLETE_FENCE_NONE = 0,
+ ADF_COMPLETE_FENCE_PRESENT = 1,
+ ADF_COMPLETE_FENCE_RELEASE = 2,
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_set_event {
__u8 type;
__u8 enabled;
};
-struct adf_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_event {
__u8 type;
__u32 length;
};
-struct adf_vsync_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_vsync_event {
struct adf_event base;
__aligned_u64 timestamp;
};
-struct adf_hotplug_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_hotplug_event {
struct adf_event base;
__u8 connected;
};
-#define ADF_MAX_PLANES 4
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ADF_MAX_PLANES 4
struct adf_buffer_config {
__u32 overlay_engine;
__u32 w;
- __u32 h;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 h;
__u32 format;
__s32 fd[ADF_MAX_PLANES];
__u32 offset[ADF_MAX_PLANES];
- __u32 pitch[ADF_MAX_PLANES];
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 pitch[ADF_MAX_PLANES];
__u8 n_planes;
__s32 acquire_fence;
};
-#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
struct adf_post_config {
size_t n_interfaces;
__u32 __user * interfaces;
- size_t n_bufs;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ size_t n_bufs;
struct adf_buffer_config __user * bufs;
size_t custom_data_size;
void __user * custom_data;
- __s32 complete_fence;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __s32 complete_fence;
};
+struct adf_post_config_v2 {
+ __u32 n_interfaces;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 interfaces;
+ __u32 n_bufs;
+ __u64 bufs;
+ __u64 custom_data_size;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 custom_data;
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
struct adf_simple_buffer_alloc {
__u16 w;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u16 h;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 format;
__s32 fd;
__u32 offset;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 pitch;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct adf_simple_post_config {
struct adf_buffer_config buf;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__s32 complete_fence;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+struct adf_simple_post_config_v2 {
+ struct adf_buffer_config buf;
+ __s32 complete_fence;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 complete_fence_type;
};
struct adf_attachment_config {
__u32 overlay_engine;
@@ -177,4 +202,8 @@
#define ADF_ATTACH _IOW(ADF_IOCTL_TYPE, 9, struct adf_attachment_config)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ADF_DETACH _IOW(ADF_IOCTL_TYPE, 10, struct adf_attachment_config)
+#define ADF_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 11, struct adf_post_config_v2)
+#define ADF_SIMPLE_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 12, struct adf_simple_post_config_v2)
#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+
diff --git a/adf/libadf/original-kernel-headers/video/adf.h b/adf/libadf/original-kernel-headers/video/adf.h
index c5d2e62..8293c1d 100644
--- a/adf/libadf/original-kernel-headers/video/adf.h
+++ b/adf/libadf/original-kernel-headers/video/adf.h
@@ -46,6 +46,15 @@
ADF_EVENT_TYPE_MAX = 255,
};
+enum adf_complete_fence_type {
+ /* no fence */
+ ADF_COMPLETE_FENCE_NONE = 0,
+ /* fence fires when the configuration appears on the screen */
+ ADF_COMPLETE_FENCE_PRESENT = 1,
+ /* fence fires when the configuration leaves the screen */
+ ADF_COMPLETE_FENCE_RELEASE = 2,
+};
+
/**
* struct adf_set_event - start or stop subscribing to ADF events
*
@@ -131,6 +140,9 @@
/**
* struct adf_post_config - request to flip to a new set of buffers
*
+ * This request is equivalent to &struct adf_post_config_v2 with
+ * @complete_fence_type = %ADF_COMPLETE_FENCE_RELEASE.
+ *
* @n_interfaces: number of interfaces targeted by the flip (input)
* @interfaces: ids of interfaces targeted by the flip (input)
* @n_bufs: number of buffers displayed (input)
@@ -152,6 +164,34 @@
__s32 complete_fence;
};
+
+/**
+ * struct adf_post_config_v2 - request to flip to a new set of buffers
+ *
+ * @n_interfaces: number of interfaces targeted by the flip (input)
+ * @interfaces: ids of interfaces targeted by the flip (input)
+ * @n_bufs: number of buffers displayed (input)
+ * @bufs: description of buffers displayed (input)
+ * @custom_data_size: size of driver-private data (input)
+ * @custom_data: driver-private data (input)
+ * @complete_fence_type: one of &enum adf_complete_fence_type describing what
+ * fence to return (input)
+ * @complete_fence: sync_fence fd which will fire at the time
+ * requested by @complete_fence_type (output)
+ */
+struct adf_post_config_v2 {
+ __u32 n_interfaces;
+ __u64 interfaces; /* __u32 * packed into __u64 */
+
+ __u32 n_bufs;
+ __u64 bufs; /* struct adf_buffer_config * packed into __u64 */
+
+ __u64 custom_data_size;
+ __u64 custom_data; /* void * packed into __u64 */
+
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
/**
@@ -189,6 +229,9 @@
* struct adf_simple_post_config - request to flip to a single buffer without
* driver-private data
*
+ * This request is equivalent to &struct adf_simple_post_config_v2 with
+ * @complete_fence_type = %ADF_COMPLETE_FENCE_RELEASE.
+ *
* @buf: description of buffer displayed (input)
* @complete_fence: sync_fence fd which will clear when this buffer has left the
* screen (output)
@@ -199,6 +242,22 @@
};
/**
+ * struct adf_simple_post_config_v2 - request to flip to a single buffer without
+ * driver-private data
+ *
+ * @buf: description of buffer displayed (input)
+ * @complete_fence_type: one of &enum adf_complete_fence_type describing what
+ * fence to return (input)
+ * @complete_fence: sync_fence fd which will fire at the time
+ * requested by @complete_fence_type (output)
+ */
+struct adf_simple_post_config_v2 {
+ struct adf_buffer_config buf;
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
+
+/**
* struct adf_attachment_config - description of attachment between an overlay
* engine and an interface
*
@@ -318,4 +377,10 @@
#define ADF_DETACH _IOW(ADF_IOCTL_TYPE, 10, \
struct adf_attachment_config)
+#define ADF_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 11, \
+ struct adf_post_config_v2)
+#define ADF_SIMPLE_POST_CONFIG_V2 \
+ _IOW(ADF_IOCTL_TYPE, 12, \
+ struct adf_simple_post_config_v2)
+
#endif /* _UAPI_VIDEO_ADF_H_ */
diff --git a/adf/libadf/tests/Android.bp b/adf/libadf/tests/Android.bp
index 7b33300..9b3430e 100644
--- a/adf/libadf/tests/Android.bp
+++ b/adf/libadf/tests/Android.bp
@@ -17,6 +17,7 @@
cc_test {
name: "adf-unit-tests",
srcs: ["adf_test.cpp"],
+ shared_libs: ["libsync"],
static_libs: ["libadf"],
cflags: ["-Werror"],
}
diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
index eaa9342..82a91f4 100644
--- a/adf/libadf/tests/adf_test.cpp
+++ b/adf/libadf/tests/adf_test.cpp
@@ -20,6 +20,7 @@
#include <adf/adf.h>
#include <gtest/gtest.h>
#include <sys/mman.h>
+#include <sync/sync.h>
class AdfTest : public testing::Test {
public:
@@ -73,24 +74,6 @@
FAIL(); /* this should never happen */
}
- void drawCheckerboard(void *buf, uint32_t w, uint32_t h, uint32_t pitch) {
- uint8_t *buf8 = reinterpret_cast<uint8_t *>(buf);
- for (uint32_t y = 0; y < h / 2; y++) {
- uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
- for (uint32_t x = 0; x < w / 2; x++)
- scanline[x] = 0xFF0000FF;
- for (uint32_t x = w / 2; x < w; x++)
- scanline[x] = 0xFF00FFFF;
- }
- for (uint32_t y = h / 2; y < h; y++) {
- uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
- for (uint32_t x = 0; x < w / 2; x++)
- scanline[x] = 0xFFFF00FF;
- for (uint32_t x = w / 2; x < w; x++)
- scanline[x] = 0xFFFFFFFF;
- }
- }
-
/* various helpers to call ADF and die on failure */
void getInterfaceData(adf_interface_data &data) {
@@ -141,6 +124,42 @@
free(event);
}
+ void drawCheckerboard(uint32_t &w, uint32_t &h, uint32_t &format,
+ char format_str[ADF_FORMAT_STR_SIZE], int &buf_fd, uint32_t &offset,
+ uint32_t &pitch) {
+ ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
+ ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
+
+ buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
+ &pitch);
+ ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-buf_fd);
+ EXPECT_GE(pitch, w * 4);
+
+ void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd,
+ offset);
+ ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-errno);
+
+ uint8_t *buf8 = static_cast<uint8_t *>(mapped);
+ for (uint32_t y = 0; y < h / 2; y++) {
+ uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+ for (uint32_t x = 0; x < w / 2; x++)
+ scanline[x] = 0xFF0000FF;
+ for (uint32_t x = w / 2; x < w; x++)
+ scanline[x] = 0xFF00FFFF;
+ }
+ for (uint32_t y = h / 2; y < h; y++) {
+ uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+ for (uint32_t x = 0; x < w / 2; x++)
+ scanline[x] = 0xFFFF00FF;
+ for (uint32_t x = w / 2; x < w; x++)
+ scanline[x] = 0xFFFFFFFF;
+ }
+
+ munmap(mapped, pitch * h);
+ }
+
protected:
adf_device dev;
adf_id_t intf_id;
@@ -169,7 +188,7 @@
const size_t AdfTest::n_fmt8888 = sizeof(fmt8888) / sizeof(fmt8888[0]);
TEST(adf, devices) {
- adf_id_t *devs;
+ adf_id_t *devs = nullptr;
ssize_t n_devs = adf_devices(&devs);
free(devs);
@@ -310,27 +329,11 @@
}
TEST_F(AdfTest, simple_buffer) {
- uint32_t w = 0, h = 0;
- ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
-
- uint32_t format = 0;
+ int buf_fd;
+ uint32_t w, h, format, offset, pitch;
char format_str[ADF_FORMAT_STR_SIZE];
- ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
-
- uint32_t offset;
- uint32_t pitch;
- int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
- &pitch);
- ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
- format_str << " buffer failed: " << strerror(-buf_fd);
- EXPECT_GE(pitch, w * 4);
-
- void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd,
- offset);
- ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " <<
- format_str << " buffer failed: " << strerror(-errno);
- drawCheckerboard(mapped, w, h, pitch);
- munmap(mapped, pitch * h);
+ ASSERT_NO_FATAL_FAILURE(drawCheckerboard(w, h, format, format_str,
+ buf_fd, offset, pitch));
ASSERT_NO_FATAL_FAILURE(attach());
ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
@@ -342,3 +345,59 @@
format_str << " buffer failed: " << strerror(-release_fence);
close(release_fence);
}
+
+TEST_F(AdfTest, simple_buffer_v2) {
+ int buf_fd;
+ uint32_t w, h, format, offset, pitch;
+ char format_str[ADF_FORMAT_STR_SIZE];
+ ASSERT_NO_FATAL_FAILURE(drawCheckerboard(w, h, format, format_str,
+ buf_fd, offset, pitch));
+
+ ASSERT_NO_FATAL_FAILURE(attach());
+ ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
+
+ int config_1_release;
+ int err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_RELEASE,
+ &config_1_release);
+ if (err == -ENOTTY) {
+ GTEST_LOG_(INFO) << "ADF_SIMPLE_POST_CONFIG_V2 not supported on this kernel";
+ return;
+ }
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+
+ err = sync_wait(config_1_release, 1000);
+ ASSERT_EQ(-1, err) <<
+ "waiting for config 1's release fence should not have suceeded";
+ ASSERT_EQ(ETIME, errno) <<
+ "config 1's release fence should have timed out, but failed instead: " <<
+ strerror(errno);
+
+ int config_2_present;
+ err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_PRESENT,
+ &config_2_present);
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+
+ err = sync_wait(config_2_present, 1000);
+ ASSERT_EQ(0, err) <<
+ "waiting for config 2's present fence failed: " << strerror(errno);
+ err = sync_wait(config_1_release, 0);
+ ASSERT_EQ(0, err) <<
+ "waiting for config 1's release fence failed: " << strerror(errno);
+ close(config_1_release);
+ close(config_2_present);
+
+ int config_3_no_fence;
+ err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_NONE,
+ &config_3_no_fence);
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+ ASSERT_EQ(-1, config_3_no_fence) <<
+ "fence returned even though the fence type was ADF_COMPLETE_FENCE_NONE";
+
+ close(buf_fd);
+}
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index a97862a..63c0f75 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -166,6 +166,71 @@
return 0;
}
+static int32_t adf_display_attribute_hwc2(const adf_interface_data &data,
+ const drm_mode_modeinfo &mode, const uint32_t attribute)
+{
+ switch (attribute) {
+ case HWC2_ATTRIBUTE_VSYNC_PERIOD:
+ if (mode.vrefresh)
+ return 1000000000 / mode.vrefresh;
+ return 0;
+
+ case HWC2_ATTRIBUTE_WIDTH:
+ return mode.hdisplay;
+
+ case HWC2_ATTRIBUTE_HEIGHT:
+ return mode.vdisplay;
+
+ case HWC2_ATTRIBUTE_DPI_X:
+ return dpi(mode.hdisplay, data.width_mm);
+
+ case HWC2_ATTRIBUTE_DPI_Y:
+ return dpi(mode.vdisplay, data.height_mm);
+
+ default:
+ ALOGE("unknown display attribute %u", attribute);
+ return -EINVAL;
+ }
+}
+
+int adf_getDisplayAttributes_hwc2(struct adf_hwc_helper *dev, int disp,
+ uint32_t config, const uint32_t *attributes, int32_t *values)
+{
+ if ((size_t)disp >= dev->intf_fds.size())
+ return -EINVAL;
+
+ if (config >= dev->display_configs.size())
+ return -EINVAL;
+
+ adf_interface_data data;
+ int err = adf_get_interface_data(dev->intf_fds[disp], &data);
+ if (err < 0) {
+ ALOGE("failed to get ADF interface data: %s", strerror(err));
+ return err;
+ }
+
+ for (int i = 0; attributes[i] != HWC2_ATTRIBUTE_INVALID; i++)
+ values[i] = adf_display_attribute_hwc2(data,
+ dev->display_configs[config], attributes[i]);
+
+ adf_free_interface_data(&data);
+ return 0;
+}
+
+int adf_set_active_config_hwc2(struct adf_hwc_helper *dev, int disp,
+ uint32_t config)
+{
+ if ((size_t)disp >= dev->intf_fds.size())
+ return -EINVAL;
+
+ if (config >= dev->display_configs.size())
+ return -EINVAL;
+
+ struct drm_mode_modeinfo mode = dev->display_configs[config];
+
+ return adf_interface_set_mode(dev->intf_fds[disp], &mode);
+}
+
static void handle_adf_event(struct adf_hwc_helper *dev, int disp)
{
adf_event *event;
@@ -208,28 +273,39 @@
setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
- pollfd *fds = new pollfd[dev->intf_fds.size()];
+ struct sigaction action = { };
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = [](int) { pthread_exit(0); };
+
+ if (sigaction(SIGUSR2, &action, NULL) < 0) {
+ ALOGE("failed to set thread exit action %s", strerror(errno));
+ return NULL;
+ }
+
+ sigset_t signal_set;
+ sigemptyset(&signal_set);
+ sigaddset(&signal_set, SIGUSR2);
+
+ pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
+
+ pollfd fds[dev->intf_fds.size()];
for (size_t i = 0; i < dev->intf_fds.size(); i++) {
fds[i].fd = dev->intf_fds[i];
fds[i].events = POLLIN | POLLPRI;
}
while (true) {
- int err = poll(fds, dev->intf_fds.size(), -1);
-
- if (err > 0) {
- for (size_t i = 0; i < dev->intf_fds.size(); i++)
- if (fds[i].revents & (POLLIN | POLLPRI))
- handle_adf_event(dev, i);
- }
- else if (err == -1) {
- if (errno == EINTR)
- break;
+ if (TEMP_FAILURE_RETRY(poll(fds, dev->intf_fds.size(), -1)) < 0) {
ALOGE("error in event thread: %s", strerror(errno));
+ break;
}
+
+ for (size_t i = 0; i < dev->intf_fds.size(); i++)
+ if (fds[i].revents & (POLLIN | POLLPRI))
+ handle_adf_event(dev, i);
}
- delete [] fds;
return NULL;
}
@@ -264,6 +340,12 @@
}
}
+ sigset_t signal_set;
+ sigemptyset(&signal_set);
+ sigaddset(&signal_set, SIGUSR2);
+
+ pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
+
ret = pthread_create(&dev_ret->event_thread, NULL, adf_event_thread,
dev_ret);
if (ret) {
@@ -284,7 +366,7 @@
void adf_hwc_close(struct adf_hwc_helper *dev)
{
- pthread_kill(dev->event_thread, SIGTERM);
+ pthread_kill(dev->event_thread, SIGUSR2);
pthread_join(dev->event_thread, NULL);
for (size_t i = 0; i < dev->intf_fds.size(); i++)
diff --git a/adf/libadfhwc/include/adfhwc/adfhwc.h b/adf/libadfhwc/include/adfhwc/adfhwc.h
index 71e7624..4f70925 100644
--- a/adf/libadfhwc/include/adfhwc/adfhwc.h
+++ b/adf/libadfhwc/include/adfhwc/adfhwc.h
@@ -23,6 +23,7 @@
#include <video/adf.h>
#include <hardware/hwcomposer.h>
+#include <hardware/hwcomposer2.h>
struct adf_hwc_helper;
@@ -123,6 +124,16 @@
uint32_t *configs, size_t *numConfigs);
int adf_getDisplayAttributes(struct adf_hwc_helper *dev, int disp,
uint32_t config, const uint32_t *attributes, int32_t *values);
+/**
+ * Generic implementation of common HWC2 functions.
+ *
+ * The HWC2 should not return these functions directly through getFunction.
+ * Instead, the HWC2 should return stub functions which call these helpers.
+ */
+int adf_getDisplayAttributes_hwc2(struct adf_hwc_helper *dev, int disp,
+ uint32_t config, const uint32_t *attributes, int32_t *values);
+int adf_set_active_config_hwc2(struct adf_hwc_helper *dev, int disp,
+ uint32_t config);
__END_DECLS
diff --git a/base/.clang-format b/base/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/base/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/base/Android.bp b/base/Android.bp
index b9a6e0b..7b1dc8e 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -44,6 +44,9 @@
"properties.cpp",
],
cppflags: ["-Wexit-time-destructors"],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
},
darwin: {
srcs: ["errors_unix.cpp"],
@@ -75,6 +78,7 @@
host_supported: true,
clang: true,
srcs: [
+ "endian_test.cpp",
"errors_test.cpp",
"file_test.cpp",
"logging_test.cpp",
@@ -89,6 +93,9 @@
target: {
android: {
srcs: ["properties_test.cpp"],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
},
windows: {
srcs: ["utf8_test.cpp"],
diff --git a/base/endian_test.cpp b/base/endian_test.cpp
new file mode 100644
index 0000000..963ab13
--- /dev/null
+++ b/base/endian_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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 "android-base/endian.h"
+
+#include <gtest/gtest.h>
+
+TEST(endian, constants) {
+ ASSERT_TRUE(__LITTLE_ENDIAN == LITTLE_ENDIAN);
+ ASSERT_TRUE(__BIG_ENDIAN == BIG_ENDIAN);
+ ASSERT_TRUE(__BYTE_ORDER == BYTE_ORDER);
+
+ ASSERT_EQ(__LITTLE_ENDIAN, __BYTE_ORDER);
+}
+
+TEST(endian, smoke) {
+ static constexpr uint16_t le16 = 0x1234;
+ static constexpr uint32_t le32 = 0x12345678;
+ static constexpr uint64_t le64 = 0x123456789abcdef0;
+
+ static constexpr uint16_t be16 = 0x3412;
+ static constexpr uint32_t be32 = 0x78563412;
+ static constexpr uint64_t be64 = 0xf0debc9a78563412;
+
+ ASSERT_EQ(be16, htons(le16));
+ ASSERT_EQ(be32, htonl(le32));
+ ASSERT_EQ(be64, htonq(le64));
+
+ ASSERT_EQ(le16, ntohs(be16));
+ ASSERT_EQ(le32, ntohl(be32));
+ ASSERT_EQ(le64, ntohq(be64));
+
+ ASSERT_EQ(be16, htobe16(le16));
+ ASSERT_EQ(be32, htobe32(le32));
+ ASSERT_EQ(be64, htobe64(le64));
+
+ ASSERT_EQ(le16, betoh16(be16));
+ ASSERT_EQ(le32, betoh32(be32));
+ ASSERT_EQ(le64, betoh64(be64));
+
+ ASSERT_EQ(le16, htole16(le16));
+ ASSERT_EQ(le32, htole32(le32));
+ ASSERT_EQ(le64, htole64(le64));
+
+ ASSERT_EQ(le16, letoh16(le16));
+ ASSERT_EQ(le32, letoh32(le32));
+ ASSERT_EQ(le64, letoh64(le64));
+
+ ASSERT_EQ(le16, be16toh(be16));
+ ASSERT_EQ(le32, be32toh(be32));
+ ASSERT_EQ(le64, be64toh(be64));
+
+ ASSERT_EQ(le16, le16toh(le16));
+ ASSERT_EQ(le32, le32toh(le32));
+ ASSERT_EQ(le64, le64toh(le64));
+}
diff --git a/base/file.cpp b/base/file.cpp
index 6284b04..378a405 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -18,11 +18,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <string>
#include <vector>
@@ -210,6 +212,20 @@
}
#endif
+#if !defined(_WIN32)
+bool Realpath(const std::string& path, std::string* result) {
+ result->clear();
+
+ char* realpath_buf = realpath(path.c_str(), nullptr);
+ if (realpath_buf == nullptr) {
+ return false;
+ }
+ result->assign(realpath_buf);
+ free(realpath_buf);
+ return true;
+}
+#endif
+
std::string GetExecutablePath() {
#if defined(__linux__)
std::string path;
@@ -236,5 +252,59 @@
#endif
}
+std::string GetExecutableDirectory() {
+ return Dirname(GetExecutablePath());
+}
+
+std::string Basename(const std::string& path) {
+ // Copy path because basename may modify the string passed in.
+ std::string result(path);
+
+#if !defined(__BIONIC__)
+ // Use lock because basename() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to basename in the process also grab this same lock, but its
+ // better than nothing. Bionic's basename returns a thread-local buffer.
+ static std::mutex& basename_lock = *new std::mutex();
+ std::lock_guard<std::mutex> lock(basename_lock);
+#endif
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* name = basename(&result[0]);
+
+ // In case basename returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ result.assign(name);
+
+ return result;
+}
+
+std::string Dirname(const std::string& path) {
+ // Copy path because dirname may modify the string passed in.
+ std::string result(path);
+
+#if !defined(__BIONIC__)
+ // Use lock because dirname() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to dirname in the process also grab this same lock, but its
+ // better than nothing. Bionic's dirname returns a thread-local buffer.
+ static std::mutex& dirname_lock = *new std::mutex();
+ std::lock_guard<std::mutex> lock(dirname_lock);
+#endif
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* parent = dirname(&result[0]);
+
+ // In case dirname returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ result.assign(parent);
+
+ return result;
+}
+
} // namespace base
} // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index ed39ce9..266131e 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -159,6 +159,58 @@
#endif
}
+TEST(file, Realpath) {
+#if !defined(_WIN32)
+ TemporaryDir td;
+ std::string basename = android::base::Basename(td.path);
+ std::string dir_name = android::base::Dirname(td.path);
+ std::string base_dir_name = android::base::Basename(dir_name);
+
+ {
+ std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
+ std::string result;
+ ASSERT_TRUE(android::base::Realpath(path, &result));
+ ASSERT_EQ(td.path, result);
+ }
+
+ {
+ std::string path = std::string(td.path) + "/..";
+ std::string result;
+ ASSERT_TRUE(android::base::Realpath(path, &result));
+ ASSERT_EQ(dir_name, result);
+ }
+
+ {
+ errno = 0;
+ std::string path = std::string(td.path) + "/foo.noent";
+ std::string result = "wrong";
+ ASSERT_TRUE(!android::base::Realpath(path, &result));
+ ASSERT_TRUE(result.empty());
+ ASSERT_EQ(ENOENT, errno);
+ }
+#endif
+}
+
+TEST(file, GetExecutableDirectory) {
+ std::string path = android::base::GetExecutableDirectory();
+ ASSERT_NE("", path);
+ ASSERT_NE(android::base::GetExecutablePath(), path);
+ ASSERT_EQ('/', path[0]);
+ ASSERT_NE('/', path[path.size() - 1]);
+}
+
TEST(file, GetExecutablePath) {
ASSERT_NE("", android::base::GetExecutablePath());
}
+
+TEST(file, Basename) {
+ EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
+ EXPECT_EQ("sh", android::base::Basename("sh"));
+ EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
+}
+
+TEST(file, Dirname) {
+ EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
+ EXPECT_EQ(".", android::base::Dirname("sh"));
+ EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
+}
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
new file mode 100644
index 0000000..6eb677c
--- /dev/null
+++ b/base/include/android-base/endian.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_BASE_ENDIAN_H
+#define ANDROID_BASE_ENDIAN_H
+
+/* A cross-platform equivalent of bionic's <sys/endian.h>. */
+
+#if defined(__BIONIC__)
+
+#include <sys/endian.h>
+
+#elif defined(__GLIBC__)
+
+/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
+#include <endian.h>
+
+/* glibc keeps htons and htonl in <netinet/in.h>. */
+#include <netinet/in.h>
+
+/* glibc doesn't have the 64-bit variants. */
+#define htonq(x) htobe64(x)
+#define ntohq(x) be64toh(x)
+
+/* glibc has different names to BSD for these. */
+#define betoh16(x) be16toh(x)
+#define betoh32(x) be32toh(x)
+#define betoh64(x) be64toh(x)
+
+#else
+
+/* Mac OS and Windows have nothing. */
+
+#define __LITTLE_ENDIAN 1234
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+
+#define __BIG_ENDIAN 4321
+#define BIG_ENDIAN __BIG_ENDIAN
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define BYTE_ORDER __BYTE_ORDER
+
+#define htons(x) __builtin_bswap16(x)
+#define htonl(x) __builtin_bswap32(x)
+#define htonq(x) __builtin_bswap64(x)
+
+#define ntohs(x) __builtin_bswap16(x)
+#define ntohl(x) __builtin_bswap32(x)
+#define ntohq(x) __builtin_bswap64(x)
+
+#define htobe16(x) __builtin_bswap16(x)
+#define htobe32(x) __builtin_bswap32(x)
+#define htobe64(x) __builtin_bswap64(x)
+
+#define betoh16(x) __builtin_bswap16(x)
+#define betoh32(x) __builtin_bswap32(x)
+#define betoh64(x) __builtin_bswap64(x)
+
+#define htole16(x) (x)
+#define htole32(x) (x)
+#define htole64(x) (x)
+
+#define letoh16(x) (x)
+#define letoh32(x) (x)
+#define letoh64(x) (x)
+
+#define be16toh(x) __builtin_bswap16(x)
+#define be32toh(x) __builtin_bswap32(x)
+#define be64toh(x) __builtin_bswap64(x)
+
+#define le16toh(x) (x)
+#define le32toh(x) (x)
+#define le64toh(x) (x)
+
+#endif
+
+#endif // ANDROID_BASE_ENDIAN_H
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index cd64262..651f529 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -47,10 +47,17 @@
bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
#if !defined(_WIN32)
+bool Realpath(const std::string& path, std::string* result);
bool Readlink(const std::string& path, std::string* result);
#endif
std::string GetExecutablePath();
+std::string GetExecutableDirectory();
+
+// Like the regular basename and dirname, but thread-safe on all
+// platforms and capable of correctly handling exotic Windows paths.
+std::string Basename(const std::string& path);
+std::string Dirname(const std::string& path);
} // namespace base
} // namespace android
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 50677a3..e78edbb 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -17,6 +17,37 @@
#ifndef ANDROID_BASE_LOGGING_H
#define ANDROID_BASE_LOGGING_H
+//
+// Google-style C++ logging.
+//
+
+// This header provides a C++ stream interface to logging.
+//
+// To log:
+//
+// LOG(INFO) << "Some text; " << some_value;
+//
+// Replace `INFO` with any severity from `enum LogSeverity`.
+//
+// To log the result of a failed function and include the string
+// representation of `errno` at the end:
+//
+// PLOG(ERROR) << "Write failed";
+//
+// The output will be something like `Write failed: I/O error`.
+// Remember this as 'P' as in perror(3).
+//
+// To output your own types, simply implement operator<< as normal.
+//
+// By default, output goes to logcat on Android and stderr on the host.
+// A process can use `SetLogger` to decide where all logging goes.
+// Implementations are provided for logcat, stderr, and dmesg.
+
+// This header also provides assertions:
+//
+// CHECK(must_be_true);
+// CHECK_EQ(a, b) << z_is_interesting_too;
+
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
#ifdef _WIN32
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4d7082a..4de5e57 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -23,6 +23,7 @@
#error Only bionic supports system properties.
#endif
+#include <chrono>
#include <limits>
#include <string>
@@ -58,6 +59,19 @@
// tell you whether or not your call succeeded. A `false` return value definitely means failure.
bool SetProperty(const std::string& key, const std::string& value);
+// Waits for the system property `key` to have the value `expected_value`.
+// Times out after `relative_timeout`.
+// Returns true on success, false on timeout.
+bool WaitForProperty(const std::string& key,
+ const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout);
+
+// Waits for the system property `key` to be created.
+// Times out after `relative_timeout`.
+// Returns true on success, false on timeout.
+bool WaitForPropertyCreation(const std::string& key,
+ std::chrono::milliseconds relative_timeout);
+
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 37daf9a..32c0128 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -14,14 +14,21 @@
* limitations under the License.
*/
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+
#include "android-base/properties.h"
#include <sys/system_properties.h>
+#include <sys/_system_properties.h>
+#include <algorithm>
+#include <chrono>
#include <string>
#include <android-base/parseint.h>
+using namespace std::chrono_literals;
+
namespace android {
namespace base {
@@ -78,5 +85,94 @@
return (__system_property_set(key.c_str(), value.c_str()) == 0);
}
+struct WaitForPropertyData {
+ bool done;
+ const std::string* expected_value;
+ unsigned last_read_serial;
+};
+
+static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
+ WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
+ if (*data->expected_value == value) {
+ data->done = true;
+ } else {
+ data->last_read_serial = serial;
+ }
+}
+
+// TODO: chrono_utils?
+static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
+ auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
+ auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
+ ts.tv_sec = s.count();
+ ts.tv_nsec = ns.count();
+}
+
+using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
+
+static void UpdateTimeSpec(timespec& ts,
+ const AbsTime& timeout) {
+ auto now = std::chrono::steady_clock::now();
+ auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
+ if (remaining_timeout < 0ns) {
+ ts = { 0, 0 };
+ } else {
+ DurationToTimeSpec(ts, remaining_timeout);
+ }
+}
+
+// Waits for the system property `key` to be created.
+// Times out after `relative_timeout`.
+// Sets absolute_timeout which represents absolute time for the timeout.
+// Returns nullptr on timeout.
+static const prop_info* WaitForPropertyCreation(const std::string& key,
+ const std::chrono::milliseconds& relative_timeout,
+ AbsTime& absolute_timeout) {
+ // TODO: boot_clock?
+ auto now = std::chrono::steady_clock::now();
+ absolute_timeout = now + relative_timeout;
+
+ // Find the property's prop_info*.
+ const prop_info* pi;
+ unsigned global_serial = 0;
+ while ((pi = __system_property_find(key.c_str())) == nullptr) {
+ // The property doesn't even exist yet.
+ // Wait for a global change and then look again.
+ timespec ts;
+ UpdateTimeSpec(ts, absolute_timeout);
+ if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
+ }
+ return pi;
+}
+
+bool WaitForProperty(const std::string& key,
+ const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout) {
+ AbsTime absolute_timeout;
+ const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+ if (pi == nullptr) return false;
+
+ WaitForPropertyData data;
+ data.expected_value = &expected_value;
+ data.done = false;
+ while (true) {
+ timespec ts;
+ // Check whether the property has the value we're looking for?
+ __system_property_read_callback(pi, WaitForPropertyCallback, &data);
+ if (data.done) return true;
+
+ // It didn't, so wait for the property to change before checking again.
+ UpdateTimeSpec(ts, absolute_timeout);
+ uint32_t unused;
+ if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
+ }
+}
+
+bool WaitForPropertyCreation(const std::string& key,
+ std::chrono::milliseconds relative_timeout) {
+ AbsTime absolute_timeout;
+ return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+}
+
} // namespace base
} // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index da89ec5..1bbe482 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -18,7 +18,12 @@
#include <gtest/gtest.h>
+#include <atomic>
+#include <chrono>
#include <string>
+#include <thread>
+
+using namespace std::chrono_literals;
TEST(properties, smoke) {
android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -119,3 +124,51 @@
TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
+
+TEST(properties, WaitForProperty) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ std::this_thread::sleep_for(100ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s));
+ thread.join();
+}
+
+TEST(properties, WaitForProperty_timeout) {
+ auto t0 = std::chrono::steady_clock::now();
+ ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a",
+ 200ms));
+ auto t1 = std::chrono::steady_clock::now();
+
+ ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
+ // Upper bounds on timing are inherently flaky, but let's try...
+ ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
+}
+
+TEST(properties, WaitForPropertyCreation) {
+ std::thread thread([&]() {
+ std::this_thread::sleep_for(100ms);
+ android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
+ });
+
+ ASSERT_TRUE(android::base::WaitForPropertyCreation(
+ "debug.libbase.WaitForPropertyCreation_test", 1s));
+ thread.join();
+}
+
+TEST(properties, WaitForPropertyCreation_timeout) {
+ auto t0 = std::chrono::steady_clock::now();
+ ASSERT_FALSE(android::base::WaitForPropertyCreation(
+ "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms));
+ auto t1 = std::chrono::steady_clock::now();
+
+ ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
+ // Upper bounds on timing are inherently flaky, but let's try...
+ ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index 46fe939..bfdaf12 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -36,11 +36,12 @@
size_t base = 0;
size_t found;
- do {
+ while (true) {
found = s.find_first_of(delimiters, base);
result.push_back(s.substr(base, found - base));
+ if (found == s.npos) break;
base = found + 1;
- } while (found != s.npos);
+ }
return result;
}
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7a65a00..7ed5b2b 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -251,3 +251,7 @@
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
}
+
+TEST(strings, ubsan_28729303) {
+ android::base::Split("/dev/null", ":");
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 3b3d698..636477d 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -57,7 +57,13 @@
static std::string GetSystemTempDir() {
#if defined(__ANDROID__)
- return "/data/local/tmp";
+ const char* tmpdir = "/data/local/tmp";
+ if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+ return tmpdir;
+ }
+ // Tests running in app context can't access /data/local/tmp,
+ // so try current directory if /data/local/tmp is not accessible.
+ return ".";
#elif defined(_WIN32)
char tmp_dir[MAX_PATH];
DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index d98a9d7..f744ad1 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
bootstat_lib_src_files = [
"boot_event_record_store.cpp",
- "histogram_logger.cpp",
"uptime_parser.cpp",
]
@@ -27,15 +26,12 @@
"-Wall",
"-Wextra",
"-Werror",
-
- // 524291 corresponds to sysui_histogram, from
- // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
- "-DHISTOGRAM_LOG_TAG=524291",
],
shared_libs: [
"libbase",
"libcutils",
"liblog",
+ "libmetricslogger",
],
whole_static_libs: ["libgtest_prod"],
// Clang is required because of C++14
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index f902af3..2648594 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -26,7 +26,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
-#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index c85667e..a4cc5f2 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -35,9 +35,9 @@
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
+#include <metricslogger/metrics_logger.h>
#include "boot_event_record_store.h"
-#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
@@ -49,7 +49,7 @@
auto events = boot_event_store.GetAllBootEvents();
for (auto i = events.cbegin(); i != events.cend(); ++i) {
- bootstat::LogHistogram(i->first, i->second);
+ android::metricslogger::LogHistogram(i->first, i->second);
}
}
@@ -225,7 +225,12 @@
void RecordBootloaderTimings(BootEventRecordStore* boot_event_store) {
// |ro.boot.boottime| is of the form 'stage1:time1,...,stageN:timeN'.
std::string value = GetProperty("ro.boot.boottime");
+ if (value.empty()) {
+ // ro.boot.boottime is not reported on all devices.
+ return;
+ }
+ int32_t total_time = 0;
auto stages = android::base::Split(value, ",");
for (auto const &stageTiming : stages) {
// |stageTiming| is of the form 'stage:time'.
@@ -235,10 +240,13 @@
std::string stageName = stageTimingValues[0];
int32_t time_ms;
if (android::base::ParseInt(stageTimingValues[1], &time_ms)) {
+ total_time += time_ms;
boot_event_store->AddBootEventWithValue(
"boottime.bootloader." + stageName, time_ms);
}
}
+
+ boot_event_store->AddBootEventWithValue("boottime.bootloader.total", total_time);
}
// Records several metrics related to the time it takes to boot the device,
@@ -317,18 +325,18 @@
if (current_time_utc < 0) {
// UMA does not display negative values in buckets, so convert to positive.
- bootstat::LogHistogram(
+ android::metricslogger::LogHistogram(
"factory_reset_current_time_failure", std::abs(current_time_utc));
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_current_time_failure", std::abs(current_time_utc));
return;
} else {
- bootstat::LogHistogram("factory_reset_current_time", current_time_utc);
+ android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_current_time", current_time_utc);
@@ -347,9 +355,9 @@
// Calculate and record the difference in time between now and the
// factory_reset time.
time_t factory_reset_utc = record.second;
- bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
+ android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
- // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
// is losing records somehow.
boot_event_store.AddBootEventWithValue(
"factory_reset_record_value", factory_reset_utc);
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index b072412..f4756d5 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -8,7 +8,8 @@
#
# post-fs-data: /data is writable
# property:init.svc.bootanim=running: The boot animation is running
-on post-fs-data && property:init.svc.bootanim=running
+# property:ro.crypto.type=block: FDE device
+on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
# sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
diff --git a/debuggerd/.clang-format b/debuggerd/.clang-format
deleted file mode 100644
index 9b7478c..0000000
--- a/debuggerd/.clang-format
+++ /dev/null
@@ -1,15 +0,0 @@
-BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
-
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-IndentWidth: 2
-ContinuationIndentWidth: 2
-PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
-PenaltyExcessCharacter: 32
-
-Cpp11BracedListStyle: false
diff --git a/debuggerd/.clang-format b/debuggerd/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/debuggerd/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ca881aa..2d6c7f5 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,25 +1,82 @@
cc_defaults {
name: "debuggerd_defaults",
+ defaults: ["linux_bionic_supported"],
cflags: [
"-Wall",
"-Wextra",
- "-Wno-error",
+ "-Werror",
"-Wno-nullability-completeness",
"-Os",
],
+ // util.cpp gets async signal safe logging via libc_logging,
+ // which defines its interface in bionic private headers.
+ include_dirs: ["bionic/libc"],
+
local_include_dirs: ["include"],
}
+// Utility library to tombstoned and get an output fd.
cc_library_static {
- name: "libdebuggerd_handler",
+ name: "libtombstoned_client",
+ defaults: ["debuggerd_defaults"],
+ srcs: [
+ "tombstoned_client.cpp",
+ "util.cpp",
+ ],
+
+ whole_static_libs: [
+ "libc_logging",
+ "libcutils",
+ "libbase",
+ ],
+}
+
+// Core implementation, linked into libdebuggerd_handler and the dynamic linker.
+cc_library_static {
+ name: "libdebuggerd_handler_core",
defaults: ["debuggerd_defaults"],
srcs: ["handler/debuggerd_handler.cpp"],
- // libdebuggerd_handler gets async signal safe logging via libc_logging,
- // which defines its interface in bionic private headers.
- include_dirs: ["bionic/libc"],
- static_libs: ["libc_logging"],
+ whole_static_libs: [
+ "libc_logging",
+ "libdebuggerd",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
+// Implementation with a no-op fallback.
+cc_library_static {
+ name: "libdebuggerd_handler",
+ defaults: ["debuggerd_defaults"],
+ srcs: ["handler/debuggerd_fallback_nop.cpp"],
+
+ whole_static_libs: [
+ "libdebuggerd_handler_core",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
+// Fallback implementation.
+cc_library_static {
+ name: "libdebuggerd_handler_fallback",
+ defaults: ["debuggerd_defaults"],
+ srcs: [
+ "handler/debuggerd_fallback.cpp",
+ ],
+
+ whole_static_libs: [
+ "libdebuggerd_handler_core",
+ "libtombstoned_client",
+ "libbase",
+ "libdebuggerd",
+ "libbacktrace",
+ "libunwind",
+ "liblzma",
+ "libcutils",
+ ],
export_include_dirs: ["include"],
}
@@ -36,10 +93,11 @@
"libbase",
"libcutils",
],
+
export_include_dirs: ["include"],
}
-cc_library {
+cc_library_static {
name: "libdebuggerd",
defaults: ["debuggerd_defaults"],
@@ -75,8 +133,10 @@
local_include_dirs: ["libdebuggerd/include"],
export_include_dirs: ["libdebuggerd/include"],
- shared_libs: [
+ static_libs: [
"libbacktrace",
+ "libunwind",
+ "liblzma",
"libbase",
"libcutils",
"liblog",
@@ -150,10 +210,15 @@
},
},
+ static_libs: [
+ "libtombstoned_client",
+ "libdebuggerd",
+ "libcutils",
+ ],
+
shared_libs: [
"libbacktrace",
"libbase",
- "libdebuggerd",
"liblog",
"libprocinfo",
"libselinux",
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 81d70df..f2975d1 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -45,42 +45,6 @@
return true;
}
-static bool check_dumpable(pid_t pid) {
- // /proc/<pid> is owned by the effective UID of the process.
- // Ownership of most of the other files in /proc/<pid> varies based on PR_SET_DUMPABLE.
- // If PR_GET_DUMPABLE would return 0, they're owned by root, instead.
- std::string proc_pid_path = android::base::StringPrintf("/proc/%d/", pid);
- std::string proc_pid_status_path = proc_pid_path + "/status";
-
- unique_fd proc_pid_fd(open(proc_pid_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
- if (proc_pid_fd == -1) {
- return false;
- }
- unique_fd proc_pid_status_fd(openat(proc_pid_fd, "status", O_RDONLY | O_CLOEXEC));
- if (proc_pid_status_fd == -1) {
- return false;
- }
-
- struct stat proc_pid_st;
- struct stat proc_pid_status_st;
- if (fstat(proc_pid_fd.get(), &proc_pid_st) != 0 ||
- fstat(proc_pid_status_fd.get(), &proc_pid_status_st) != 0) {
- return false;
- }
-
- // We can't figure out if a process is dumpable if its effective UID is root, but that's fine
- // because being root bypasses the PR_SET_DUMPABLE check for ptrace.
- if (proc_pid_st.st_uid == 0) {
- return true;
- }
-
- if (proc_pid_status_st.st_uid == 0) {
- return false;
- }
-
- return true;
-}
-
bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
int timeout_ms) {
LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
@@ -114,11 +78,6 @@
return true;
};
- if (!check_dumpable(pid)) {
- dprintf(output_fd.get(), "target pid %d is not dumpable\n", pid);
- return true;
- }
-
sockfd.reset(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
if (sockfd == -1) {
PLOG(ERROR) << "libdebugger_client: failed to create socket";
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 4e083ae..88f390b 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <limits>
+#include <map>
#include <memory>
#include <set>
#include <vector>
@@ -36,6 +37,7 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <log/log.h>
@@ -48,10 +50,25 @@
#include "debuggerd/handler.h"
#include "debuggerd/protocol.h"
+#include "debuggerd/tombstoned.h"
#include "debuggerd/util.h"
using android::base::unique_fd;
+using android::base::ReadFileToString;
using android::base::StringPrintf;
+using android::base::Trim;
+
+static std::string get_process_name(pid_t pid) {
+ std::string result = "<unknown>";
+ ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &result);
+ return result;
+}
+
+static std::string get_thread_name(pid_t tid) {
+ std::string result = "<unknown>";
+ ReadFileToString(StringPrintf("/proc/%d/comm", tid), &result);
+ return Trim(result);
+}
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
@@ -128,47 +145,6 @@
return true;
}
-static bool tombstoned_connect(pid_t pid, unique_fd* tombstoned_socket, unique_fd* output_fd) {
- unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
- ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
- if (sockfd == -1) {
- PLOG(ERROR) << "failed to connect to tombstoned";
- return false;
- }
-
- TombstonedCrashPacket packet = {};
- packet.packet_type = CrashPacketType::kDumpRequest;
- packet.packet.dump_request.pid = pid;
- if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
- PLOG(ERROR) << "failed to write DumpRequest packet";
- return false;
- }
-
- unique_fd tmp_output_fd;
- ssize_t rc = recv_fd(sockfd, &packet, sizeof(packet), &tmp_output_fd);
- if (rc == -1) {
- PLOG(ERROR) << "failed to read response to DumpRequest packet";
- return false;
- } else if (rc != sizeof(packet)) {
- LOG(ERROR) << "read DumpRequest response packet of incorrect length (expected "
- << sizeof(packet) << ", got " << rc << ")";
- return false;
- }
-
- *tombstoned_socket = std::move(sockfd);
- *output_fd = std::move(tmp_output_fd);
- return true;
-}
-
-static bool tombstoned_notify_completion(int tombstoned_socket) {
- TombstonedCrashPacket packet = {};
- packet.packet_type = CrashPacketType::kCompletedDump;
- if (TEMP_FAILURE_RETRY(write(tombstoned_socket, &packet, sizeof(packet))) != sizeof(packet)) {
- return false;
- }
- return true;
-}
-
static void signal_handler(int) {
// We can't log easily, because the heap might be corrupt.
// Just die and let the surrounding log context explain things.
@@ -188,7 +164,12 @@
}
}
- dprintf(output_fd.get(), "crash_dump failed to dump process %d: %s\n", target, abort_msg);
+ dprintf(output_fd.get(), "crash_dump failed to dump process");
+ if (target != 1) {
+ dprintf(output_fd.get(), " %d: %s\n", target, abort_msg);
+ } else {
+ dprintf(output_fd.get(), ": %s\n", abort_msg);
+ }
_exit(1);
}
@@ -211,17 +192,6 @@
}
}
-static void check_process(int proc_fd, pid_t expected_pid) {
- android::procinfo::ProcessInfo proc_info;
- if (!android::procinfo::GetProcessInfoFromProcPidFd(proc_fd, &proc_info)) {
- LOG(FATAL) << "failed to fetch process info";
- }
-
- if (proc_info.pid != expected_pid) {
- LOG(FATAL) << "pid mismatch: expected " << expected_pid << ", actual " << proc_info.ppid;
- }
-}
-
int main(int argc, char** argv) {
pid_t target = getppid();
bool tombstoned_connected = false;
@@ -238,20 +208,25 @@
action.sa_handler = signal_handler;
debuggerd_register_handlers(&action);
- if (argc != 2) {
+ if (argc != 3) {
return 1;
}
pid_t main_tid;
-
- if (target == 1) {
- LOG(FATAL) << "target died before we could attach";
- }
+ pid_t pseudothread_tid;
if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) {
LOG(FATAL) << "invalid main tid: " << argv[1];
}
+ if (!android::base::ParseInt(argv[2], &pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) {
+ LOG(FATAL) << "invalid pseudothread tid: " << argv[2];
+ }
+
+ if (target == 1) {
+ LOG(FATAL) << "target died before we could attach (received main tid = " << main_tid << ")";
+ }
+
android::procinfo::ProcessInfo target_info;
if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) {
LOG(FATAL) << "failed to fetch process info for target " << main_tid;
@@ -269,6 +244,11 @@
PLOG(FATAL) << "failed to open " << target_proc_path;
}
+ // Make sure our parent didn't die.
+ if (getppid() != target) {
+ PLOG(FATAL) << "parent died";
+ }
+
// Reparent ourselves to init, so that the signal handler can waitpid on the
// original process to avoid leaving a zombie for non-fatal dumps.
pid_t forkpid = fork();
@@ -281,19 +261,56 @@
// Die if we take too long.
alarm(20);
- check_process(target_proc_fd, target);
-
std::string attach_error;
+
+ // Seize the main thread.
if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
LOG(FATAL) << attach_error;
}
- check_process(target_proc_fd, target);
+ // Seize the siblings.
+ std::map<pid_t, std::string> threads;
+ {
+ std::set<pid_t> siblings;
+ if (!android::procinfo::GetProcessTids(target, &siblings)) {
+ PLOG(FATAL) << "failed to get process siblings";
+ }
+
+ // but not the already attached main thread.
+ siblings.erase(main_tid);
+ // or the handler pseudothread.
+ siblings.erase(pseudothread_tid);
+
+ for (pid_t sibling_tid : siblings) {
+ if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
+ LOG(WARNING) << attach_error;
+ } else {
+ threads.emplace(sibling_tid, get_thread_name(sibling_tid));
+ }
+ }
+ }
+
+ // Collect the backtrace map, open files, and process/thread names, while we still have caps.
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
+ if (!backtrace_map) {
+ LOG(FATAL) << "failed to create backtrace map";
+ }
+
+ // Collect the list of open files.
+ OpenFilesList open_files;
+ populate_open_files_list(target, &open_files);
+
+ std::string process_name = get_process_name(main_tid);
+ threads.emplace(main_tid, get_thread_name(main_tid));
+
+ // Drop our capabilities now that we've attached to the threads we care about.
+ drop_capabilities();
LOG(INFO) << "obtaining output fd from tombstoned";
tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd);
// Write a '\1' to stdout to tell the crashing process to resume.
+ // It also restores the value of PR_SET_DUMPABLE at this point.
if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) {
PLOG(ERROR) << "failed to communicate to target process";
}
@@ -339,48 +356,14 @@
abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr);
}
- // Now that we have the signal that kicked things off, attach all of the
- // sibling threads, and then proceed.
- std::set<pid_t> attached_siblings;
- {
- std::set<pid_t> siblings;
- if (!android::procinfo::GetProcessTids(target, &siblings)) {
- PLOG(FATAL) << "failed to get process siblings";
- }
- siblings.erase(main_tid);
-
- for (pid_t sibling_tid : siblings) {
- if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
- LOG(WARNING) << attach_error;
- } else {
- attached_siblings.insert(sibling_tid);
- }
- }
- }
-
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
- if (!backtrace_map) {
- LOG(FATAL) << "failed to create backtrace map";
- }
-
- // Drop our capabilities now that we've attached to the threads we care about.
- drop_capabilities();
-
- check_process(target_proc_fd, target);
-
// TODO: Use seccomp to lock ourselves down.
std::string amfd_data;
-
if (backtrace) {
- dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0);
+ dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
} else {
- // Collect the list of open files.
- OpenFilesList open_files;
- populate_open_files_list(target, &open_files);
-
- engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid,
- attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
+ engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
+ process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
}
// We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 4727894..f73f672 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -48,6 +48,7 @@
shared_libs: [
"libbase",
"liblog",
+ "libseccomp_policy",
],
multilib: {
lib32: {
@@ -69,6 +70,7 @@
"libdebuggerd_handler",
"libbase",
"liblog",
+ "libseccomp_policy",
],
multilib: {
lib32: {
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 64a38dd..6970201 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -26,12 +26,15 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/prctl.h>
#include <unistd.h>
// We test both kinds of logging.
#include <android-base/logging.h>
#include <log/log.h>
+#include "seccomp_policy.h"
+
#if defined(STATIC_CRASHER)
#include "debuggerd/handler.h"
#endif
@@ -188,6 +191,9 @@
fprintf(stderr, " fprintf-NULL pass a null pointer to fprintf\n");
fprintf(stderr, " readdir-NULL pass a null pointer to readdir\n");
fprintf(stderr, " strlen-NULL pass a null pointer to strlen\n");
+ fprintf(stderr, " pthread_join-NULL pass a null pointer to pthread_join\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " no_new_privs set PR_SET_NO_NEW_PRIVS and then abort\n");
fprintf(stderr, "\n");
fprintf(stderr, "prefix any of the above with 'thread-' to run on a new thread\n");
fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
@@ -255,6 +261,8 @@
readdir_null();
} else if (!strcasecmp(arg, "strlen-NULL")) {
return strlen_null();
+ } else if (!strcasecmp(arg, "pthread_join-NULL")) {
+ return pthread_join(0, nullptr);
} else if (!strcasecmp(arg, "heap-usage")) {
abuse_heap();
} else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
@@ -263,6 +271,7 @@
munmap(map, sizeof(int));
map[0] = '8';
} else if (!strcasecmp(arg, "seccomp")) {
+ set_seccomp_filter();
syscall(99999);
#if defined(__arm__)
} else if (!strcasecmp(arg, "kuser_helper_version")) {
@@ -276,6 +285,12 @@
} else if (!strcasecmp(arg, "kuser_cmpxchg64")) {
return __kuser_cmpxchg64(0, 0, 0);
#endif
+ } else if (!strcasecmp(arg, "no_new_privs")) {
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1) != 0) {
+ fprintf(stderr, "prctl(PR_SET_NO_NEW_PRIVS, 1) failed: %s\n", strerror(errno));
+ return EXIT_SUCCESS;
+ }
+ abort();
} else {
return usage();
}
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 0c5d3cf..492e9f0 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -34,6 +34,8 @@
static void usage(int exit_code) {
fprintf(stderr, "usage: debuggerd [-b] PID\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "-b, --backtrace just a backtrace rather than a full tombstone\n");
_exit(exit_code);
}
@@ -56,7 +58,8 @@
int main(int argc, char* argv[]) {
if (argc <= 1) usage(0);
if (argc > 3) usage(1);
- if (argc == 3 && strcmp(argv[1], "-b") != 0) usage(1);
+ if (argc == 3 && strcmp(argv[1], "-b") != 0 && strcmp(argv[1], "--backtrace") != 0) usage(1);
+ bool backtrace_only = argc == 3;
pid_t pid;
if (!android::base::ParseInt(argv[argc - 1], &pid, 1, std::numeric_limits<pid_t>::max())) {
@@ -69,9 +72,8 @@
}
std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
- bool backtrace = argc == 3;
if (!debuggerd_trigger_dump(pid, std::move(pipewrite),
- backtrace ? kDebuggerdBacktrace : kDebuggerdTombstone, 0)) {
+ backtrace_only ? kDebuggerdBacktrace : kDebuggerdTombstone, 0)) {
redirect_thread.join();
errx(1, "failed to dump process %d", pid);
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index e7503e9..1a27f3f 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -17,6 +17,7 @@
#include <err.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/types.h>
@@ -24,6 +25,8 @@
#include <regex>
#include <thread>
+#include <android/set_abort_message.h>
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
@@ -40,10 +43,8 @@
using android::base::unique_fd;
#if defined(__LP64__)
-#define CRASHER_PATH "/system/xbin/crasher64"
#define ARCH_SUFFIX "64"
#else
-#define CRASHER_PATH "/system/xbin/crasher"
#define ARCH_SUFFIX ""
#endif
@@ -179,23 +180,14 @@
if (crasher_pid == -1) {
FAIL() << "fork failed: " << strerror(errno);
} else if (crasher_pid == 0) {
- unique_fd devnull(open("/dev/null", O_WRONLY));
- dup2(crasher_read_pipe.get(), STDIN_FILENO);
- dup2(devnull.get(), STDOUT_FILENO);
- dup2(devnull.get(), STDERR_FILENO);
+ char dummy;
+ crasher_pipe.reset();
+ TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
function();
_exit(0);
}
}
-void CrasherTest::StartCrasher(const std::string& crash_type) {
- std::string type = "wait-" + crash_type;
- StartProcess([type]() {
- execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
- err(1, "exec failed");
- });
-}
-
void CrasherTest::FinishCrasher() {
if (crasher_pipe == -1) {
FAIL() << "crasher pipe uninitialized";
@@ -216,7 +208,9 @@
FAIL() << "failed to wait for crasher: " << strerror(errno);
}
- if (!WIFSIGNALED(status)) {
+ if (WIFEXITED(status)) {
+ FAIL() << "crasher failed to exec: " << strerror(WEXITSTATUS(status));
+ } else if (!WIFSIGNALED(status)) {
FAIL() << "crasher didn't terminate via a signal";
}
ASSERT_EQ(signo, WTERMSIG(status));
@@ -247,7 +241,10 @@
TEST_F(CrasherTest, smoke) {
int intercept_result;
unique_fd output_fd;
- StartCrasher("SIGSEGV");
+ StartProcess([]() {
+ *reinterpret_cast<volatile char*>(0xdead) = '1';
+ });
+
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGSEGV);
@@ -263,7 +260,9 @@
TEST_F(CrasherTest, abort) {
int intercept_result;
unique_fd output_fd;
- StartCrasher("abort");
+ StartProcess([]() {
+ abort();
+ });
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGABRT);
@@ -279,7 +278,9 @@
TEST_F(CrasherTest, signal) {
int intercept_result;
unique_fd output_fd;
- StartCrasher("abort");
+ StartProcess([]() {
+ abort();
+ });
StartIntercept(&output_fd);
// Wait for a bit, or we might end up killing the process before the signal
@@ -301,7 +302,10 @@
TEST_F(CrasherTest, abort_message) {
int intercept_result;
unique_fd output_fd;
- StartCrasher("smash-stack");
+ StartProcess([]() {
+ android_set_abort_message("abort message goes here");
+ abort();
+ });
StartIntercept(&output_fd);
FinishCrasher();
AssertDeath(SIGABRT);
@@ -311,13 +315,15 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
- ASSERT_MATCH(result, R"(Abort message: 'stack corruption detected \(-fstack-protector\)')");
+ ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
}
TEST_F(CrasherTest, intercept_timeout) {
int intercept_result;
unique_fd output_fd;
- StartCrasher("abort");
+ StartProcess([]() {
+ abort();
+ });
StartIntercept(&output_fd);
// Don't let crasher finish until we timeout.
@@ -336,7 +342,9 @@
}
sleep(1);
- StartCrasher("abort");
+ StartProcess([]() {
+ abort();
+ });
FinishCrasher();
int status;
@@ -355,7 +363,9 @@
FAIL() << "failed to enable wait_for_gdb";
}
- StartCrasher("abort");
+ StartProcess([]() {
+ abort();
+ });
ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
AssertDeath(SIGSEGV);
}
@@ -364,7 +374,10 @@
std::string result;
int intercept_result;
unique_fd output_fd;
- StartCrasher("abort");
+
+ StartProcess([]() {
+ abort();
+ });
StartIntercept(&output_fd);
std::this_thread::sleep_for(500ms);
@@ -390,18 +403,108 @@
}
TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
+ int intercept_result;
+ unique_fd output_fd;
StartProcess([]() {
prctl(PR_SET_DUMPABLE, 0);
- volatile char* null = static_cast<char*>(nullptr);
- *null = '\0';
+ abort();
});
- AssertDeath(SIGSEGV);
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
}
-TEST_F(CrasherTest, PR_SET_DUMPABLE_0_raise) {
+TEST_F(CrasherTest, capabilities) {
+ ASSERT_EQ(0U, getuid()) << "capability test requires root";
+
StartProcess([]() {
- prctl(PR_SET_DUMPABLE, 0);
- raise(SIGUSR1);
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
+ err(1, "failed to set PR_SET_KEEPCAPS");
+ }
+
+ if (setresuid(1, 1, 1) != 0) {
+ err(1, "setresuid failed");
+ }
+
+ __user_cap_header_struct capheader;
+ __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ // Turn on every third capability.
+ static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
+ for (int i = 0; i < CAP_LAST_CAP; i += 3) {
+ capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
+ capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
+ }
+
+ // Make sure CAP_SYS_PTRACE is off.
+ capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
+ capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
+
+ if (capset(&capheader, &capdata[0]) != 0) {
+ err(1, "capset failed");
+ }
+
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
+ err(1, "failed to drop ambient capabilities");
+ }
+
+ raise(SIGSYS);
});
- AssertDeath(SIGUSR1);
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSYS);
+
+ std::string result;
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
+}
+
+TEST(crash_dump, zombie) {
+ pid_t forkpid = fork();
+
+ int pipefd[2];
+ ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+
+ pid_t rc;
+ int status;
+
+ if (forkpid == 0) {
+ errno = 0;
+ rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
+ if (rc != -1 || errno != ECHILD) {
+ errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+ }
+
+ raise(DEBUGGER_SIGNAL);
+
+ errno = 0;
+ rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+ if (rc != -1 || errno != ECHILD) {
+ errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+ }
+ _exit(0);
+ } else {
+ rc = waitpid(forkpid, &status, 0);
+ ASSERT_EQ(forkpid, rc);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
+ }
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
new file mode 100644
index 0000000..5c6c59c
--- /dev/null
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+#include <syscall.h>
+#include <unistd.h>
+
+#include <atomic>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+
+#include "debuggerd/handler.h"
+#include "debuggerd/tombstoned.h"
+#include "debuggerd/util.h"
+
+#include "backtrace.h"
+#include "tombstone.h"
+
+#include "private/libc_logging.h"
+
+using android::base::unique_fd;
+
+extern "C" void __linker_enable_fallback_allocator();
+extern "C" void __linker_disable_fallback_allocator();
+
+// This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
+// uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
+// the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
+//
+// This isn't the default method of dumping because it can fail in cases such as address space
+// exhaustion.
+static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
+ __linker_enable_fallback_allocator();
+ dump_backtrace_ucontext(output_fd, ucontext);
+ __linker_disable_fallback_allocator();
+}
+
+static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
+ void* abort_message) {
+ __linker_enable_fallback_allocator();
+ engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
+ ucontext);
+ __linker_disable_fallback_allocator();
+}
+
+static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
+ pid_t current_tid = gettid();
+ char buf[BUFSIZ];
+ snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
+ DIR* dir = opendir(buf);
+
+ if (!dir) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
+ return;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ char* end;
+ long tid = strtol(ent->d_name, &end, 10);
+ if (end == ent->d_name || *end != '\0') {
+ continue;
+ }
+
+ if (tid != current_tid) {
+ callback(tid, output_fd);
+ }
+ }
+ closedir(dir);
+}
+
+static bool forward_output(int src_fd, int dst_fd) {
+ // Make sure the thread actually got the signal.
+ struct pollfd pfd = {
+ .fd = src_fd, .events = POLLIN,
+ };
+
+ // Wait for up to a second for output to start flowing.
+ if (poll(&pfd, 1, 1000) != 1) {
+ return false;
+ }
+
+ while (true) {
+ char buf[512];
+ ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
+ if (rc == 0) {
+ return true;
+ } else if (rc < 0) {
+ return false;
+ }
+
+ if (!android::base::WriteFully(dst_fd, buf, rc)) {
+ // We failed to write to tombstoned, but there's not much we can do.
+ // Keep reading from src_fd to keep things going.
+ continue;
+ }
+ }
+}
+
+static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
+ static std::atomic<int> trace_output_fd(-1);
+
+ if (info->si_value.sival_int == ~0) {
+ // Asked to dump by the original signal recipient.
+ debuggerd_fallback_trace(trace_output_fd, ucontext);
+
+ int tmp = trace_output_fd.load();
+ trace_output_fd.store(-1);
+ close(tmp);
+ return;
+ }
+
+ // Only allow one thread to perform a trace at a time.
+ static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_mutex_trylock(&trace_mutex);
+ if (ret != 0) {
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s", strerror(ret));
+ return;
+ }
+
+ // Fetch output fd from tombstoned.
+ unique_fd tombstone_socket, output_fd;
+ if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd)) {
+ goto exit;
+ }
+
+ dump_backtrace_header(output_fd.get());
+
+ // Dump our own stack.
+ debuggerd_fallback_trace(output_fd.get(), ucontext);
+
+ // Send a signal to all of our siblings, asking them to dump their stack.
+ iterate_siblings(
+ [](pid_t tid, int output_fd) {
+ // Use a pipe, to be able to detect situations where the thread gracefully exits before
+ // receiving our signal.
+ unique_fd pipe_read, pipe_write;
+ if (!Pipe(&pipe_read, &pipe_write)) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", strerror(errno));
+ return false;
+ }
+
+ trace_output_fd.store(pipe_write.get());
+
+ siginfo_t siginfo = {};
+ siginfo.si_code = SI_QUEUE;
+ siginfo.si_value.sival_int = ~0;
+ siginfo.si_pid = getpid();
+ siginfo.si_uid = getuid();
+
+ if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", tid,
+ strerror(errno));
+ return false;
+ }
+
+ bool success = forward_output(pipe_read.get(), output_fd);
+ if (success) {
+ // The signaled thread has closed trace_output_fd already.
+ (void)pipe_write.release();
+ } else {
+ trace_output_fd.store(-1);
+ }
+
+ return true;
+ },
+ output_fd.get());
+
+ dump_backtrace_footer(output_fd.get());
+ tombstoned_notify_completion(tombstone_socket.get());
+
+exit:
+ pthread_mutex_unlock(&trace_mutex);
+}
+
+static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
+ // Only allow one thread to handle a crash.
+ static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_mutex_lock(&crash_mutex);
+ if (ret != 0) {
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
+ return;
+ }
+
+ unique_fd tombstone_socket, output_fd;
+ bool tombstoned_connected = tombstoned_connect(getpid(), &tombstone_socket, &output_fd);
+ debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
+ if (tombstoned_connected) {
+ tombstoned_notify_completion(tombstone_socket.get());
+ }
+}
+
+extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
+ void* abort_message) {
+ if (info->si_signo == DEBUGGER_SIGNAL) {
+ return trace_handler(info, ucontext);
+ } else {
+ return crash_handler(info, ucontext, abort_message);
+ }
+}
diff --git a/debuggerd/handler/debuggerd_fallback_nop.cpp b/debuggerd/handler/debuggerd_fallback_nop.cpp
new file mode 100644
index 0000000..331301f
--- /dev/null
+++ b/debuggerd/handler/debuggerd_fallback_nop.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern "C" void debuggerd_fallback_handler(struct siginfo_t*, struct ucontext_t*, void*) {
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 38a7be3..cf24d57 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -62,6 +62,21 @@
#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
+class ErrnoRestorer {
+ public:
+ ErrnoRestorer() : saved_errno_(errno) {
+ }
+
+ ~ErrnoRestorer() {
+ errno = saved_errno_;
+ }
+
+ private:
+ int saved_errno_;
+};
+
+extern "C" void debuggerd_fallback_handler(siginfo_t*, ucontext_t*, void*);
+
static debuggerd_callbacks_t g_callbacks;
// Mutex to ensure only one crashing thread dumps itself.
@@ -81,7 +96,7 @@
va_start(args, fmt);
char buf[4096];
- vsnprintf(buf, sizeof(buf), fmt, args);
+ __libc_format_buffer_va_list(buf, sizeof(buf), fmt, args);
fatal("%s: %s", buf, strerror(err));
}
@@ -174,6 +189,41 @@
return (old_action.sa_flags & SA_SIGINFO) != 0;
}
+static void raise_caps() {
+ // Raise CapInh to match CapPrm, so that we can set the ambient bits.
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ if (capget(&capheader, &capdata[0]) == -1) {
+ fatal_errno("capget failed");
+ }
+
+ if (capdata[0].permitted != capdata[0].inheritable ||
+ capdata[1].permitted != capdata[1].inheritable) {
+ capdata[0].inheritable = capdata[0].permitted;
+ capdata[1].inheritable = capdata[1].permitted;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno));
+ }
+ }
+
+ // Set the ambient capability bits so that crash_dump gets all of our caps and can ptrace us.
+ uint64_t capmask = capdata[0].inheritable;
+ capmask |= static_cast<uint64_t>(capdata[1].inheritable) << 32;
+ for (unsigned long i = 0; i < 64; ++i) {
+ if (capmask & (1ULL << i)) {
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) != 0) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to raise ambient capability %lu: %s",
+ i, strerror(errno));
+ }
+ }
+ }
+}
+
struct debugger_thread_info {
bool crash_dump_started;
pid_t crashing_tid;
@@ -217,14 +267,14 @@
close(pipefds[0]);
close(pipefds[1]);
- // Set all of the ambient capability bits we can, so that crash_dump can ptrace us.
- for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) != -1; ++i) {
- prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
- }
+ raise_caps();
- char buf[10];
- snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);
- execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr);
+ char main_tid[10];
+ char pseudothread_tid[10];
+ __libc_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid);
+ __libc_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid);
+
+ execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr);
fatal_errno("exec failed");
} else {
@@ -249,7 +299,7 @@
// Don't leave a zombie child.
int status;
- if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) {
+ if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
__libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
strerror(errno));
} else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
@@ -286,20 +336,14 @@
fatal_errno("failed to resend signal during crash");
}
}
-
- if (info->si_signo == DEBUGGER_SIGNAL) {
- pthread_mutex_unlock(&crash_mutex);
- }
}
// Handler that does crash dumping by forking and doing the processing in the child.
// Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump.
-static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
- int ret = pthread_mutex_lock(&crash_mutex);
- if (ret != 0) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
- return;
- }
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* context) {
+ // Make sure we don't change the value of errno, in case a signal comes in between the process
+ // making a syscall and checking errno.
+ ErrnoRestorer restorer;
// It's possible somebody cleared the SA_SIGINFO flag, which would mean
// our "info" arg holds an undefined value.
@@ -322,20 +366,29 @@
// check to allow all si_code values in calls coming from inside the house.
}
- log_signal_summary(signal_number, info);
-
- if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
- // The process has NO_NEW_PRIVS enabled, so we can't transition to the crash_dump context.
- __libc_format_log(ANDROID_LOG_INFO, "libc",
- "Suppressing debuggerd output because prctl(PR_GET_NO_NEW_PRIVS)==1");
- resend_signal(info, false);
- return;
- }
-
void* abort_message = nullptr;
if (g_callbacks.get_abort_message) {
abort_message = g_callbacks.get_abort_message();
}
+
+ if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
+ // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely,
+ // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
+ // ANR trace.
+ debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message);
+ resend_signal(info, false);
+ return;
+ }
+
+ // Only allow one thread to handle a signal at a time.
+ int ret = pthread_mutex_lock(&crash_mutex);
+ if (ret != 0) {
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
+ return;
+ }
+
+ log_signal_summary(signal_number, info);
+
// Populate si_value with the abort message address, if found.
if (abort_message) {
info->si_value.sival_ptr = abort_message;
@@ -349,6 +402,12 @@
.info = info
};
+ // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
+ int orig_dumpable = prctl(PR_GET_DUMPABLE);
+ if (prctl(PR_SET_DUMPABLE, 1) != 0) {
+ fatal_errno("failed to set dumpable");
+ }
+
// Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
pid_t child_pid =
clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
@@ -364,6 +423,11 @@
// and then wait for it to finish.
__futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr);
+ // Restore PR_SET_DUMPABLE to its original value.
+ if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) {
+ fatal_errno("failed to restore dumpable");
+ }
+
// Signals can either be fatal or nonfatal.
// For fatal signals, crash_dump will PTRACE_CONT us with the signal we
// crashed with, so that processes using waitpid on us will see that we
@@ -375,6 +439,11 @@
}
resend_signal(info, thread_info.crash_dump_started);
+ if (info->si_signo == DEBUGGER_SIGNAL) {
+ // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
+ // starting to dump right before our death.
+ pthread_mutex_unlock(&crash_mutex);
+ }
}
void debuggerd_init(debuggerd_callbacks_t* callbacks) {
diff --git a/debuggerd/include/debuggerd/tombstoned.h b/debuggerd/include/debuggerd/tombstoned.h
new file mode 100644
index 0000000..d158d50
--- /dev/null
+++ b/debuggerd/include/debuggerd/tombstoned.h
@@ -0,0 +1,26 @@
+#pragma once
+
+/*
+ * Copyright 2017, 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 <sys/types.h>
+
+#include <android-base/unique_fd.h>
+
+bool tombstoned_connect(pid_t pid, android::base::unique_fd* tombstoned_socket,
+ android::base::unique_fd* output_fd);
+
+bool tombstoned_notify_completion(int tombstoned_socket);
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 0664442..334d97f 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -38,18 +38,7 @@
#include "utility.h"
-static void dump_process_header(log_t* log, pid_t pid) {
- char path[PATH_MAX];
- char procnamebuf[1024];
- char* procname = NULL;
- FILE* fp;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
+static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
@@ -57,8 +46,8 @@
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
- if (procname) {
- _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
+ if (process_name) {
+ _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
@@ -67,25 +56,13 @@
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) {
- char path[PATH_MAX];
- char threadnamebuf[1024];
- char* threadname = NULL;
- FILE* fp;
+static void log_thread_name(log_t* log, pid_t tid, const char* thread_name) {
+ _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread_name, tid);
+}
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
- }
-
- _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
+ const std::string& thread_name) {
+ log_thread_name(log, tid, thread_name.c_str());
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
if (backtrace->Unwind(0)) {
@@ -96,22 +73,65 @@
}
}
-void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, std::string* amfd_data) {
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, std::string* amfd_data) {
log_t log;
log.tfd = fd;
log.amfd_data = amfd_data;
- dump_process_header(&log, pid);
- dump_thread(&log, map, pid, tid);
+ dump_process_header(&log, pid, process_name.c_str());
+ dump_thread(&log, map, pid, tid, threads.find(tid)->second.c_str());
- for (pid_t sibling : siblings) {
- dump_thread(&log, map, pid, sibling);
+ for (const auto& it : threads) {
+ pid_t thread_tid = it.first;
+ const std::string& thread_name = it.second;
+ if (thread_tid != tid) {
+ dump_thread(&log, map, pid, thread_tid, thread_name.c_str());
+ }
}
dump_process_footer(&log, pid);
}
+void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext) {
+ pid_t pid = getpid();
+ pid_t tid = gettid();
+
+ log_t log;
+ log.tfd = output_fd;
+ log.amfd_data = nullptr;
+
+ char thread_name[16];
+ read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
+ log_thread_name(&log, tid, thread_name);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
+ if (backtrace->Unwind(0, ucontext)) {
+ dump_backtrace_to_log(backtrace.get(), &log, " ");
+ } else {
+ ALOGE("Unwind failed: tid = %d: %s", tid,
+ backtrace->GetErrorString(backtrace->GetError()).c_str());
+ }
+}
+
+void dump_backtrace_header(int output_fd) {
+ log_t log;
+ log.tfd = output_fd;
+ log.amfd_data = nullptr;
+
+ char process_name[128];
+ read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+ dump_process_header(&log, getpid(), process_name);
+}
+
+void dump_backtrace_footer(int output_fd) {
+ log_t log;
+ log.tfd = output_fd;
+ log.amfd_data = nullptr;
+
+ dump_process_footer(&log, getpid());
+}
+
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
diff --git a/debuggerd/libdebuggerd/include/backtrace.h b/debuggerd/libdebuggerd/include/backtrace.h
index acd5eaa..fe738f1 100644
--- a/debuggerd/libdebuggerd/include/backtrace.h
+++ b/debuggerd/libdebuggerd/include/backtrace.h
@@ -18,8 +18,9 @@
#define _DEBUGGERD_BACKTRACE_H
#include <sys/types.h>
+#include <sys/ucontext.h>
-#include <set>
+#include <map>
#include <string>
#include "utility.h"
@@ -29,10 +30,14 @@
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
-void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, std::string* amfd_data);
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, std::string* amfd_data);
/* Dumps the backtrace in the backtrace data structure to the log. */
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
+void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext);
+void dump_backtrace_header(int output_fd);
+void dump_backtrace_footer(int output_fd);
+
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h
index 4ff24af..79743b6 100644
--- a/debuggerd/libdebuggerd/include/tombstone.h
+++ b/debuggerd/libdebuggerd/include/tombstone.h
@@ -20,7 +20,8 @@
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
-#include <set>
+
+#include <map>
#include <string>
#include "open_files_list.h"
@@ -34,9 +35,19 @@
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
std::string* amfd_data);
+void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+ ucontext_t* ucontext);
+
+// Compatibility shim.
+__attribute__((__unused__))
+static void engrave_tombstone_ucontext(int tombstone_fd, pid_t, pid_t, uintptr_t abort_msg_address,
+ siginfo_t* siginfo, ucontext_t* ucontext) {
+ engrave_tombstone_ucontext(tombstone_fd, abort_msg_address, siginfo, ucontext);
+}
+
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/utility.h
index bbc4546..e5e5106 100644
--- a/debuggerd/libdebuggerd/include/utility.h
+++ b/debuggerd/libdebuggerd/include/utility.h
@@ -83,4 +83,6 @@
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
+void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
+
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/test/sys/system_properties.h b/debuggerd/libdebuggerd/test/sys/system_properties.h
index 9d44345..1f4f58a 100644
--- a/debuggerd/libdebuggerd/test/sys/system_properties.h
+++ b/debuggerd/libdebuggerd/test/sys/system_properties.h
@@ -32,7 +32,6 @@
// This is just enough to get the property code to compile on
// the host.
-#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ac2c0b6..c23da44 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -32,8 +32,10 @@
#include <memory>
#include <string>
-#include <android/log.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/log.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <cutils/properties.h>
@@ -214,20 +216,15 @@
cause = "call to kuser_cmpxchg64";
}
} else if (si.si_signo == SIGSYS && si.si_code == SYS_SECCOMP) {
- cause = StringPrintf("seccomp prevented call to disallowed system call %d", si.si_syscall);
+ cause = StringPrintf("seccomp prevented call to disallowed %s system call %d",
+ ABI_STRING, si.si_syscall);
}
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, pid_t tid) {
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
- ALOGE("cannot get siginfo: %s\n", strerror(errno));
- return;
- }
-
+static void dump_signal_info(log_t* log, const siginfo_t* siginfo) {
+ const siginfo_t& si = *siginfo;
char addr_desc[32]; // ", fault addr 0x1234"
if (signal_has_si_addr(si.si_signo, si.si_code)) {
snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
@@ -241,41 +238,27 @@
dump_probable_cause(log, si);
}
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
- char path[64];
- char threadnamebuf[1024];
- char* threadname = nullptr;
- FILE *fp;
-
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
+static void dump_signal_info(log_t* log, pid_t tid) {
+ siginfo_t si;
+ memset(&si, 0, sizeof(si));
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
+ ALOGE("cannot get siginfo: %s\n", strerror(errno));
+ return;
}
+
+ dump_signal_info(log, &si);
+}
+
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, const char* process_name,
+ const char* thread_name) {
// Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
- static const char logd[] = "logd";
- if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1)
- && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
+ // TODO: Why is this controlled by thread name?
+ if (strcmp(thread_name, "logd") == 0 || strncmp(thread_name, "logd.", 4) == 0) {
log->should_retrieve_logcat = false;
}
- char procnamebuf[1024];
- char* procname = nullptr;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
- threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, thread_name,
+ process_name);
}
static void dump_stack_segment(
@@ -487,13 +470,14 @@
}
}
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map,
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::string& thread_name, BacktraceMap* map,
uintptr_t abort_msg_address, bool primary_thread) {
log->current_tid = tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
}
- dump_thread_info(log, pid, tid);
+ dump_thread_info(log, pid, tid, process_name.c_str(), thread_name.c_str());
dump_signal_info(log, tid);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
@@ -648,9 +632,9 @@
}
// Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
+static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid,
+ pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "0");
@@ -659,19 +643,24 @@
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(log);
- dump_thread(log, pid, tid, map, abort_msg_address, true);
+ dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
if (want_logs) {
dump_logs(log, pid, 5);
}
- if (!siblings.empty()) {
- for (pid_t sibling : siblings) {
- dump_thread(log, pid, sibling, map, 0, false);
+ for (const auto& it : threads) {
+ pid_t thread_tid = it.first;
+ const std::string& thread_name = it.second;
+
+ if (thread_tid != tid) {
+ dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
}
}
- _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
- dump_open_files_list_to_log(open_files, log, " ");
+ if (open_files) {
+ _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
+ dump_open_files_list_to_log(*open_files, log, " ");
+ }
if (want_logs) {
dump_logs(log, pid, 0);
@@ -731,20 +720,44 @@
return fd;
}
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
-
- if (tombstone_fd < 0) {
- ALOGE("debuggerd: skipping tombstone write, nothing to do.\n");
- return;
- }
-
log.tfd = tombstone_fd;
log.amfd_data = amfd_data;
- dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address);
+ dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
+}
+
+void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+ ucontext_t* ucontext) {
+ pid_t pid = getpid();
+ pid_t tid = gettid();
+
+ log_t log;
+ log.current_tid = tid;
+ log.crashed_tid = tid;
+ log.tfd = tombstone_fd;
+ log.amfd_data = nullptr;
+
+ char thread_name[16];
+ char process_name[128];
+
+ read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
+ read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+
+ dump_thread_info(&log, pid, tid, thread_name, process_name);
+ dump_signal_info(&log, siginfo);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
+ dump_abort_message(backtrace.get(), &log, abort_msg_address);
+ // TODO: Dump registers from the ucontext.
+ if (backtrace->Unwind(0, ucontext)) {
+ dump_backtrace_and_stack(backtrace.get(), &log);
+ } else {
+ ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
+ }
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 57209aa..22fde5e 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -28,6 +28,7 @@
#include <string>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
@@ -41,6 +42,7 @@
return false;
}
+__attribute__((__weak__, visibility("default")))
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
bool write_to_tombstone = (log->tfd != -1);
bool write_to_logcat = is_allowed_in_logcat(ltype)
@@ -201,3 +203,20 @@
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}
+
+void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
+ android::base::unique_fd fd(open(path, O_RDONLY));
+ if (fd != -1) {
+ int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
+ if (rc != -1) {
+ buf[rc] = '\0';
+
+ // Trim trailing newlines.
+ if (rc > 0 && buf[rc - 1] == '\n') {
+ buf[rc - 1] = '\0';
+ }
+ return;
+ }
+ }
+ strcpy(buf, default_value);
+}
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 8705ece..6754508 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -34,6 +34,7 @@
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
+#include "debuggerd/handler.h"
#include "debuggerd/protocol.h"
#include "debuggerd/util.h"
@@ -116,7 +117,7 @@
}
result.reset(
- openat(tombstone_directory_fd, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0700));
+ openat(tombstone_directory_fd, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND | O_CLOEXEC, 0640));
if (result == -1) {
PLOG(FATAL) << "failed to create tombstone at " << kTombstoneDirectory << buf;
}
@@ -254,6 +255,16 @@
}
int main(int, char* []) {
+ umask(0137);
+
+ // Don't try to connect to ourselves if we crash.
+ struct sigaction action = {};
+ action.sa_handler = [](int signal) {
+ LOG(ERROR) << "received fatal signal " << signal;
+ _exit(1);
+ };
+ debuggerd_register_handlers(&action);
+
tombstone_directory_fd = open(kTombstoneDirectory, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (tombstone_directory_fd == -1) {
PLOG(FATAL) << "failed to open tombstone directory";
diff --git a/debuggerd/tombstoned_client.cpp b/debuggerd/tombstoned_client.cpp
new file mode 100644
index 0000000..03b4a20
--- /dev/null
+++ b/debuggerd/tombstoned_client.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017, 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 "debuggerd/tombstoned.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <utility>
+
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+
+#include "debuggerd/protocol.h"
+#include "debuggerd/util.h"
+#include "private/libc_logging.h"
+
+using android::base::unique_fd;
+
+bool tombstoned_connect(pid_t pid, unique_fd* tombstoned_socket, unique_fd* output_fd) {
+ unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
+ ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+ if (sockfd == -1) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to tombstoned: %s",
+ strerror(errno));
+ return false;
+ }
+
+ TombstonedCrashPacket packet = {};
+ packet.packet_type = CrashPacketType::kDumpRequest;
+ packet.packet.dump_request.pid = pid;
+ if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to write DumpRequest packet: %s",
+ strerror(errno));
+ return false;
+ }
+
+ unique_fd tmp_output_fd;
+ ssize_t rc = recv_fd(sockfd, &packet, sizeof(packet), &tmp_output_fd);
+ if (rc == -1) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc",
+ "failed to read response to DumpRequest packet: %s", strerror(errno));
+ return false;
+ } else if (rc != sizeof(packet)) {
+ __libc_format_log(
+ ANDROID_LOG_ERROR, "libc",
+ "received DumpRequest response packet of incorrect length (expected %zu, got %zd)",
+ sizeof(packet), rc);
+ return false;
+ }
+
+ // Make the fd O_APPEND so that our output is guaranteed to be at the end of a file.
+ // (This also makes selinux rules consistent, because selinux distinguishes between writing to
+ // a regular fd, and writing to an fd with O_APPEND).
+ int flags = fcntl(tmp_output_fd.get(), F_GETFL);
+ if (fcntl(tmp_output_fd.get(), F_SETFL, flags | O_APPEND) != 0) {
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "failed to set output fd flags: %s",
+ strerror(errno));
+ }
+
+ *tombstoned_socket = std::move(sockfd);
+ *output_fd = std::move(tmp_output_fd);
+ return true;
+}
+
+bool tombstoned_notify_completion(int tombstoned_socket) {
+ TombstonedCrashPacket packet = {};
+ packet.packet_type = CrashPacketType::kCompletedDump;
+ if (TEMP_FAILURE_RETRY(write(tombstoned_socket, &packet, sizeof(packet))) != sizeof(packet)) {
+ return false;
+ }
+ return true;
+}
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index 738abdf..4c015d7 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -22,8 +22,13 @@
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
+#include <debuggerd/protocol.h>
-ssize_t send_fd(int sockfd, const void* data, size_t len, android::base::unique_fd fd) {
+#include "private/libc_logging.h"
+
+using android::base::unique_fd;
+
+ssize_t send_fd(int sockfd, const void* data, size_t len, unique_fd fd) {
char cmsg_buf[CMSG_SPACE(sizeof(int))];
iovec iov = { .iov_base = const_cast<void*>(data), .iov_len = len };
@@ -39,8 +44,7 @@
return TEMP_FAILURE_RETRY(sendmsg(sockfd, &msg, 0));
}
-ssize_t recv_fd(int sockfd, void* _Nonnull data, size_t len,
- android::base::unique_fd* _Nullable out_fd) {
+ssize_t recv_fd(int sockfd, void* _Nonnull data, size_t len, unique_fd* _Nullable out_fd) {
char cmsg_buf[CMSG_SPACE(sizeof(int))];
iovec iov = { .iov_base = const_cast<void*>(data), .iov_len = len };
@@ -61,7 +65,7 @@
return -1;
}
- android::base::unique_fd fd;
+ unique_fd fd;
bool received_fd = msg.msg_controllen == sizeof(cmsg_buf);
if (received_fd) {
fd.reset(*reinterpret_cast<int*>(CMSG_DATA(cmsg)));
@@ -85,7 +89,7 @@
return result;
}
-bool Pipe(android::base::unique_fd* read, android::base::unique_fd* write) {
+bool Pipe(unique_fd* read, unique_fd* write) {
int pipefds[2];
if (pipe(pipefds) != 0) {
return false;
diff --git a/demangle/.clang-format b/demangle/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/demangle/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/demangle/Android.bp b/demangle/Android.bp
new file mode 100644
index 0000000..96ab57d
--- /dev/null
+++ b/demangle/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_defaults {
+ name: "libdemangle_defaults",
+
+ host_supported: true,
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+cc_library {
+ name: "libdemangle",
+ defaults: ["libdemangle_defaults"],
+
+ srcs: [
+ "Demangler.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_binary {
+ name: "demangle",
+ defaults: ["libdemangle_defaults"],
+ srcs: ["demangle.cpp"],
+ host_supported: true,
+
+ shared_libs: ["libdemangle"],
+}
+
+//-------------------------------------------------------------------------
+// Unit Tests
+//-------------------------------------------------------------------------
+cc_test {
+ name: "libdemangle_test",
+ defaults: ["libdemangle_defaults"],
+
+ srcs: [
+ "DemangleTest.cpp",
+ ],
+
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+
+ shared_libs: [
+ "libdemangle",
+ ],
+}
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
new file mode 100644
index 0000000..fb68119
--- /dev/null
+++ b/demangle/DemangleTest.cpp
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2017 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 <stdlib.h>
+
+#include <gtest/gtest.h>
+
+#include <demangle.h>
+
+#include "Demangler.h"
+
+TEST(DemangleTest, VoidArgumentTest) {
+ Demangler demangler;
+
+ ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
+ ASSERT_EQ("func(void&)", demangler.Parse("_ZN4funcERv"));
+ ASSERT_EQ("func(void, void)", demangler.Parse("_ZN4funcEvv"));
+ ASSERT_EQ("func(void*)", demangler.Parse("_ZN4funcEPv"));
+ ASSERT_EQ("func(void const)", demangler.Parse("_ZN4funcEKv"));
+ ASSERT_EQ("func(void volatile)", demangler.Parse("_ZN4funcEVv"));
+}
+
+TEST(DemangleTest, ArgumentModifiers) {
+ Demangler demangler;
+
+ ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc"));
+ ASSERT_EQ("func(char*)", demangler.Parse("_ZN4funcEPc"));
+ ASSERT_EQ("func(char**)", demangler.Parse("_ZN4funcEPPc"));
+ ASSERT_EQ("func(char***)", demangler.Parse("_ZN4funcEPPPc"));
+ ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERc"));
+ ASSERT_EQ("func(char*&)", demangler.Parse("_ZN4funcERPc"));
+ ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERRc"));
+ ASSERT_EQ("func(char*&*)", demangler.Parse("_ZN4funcEPRPc"));
+ ASSERT_EQ("func(char**&)", demangler.Parse("_ZN4funcERRPPc"));
+ ASSERT_EQ("func(char const)", demangler.Parse("_ZN4funcEKc"));
+ ASSERT_EQ("func(char volatile)", demangler.Parse("_ZN4funcEVc"));
+ ASSERT_EQ("func(char volatile const)", demangler.Parse("_ZN4funcEKVc"));
+ ASSERT_EQ("func(char const volatile)", demangler.Parse("_ZN4funcEVKc"));
+ ASSERT_EQ("func(char const* volatile&)", demangler.Parse("_ZN4funcERVPKc"));
+ ASSERT_EQ("func(void, char, short)", demangler.Parse("_ZN4funcEvcs"));
+ ASSERT_EQ("func(void*, char&, short&*)", demangler.Parse("_ZN4funcEPvRcPRs"));
+}
+
+TEST(DemangleTest, FunctionModifiers) {
+ Demangler demangler;
+
+ ASSERT_EQ("func() const", demangler.Parse("_ZNK4funcEv"));
+ ASSERT_EQ("func() volatile", demangler.Parse("_ZNV4funcEv"));
+ ASSERT_EQ("func() volatile const", demangler.Parse("_ZNKV4funcEv"));
+ ASSERT_EQ("func() const volatile", demangler.Parse("_ZNVK4funcEv"));
+}
+
+TEST(DemangleTest, MultiplePartsInName) {
+ Demangler demangler;
+
+ ASSERT_EQ("one::two()", demangler.Parse("_ZN3one3twoEv"));
+ ASSERT_EQ("one::two::three()", demangler.Parse("_ZN3one3two5threeEv"));
+ ASSERT_EQ("one::two::three::four()", demangler.Parse("_ZN3one3two5three4fourEv"));
+ ASSERT_EQ("one::two::three::four::five()", demangler.Parse("_ZN3one3two5three4four4fiveEv"));
+ ASSERT_EQ("one(two::three::four::five)", demangler.Parse("_ZN3oneEN3two5three4four4fiveE"));
+}
+
+TEST(DemangleTest, AnonymousNamespace) {
+ Demangler demangler;
+
+ ASSERT_EQ("(anonymous namespace)::two()", demangler.Parse("_ZN12_GLOBAL__N_13twoEv"));
+ ASSERT_EQ("one::two((anonymous namespace))", demangler.Parse("_ZN3one3twoE12_GLOBAL__N_1"));
+}
+
+TEST(DemangleTest, DestructorValues) {
+ Demangler demangler;
+
+ ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD0Ev"));
+ ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD1Ev"));
+ ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD2Ev"));
+ ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD5Ev"));
+ ASSERT_EQ("one::two::three::~three()", demangler.Parse("_ZN3one3two5threeD0Ev"));
+
+ ASSERT_EQ("_ZN3one3twoD3Ev", demangler.Parse("_ZN3one3twoD3Ev"));
+ ASSERT_EQ("_ZN3one3twoD4Ev", demangler.Parse("_ZN3one3twoD4Ev"));
+ ASSERT_EQ("_ZN3one3twoD6Ev", demangler.Parse("_ZN3one3twoD6Ev"));
+ ASSERT_EQ("_ZN3one3twoD7Ev", demangler.Parse("_ZN3one3twoD7Ev"));
+ ASSERT_EQ("_ZN3one3twoD8Ev", demangler.Parse("_ZN3one3twoD8Ev"));
+ ASSERT_EQ("_ZN3one3twoD9Ev", demangler.Parse("_ZN3one3twoD9Ev"));
+
+ ASSERT_EQ("one::two<three::four>::~two()", demangler.Parse("_ZN3one3twoIN5three4fourEED2Ev"));
+}
+
+TEST(DemangleTest, ConstructorValues) {
+ Demangler demangler;
+
+ ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC1Ev"));
+ ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC2Ev"));
+ ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC3Ev"));
+ ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC5Ev"));
+ ASSERT_EQ("one::two::three::three()", demangler.Parse("_ZN3one3two5threeC1Ev"));
+
+ ASSERT_EQ("_ZN3one3twoC0Ev", demangler.Parse("_ZN3one3twoC0Ev"));
+ ASSERT_EQ("_ZN3one3twoC4Ev", demangler.Parse("_ZN3one3twoC4Ev"));
+ ASSERT_EQ("_ZN3one3twoC6Ev", demangler.Parse("_ZN3one3twoC6Ev"));
+ ASSERT_EQ("_ZN3one3twoC7Ev", demangler.Parse("_ZN3one3twoC7Ev"));
+ ASSERT_EQ("_ZN3one3twoC8Ev", demangler.Parse("_ZN3one3twoC8Ev"));
+ ASSERT_EQ("_ZN3one3twoC9Ev", demangler.Parse("_ZN3one3twoC9Ev"));
+
+ ASSERT_EQ("one::two<three::four>::two()", demangler.Parse("_ZN3one3twoIN5three4fourEEC1Ev"));
+}
+
+TEST(DemangleTest, OperatorValues) {
+ Demangler demangler;
+
+ ASSERT_EQ("operator&&()", demangler.Parse("_Zaav"));
+ ASSERT_EQ("operator&()", demangler.Parse("_Zadv"));
+ ASSERT_EQ("operator&()", demangler.Parse("_Zanv"));
+ ASSERT_EQ("operator&=()", demangler.Parse("_ZaNv"));
+ ASSERT_EQ("operator=()", demangler.Parse("_ZaSv"));
+ ASSERT_EQ("operator()()", demangler.Parse("_Zclv"));
+ ASSERT_EQ("operator,()", demangler.Parse("_Zcmv"));
+ ASSERT_EQ("operator~()", demangler.Parse("_Zcov"));
+ ASSERT_EQ("operator delete[]()", demangler.Parse("_Zdav"));
+ ASSERT_EQ("operator*()", demangler.Parse("_Zdev"));
+ ASSERT_EQ("operator delete()", demangler.Parse("_Zdlv"));
+ ASSERT_EQ("operator/()", demangler.Parse("_Zdvv"));
+ ASSERT_EQ("operator/=()", demangler.Parse("_ZdVv"));
+ ASSERT_EQ("operator^()", demangler.Parse("_Zeov"));
+ ASSERT_EQ("operator^=()", demangler.Parse("_ZeOv"));
+ ASSERT_EQ("operator==()", demangler.Parse("_Zeqv"));
+ ASSERT_EQ("operator>=()", demangler.Parse("_Zgev"));
+ ASSERT_EQ("operator>()", demangler.Parse("_Zgtv"));
+ ASSERT_EQ("operator[]()", demangler.Parse("_Zixv"));
+ ASSERT_EQ("operator<=()", demangler.Parse("_Zlev"));
+ ASSERT_EQ("operator<<()", demangler.Parse("_Zlsv"));
+ ASSERT_EQ("operator<<=()", demangler.Parse("_ZlSv"));
+ ASSERT_EQ("operator<()", demangler.Parse("_Zltv"));
+ ASSERT_EQ("operator-()", demangler.Parse("_Zmiv"));
+ ASSERT_EQ("operator-=()", demangler.Parse("_ZmIv"));
+ ASSERT_EQ("operator*()", demangler.Parse("_Zmlv"));
+ ASSERT_EQ("operator*=()", demangler.Parse("_ZmLv"));
+ ASSERT_EQ("operator--()", demangler.Parse("_Zmmv"));
+ ASSERT_EQ("operator new[]()", demangler.Parse("_Znav"));
+ ASSERT_EQ("operator!=()", demangler.Parse("_Znev"));
+ ASSERT_EQ("operator-()", demangler.Parse("_Zngv"));
+ ASSERT_EQ("operator!()", demangler.Parse("_Zntv"));
+ ASSERT_EQ("operator new()", demangler.Parse("_Znwv"));
+ ASSERT_EQ("operator||()", demangler.Parse("_Zoov"));
+ ASSERT_EQ("operator|()", demangler.Parse("_Zorv"));
+ ASSERT_EQ("operator|=()", demangler.Parse("_ZoRv"));
+ ASSERT_EQ("operator->*()", demangler.Parse("_Zpmv"));
+ ASSERT_EQ("operator+()", demangler.Parse("_Zplv"));
+ ASSERT_EQ("operator+=()", demangler.Parse("_ZpLv"));
+ ASSERT_EQ("operator++()", demangler.Parse("_Zppv"));
+ ASSERT_EQ("operator+()", demangler.Parse("_Zpsv"));
+ ASSERT_EQ("operator->()", demangler.Parse("_Zptv"));
+ ASSERT_EQ("operator?()", demangler.Parse("_Zquv"));
+ ASSERT_EQ("operator%()", demangler.Parse("_Zrmv"));
+ ASSERT_EQ("operator%=()", demangler.Parse("_ZrMv"));
+ ASSERT_EQ("operator>>()", demangler.Parse("_Zrsv"));
+ ASSERT_EQ("operator>>=()", demangler.Parse("_ZrSv"));
+
+ // Spot check using an operator as part of function name.
+ ASSERT_EQ("operator&&()", demangler.Parse("_ZNaaEv"));
+ ASSERT_EQ("operator++()", demangler.Parse("_ZNppEv"));
+ ASSERT_EQ("one::operator++()", demangler.Parse("_ZN3oneppEv"));
+
+ // Spot check using an operator in an argument name.
+ ASSERT_EQ("operator+(operator|=)", demangler.Parse("_ZNpsENoRE"));
+ ASSERT_EQ("operator==()", demangler.Parse("_Zeqv"));
+ ASSERT_EQ("one(arg1::operator|=, arg2::operator==)",
+ demangler.Parse("_ZN3oneEN4arg1oREN4arg2eqE"));
+}
+
+TEST(DemangleTest, FunctionStartsWithNumber) {
+ Demangler demangler;
+
+ ASSERT_EQ("value(char, int)", demangler.Parse("_Z5valueci"));
+ ASSERT_EQ("abcdefjklmn(signed char)", demangler.Parse("_Z11abcdefjklmna"));
+ ASSERT_EQ("value(one, signed char)", demangler.Parse("_Z5value3onea"));
+}
+
+TEST(DemangleTest, StdTypes) {
+ Demangler demangler;
+
+ ASSERT_EQ("std::one", demangler.Parse("_ZNSt3oneE"));
+ ASSERT_EQ("std::one(std::two)", demangler.Parse("_ZNSt3oneESt3two"));
+ ASSERT_EQ("std::std::one(std::two)", demangler.Parse("_ZNStSt3oneESt3two"));
+ ASSERT_EQ("std()", demangler.Parse("_ZNStEv"));
+ ASSERT_EQ("one::std::std::two::~two(one::std::std::two)",
+ demangler.Parse("_ZN3oneStSt3twoD0ES0_"));
+
+ ASSERT_EQ("std::allocator", demangler.Parse("_ZNSaE"));
+ ASSERT_EQ("std::basic_string", demangler.Parse("_ZNSbE"));
+ ASSERT_EQ("_ZNScE", demangler.Parse("_ZNScE"));
+ ASSERT_EQ("std::iostream", demangler.Parse("_ZNSdE"));
+ ASSERT_EQ("_ZNSeE", demangler.Parse("_ZNSeE"));
+ ASSERT_EQ("_ZNSfE", demangler.Parse("_ZNSfE"));
+ ASSERT_EQ("_ZNSgE", demangler.Parse("_ZNSgE"));
+ ASSERT_EQ("_ZNShE", demangler.Parse("_ZNShE"));
+ ASSERT_EQ("std::istream", demangler.Parse("_ZNSiE"));
+ ASSERT_EQ("_ZNSjE", demangler.Parse("_ZNSjE"));
+ ASSERT_EQ("_ZNSkE", demangler.Parse("_ZNSkE"));
+ ASSERT_EQ("_ZNSlE", demangler.Parse("_ZNSlE"));
+ ASSERT_EQ("_ZNSmE", demangler.Parse("_ZNSmE"));
+ ASSERT_EQ("_ZNSnE", demangler.Parse("_ZNSnE"));
+ ASSERT_EQ("std::ostream", demangler.Parse("_ZNSoE"));
+ ASSERT_EQ("_ZNSpE", demangler.Parse("_ZNSpE"));
+ ASSERT_EQ("_ZNSqE", demangler.Parse("_ZNSqE"));
+ ASSERT_EQ("_ZNSrE", demangler.Parse("_ZNSrE"));
+ ASSERT_EQ("std::string", demangler.Parse("_ZNSsE"));
+ ASSERT_EQ("_ZNSuE", demangler.Parse("_ZNSuE"));
+ ASSERT_EQ("_ZNSvE", demangler.Parse("_ZNSvE"));
+ ASSERT_EQ("_ZNSwE", demangler.Parse("_ZNSwE"));
+ ASSERT_EQ("_ZNSxE", demangler.Parse("_ZNSxE"));
+ ASSERT_EQ("_ZNSyE", demangler.Parse("_ZNSyE"));
+ ASSERT_EQ("_ZNSzE", demangler.Parse("_ZNSzE"));
+}
+
+TEST(DemangleTest, SingleLetterArguments) {
+ Demangler demangler;
+
+ ASSERT_EQ("func(signed char)", demangler.Parse("_ZN4funcEa"));
+ ASSERT_EQ("func(bool)", demangler.Parse("_ZN4funcEb"));
+ ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc"));
+ ASSERT_EQ("func(double)", demangler.Parse("_ZN4funcEd"));
+ ASSERT_EQ("func(long double)", demangler.Parse("_ZN4funcEe"));
+ ASSERT_EQ("func(float)", demangler.Parse("_ZN4funcEf"));
+ ASSERT_EQ("func(__float128)", demangler.Parse("_ZN4funcEg"));
+ ASSERT_EQ("func(unsigned char)", demangler.Parse("_ZN4funcEh"));
+ ASSERT_EQ("func(int)", demangler.Parse("_ZN4funcEi"));
+ ASSERT_EQ("func(unsigned int)", demangler.Parse("_ZN4funcEj"));
+ ASSERT_EQ("_ZN4funcEk", demangler.Parse("_ZN4funcEk"));
+ ASSERT_EQ("func(long)", demangler.Parse("_ZN4funcEl"));
+ ASSERT_EQ("func(unsigned long)", demangler.Parse("_ZN4funcEm"));
+ ASSERT_EQ("func(__int128)", demangler.Parse("_ZN4funcEn"));
+ ASSERT_EQ("func(unsigned __int128)", demangler.Parse("_ZN4funcEo"));
+ ASSERT_EQ("_ZN4funcEp", demangler.Parse("_ZN4funcEp"));
+ ASSERT_EQ("_ZN4funcEq", demangler.Parse("_ZN4funcEq"));
+ ASSERT_EQ("_ZN4funcEr", demangler.Parse("_ZN4funcEr"));
+ ASSERT_EQ("func(short)", demangler.Parse("_ZN4funcEs"));
+ ASSERT_EQ("func(unsigned short)", demangler.Parse("_ZN4funcEt"));
+ ASSERT_EQ("_ZN4funcEu", demangler.Parse("_ZN4funcEu"));
+ ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
+ ASSERT_EQ("func(wchar_t)", demangler.Parse("_ZN4funcEw"));
+ ASSERT_EQ("func(long long)", demangler.Parse("_ZN4funcEx"));
+ ASSERT_EQ("func(unsigned long long)", demangler.Parse("_ZN4funcEy"));
+ ASSERT_EQ("func(...)", demangler.Parse("_ZN4funcEz"));
+}
+
+TEST(DemangleTest, DArguments) {
+ Demangler demangler;
+
+ ASSERT_EQ("func(auto)", demangler.Parse("_ZN4funcEDa"));
+ ASSERT_EQ("_ZN4funcEDb", demangler.Parse("_ZN4funcEDb"));
+ ASSERT_EQ("_ZN4funcEDc", demangler.Parse("_ZN4funcEDc"));
+ ASSERT_EQ("func(decimal64)", demangler.Parse("_ZN4funcEDd"));
+ ASSERT_EQ("func(decimal128)", demangler.Parse("_ZN4funcEDe"));
+ ASSERT_EQ("func(decimal32)", demangler.Parse("_ZN4funcEDf"));
+ ASSERT_EQ("_ZN4funcEDg", demangler.Parse("_ZN4funcEDg"));
+ ASSERT_EQ("func(half)", demangler.Parse("_ZN4funcEDh"));
+ ASSERT_EQ("func(char32_t)", demangler.Parse("_ZN4funcEDi"));
+ ASSERT_EQ("_ZN4funcEDj", demangler.Parse("_ZN4funcEDj"));
+ ASSERT_EQ("_ZN4funcEDk", demangler.Parse("_ZN4funcEDk"));
+ ASSERT_EQ("_ZN4funcEDl", demangler.Parse("_ZN4funcEDl"));
+ ASSERT_EQ("_ZN4funcEDm", demangler.Parse("_ZN4funcEDm"));
+ ASSERT_EQ("func(decltype(nullptr))", demangler.Parse("_ZN4funcEDn"));
+ ASSERT_EQ("_ZN4funcEDo", demangler.Parse("_ZN4funcEDo"));
+ ASSERT_EQ("_ZN4funcEDp", demangler.Parse("_ZN4funcEDp"));
+ ASSERT_EQ("_ZN4funcEDq", demangler.Parse("_ZN4funcEDq"));
+ ASSERT_EQ("_ZN4funcEDr", demangler.Parse("_ZN4funcEDr"));
+ ASSERT_EQ("func(char16_t)", demangler.Parse("_ZN4funcEDs"));
+ ASSERT_EQ("_ZN4funcEDt", demangler.Parse("_ZN4funcEDt"));
+ ASSERT_EQ("_ZN4funcEDu", demangler.Parse("_ZN4funcEDu"));
+ ASSERT_EQ("_ZN4funcEDv", demangler.Parse("_ZN4funcEDv"));
+ ASSERT_EQ("_ZN4funcEDw", demangler.Parse("_ZN4funcEDw"));
+ ASSERT_EQ("_ZN4funcEDx", demangler.Parse("_ZN4funcEDx"));
+ ASSERT_EQ("_ZN4funcEDy", demangler.Parse("_ZN4funcEDy"));
+ ASSERT_EQ("_ZN4funcEDz", demangler.Parse("_ZN4funcEDz"));
+}
+
+TEST(DemangleTest, FunctionArguments) {
+ Demangler demangler;
+
+ ASSERT_EQ("func(char ())", demangler.Parse("_ZN4funcEFcvE"));
+ ASSERT_EQ("func(char (*)())", demangler.Parse("_ZN4funcEPFcvE"));
+ ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE"));
+ ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE"));
+ ASSERT_EQ("func(char (*&)())", demangler.Parse("_ZN4funcERPFcvE"));
+ ASSERT_EQ("func(char (*)(int) const)", demangler.Parse("_ZN4funcEPKFciE"));
+ ASSERT_EQ("func(char (&)() const)", demangler.Parse("_ZN4funcERKFcvE"));
+ ASSERT_EQ("func(char (&)() volatile)", demangler.Parse("_ZN4funcERVFcvE"));
+ ASSERT_EQ("func(char (&)() volatile const)", demangler.Parse("_ZN4funcERKVFcvE"));
+ ASSERT_EQ("func(char (&)() const volatile)", demangler.Parse("_ZN4funcERVKFcvE"));
+ ASSERT_EQ("func(char (&)(int, signed char) const)", demangler.Parse("_ZN4funcERKFciaE"));
+ ASSERT_EQ("fake(char (&* volatile const)(void, void, signed char), signed char)",
+ demangler.Parse("_ZN4fakeEKVPRFcvvaEa"));
+}
+
+TEST(DemangleTest, TemplateFunction) {
+ Demangler demangler;
+
+ ASSERT_EQ("one<char>", demangler.Parse("_ZN3oneIcEE"));
+ ASSERT_EQ("one<void>", demangler.Parse("_ZN3oneIvEE"));
+ ASSERT_EQ("one<void*>", demangler.Parse("_ZN3oneIPvEE"));
+ ASSERT_EQ("one<void const>", demangler.Parse("_ZN3oneIKvEE"));
+ ASSERT_EQ("one<char, int, bool>", demangler.Parse("_ZN3oneIcibEE"));
+ ASSERT_EQ("one::two<three>", demangler.Parse("_ZN3one3twoIN5threeEEE"));
+ ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_ZN3oneIciN3two5threeEEE"));
+ // Template within templates.
+ ASSERT_EQ("one::two<three<char, int>>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE"));
+ ASSERT_EQ("one::two<three<char, four<int>>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE"));
+}
+
+TEST(DemangleTest, TemplateArguments) {
+ Demangler demangler;
+
+ ASSERT_EQ("one(two<char>)", demangler.Parse("_ZN3oneE3twoIcE"));
+ ASSERT_EQ("one(two<char, void>)", demangler.Parse("_ZN3oneE3twoIcvE"));
+ ASSERT_EQ("one(two<char, void, three<four, int>>)",
+ demangler.Parse("_ZN3oneE3twoIcv5threeI4fouriEE"));
+}
+
+TEST(DemangleTest, SubstitutionUnderscore) {
+ Demangler demangler;
+
+ ASSERT_EQ("a::a", demangler.Parse("_ZN1aS_E"));
+ ASSERT_EQ("one::one", demangler.Parse("_ZN3oneS_E"));
+ ASSERT_EQ("one::two::one", demangler.Parse("_ZN3one3twoS_E"));
+ ASSERT_EQ("one::two::three::one", demangler.Parse("_ZN3one3two5threeS_E"));
+ ASSERT_EQ("one::two(one)", demangler.Parse("_ZN3one3twoES_"));
+ ASSERT_EQ("one::two(three::one)", demangler.Parse("_ZN3one3twoEN5threeS_E"));
+
+ // Special case that St is part of the saved value used in the substitution.
+ ASSERT_EQ("std::one::std::one", demangler.Parse("_ZNSt3oneS_E"));
+
+ // Multiple substitutions in the string.
+ ASSERT_EQ("one::one(one, one)", demangler.Parse("_ZN3oneS_ES_S_"));
+ ASSERT_EQ("std::one::two::std::one(std::one)", demangler.Parse("_ZNSt3one3twoS_ES_"));
+}
+
+TEST(DemangleTest, SubstitutionByNumber) {
+ Demangler demangler;
+
+ // Basic substitution.
+ ASSERT_EQ("a::b::c(a::b)", demangler.Parse("_ZN1a1b1cES0_"));
+ ASSERT_EQ("_ZN1a1b1cES1_", demangler.Parse("_ZN1a1b1cES1_"));
+ ASSERT_EQ("a::b::c::d(a::b::c)", demangler.Parse("_ZN1a1b1c1dES1_"));
+ ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l)",
+ demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESA_"));
+ ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l::m)",
+ demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESB_"));
+
+ // Verify argument modifiers are included in substitution list.
+ ASSERT_EQ("one::two(char&* volatile const, char&)", demangler.Parse("_ZN3one3twoEKVPRcS0_"));
+ ASSERT_EQ("one::two(char&* volatile const, char&*)", demangler.Parse("_ZN3one3twoEKVPRcS1_"));
+ ASSERT_EQ("one::two(char&* volatile const, char&* volatile const)",
+ demangler.Parse("_ZN3one3twoEKVPRcS2_"));
+ ASSERT_EQ("one::two(int&* volatile* const, int&)", demangler.Parse("_ZN3one3twoEKPVPRiS0_"));
+ ASSERT_EQ("one::two(int&* volatile const, int&*)", demangler.Parse("_ZN3one3twoEKVPRiS1_"));
+ ASSERT_EQ("one::two(int&* volatile const, int&* volatile const)",
+ demangler.Parse("_ZN3one3twoEKVPRiS2_"));
+
+ // Verify Constructor/Destructor does properly save from function name.
+ ASSERT_EQ("_ZN1a1bES0_", demangler.Parse("_ZN1a1bES0_"));
+ ASSERT_EQ("a::b::b(a::b)", demangler.Parse("_ZN1a1bC1ES0_"));
+ ASSERT_EQ("a::b::~b(a::b)", demangler.Parse("_ZN1a1bD0ES0_"));
+
+ // Make sure substitution values are not saved.
+ ASSERT_EQ("a::b::b(a::b, char*, char*)", demangler.Parse("_ZN1a1bC1ES0_PcS1_"));
+}
+
+TEST(DemangleTest, ComplexSubstitution) {
+ Demangler demangler;
+
+ ASSERT_EQ("one::two<one::three>::two()", demangler.Parse("_ZN3one3twoINS_5threeEEC1Ev"));
+ ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)",
+ demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE"));
+ ASSERT_EQ("one::two::three::four<one::five>::~four(one::two*)",
+ demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS0_"));
+ ASSERT_EQ("one::two::three::four<one::five>::~four(one::two::three*)",
+ demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS1_"));
+ ASSERT_EQ("one::two::three::four<one::five>::~four(one::two::three::four*)",
+ demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS2_"));
+ ASSERT_EQ("one::two::three::four<one::five>::~four(one::five*)",
+ demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_"));
+}
+
+TEST(DemangleTest, StringTooLong) {
+ Demangler demangler;
+
+ ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE",
+ demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 10));
+ ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE",
+ demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 30));
+ ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)",
+ demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 31));
+
+ // Check the length check only occurs after the two letter value
+ // has been processed.
+ ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 15));
+ ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 14));
+ ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 13));
+ ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12));
+}
+
+TEST(DemangleTest, demangle) {
+ std::string str;
+
+ str = demangle("_ZN1a1b1cES0_");
+ ASSERT_EQ("a::b::c(a::b)", str);
+
+ str = demangle("_");
+ ASSERT_EQ("_", str);
+
+ str = demangle("_Z");
+ ASSERT_EQ("_Z", str);
+
+ str = demangle("_Za");
+ ASSERT_EQ("_Za", str);
+
+ str = demangle("_Zaa");
+ ASSERT_EQ("operator&&", str);
+
+ str = demangle("Xa");
+ ASSERT_EQ("Xa", str);
+}
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
new file mode 100644
index 0000000..77cfd3b
--- /dev/null
+++ b/demangle/Demangler.cpp
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2017 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 <assert.h>
+
+#include <cctype>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "Demangler.h"
+
+constexpr const char* Demangler::kTypes[];
+constexpr const char* Demangler::kDTypes[];
+constexpr const char* Demangler::kSTypes[];
+
+void Demangler::Save(const std::string& str, bool is_name) {
+ saves_.push_back(str);
+ last_save_name_ = is_name;
+}
+
+std::string Demangler::GetArgumentsString() {
+ size_t num_args = cur_state_.args.size();
+ std::string arg_str;
+ if (num_args > 0) {
+ arg_str = cur_state_.args[0];
+ for (size_t i = 1; i < num_args; i++) {
+ arg_str += ", " + cur_state_.args[i];
+ }
+ }
+ return arg_str;
+}
+
+const char* Demangler::AppendOperatorString(const char* name) {
+ const char* oper = nullptr;
+ switch (*name) {
+ case 'a':
+ name++;
+ switch (*name) {
+ case 'a':
+ oper = "operator&&";
+ break;
+ case 'd':
+ case 'n':
+ oper = "operator&";
+ break;
+ case 'N':
+ oper = "operator&=";
+ break;
+ case 'S':
+ oper = "operator=";
+ break;
+ }
+ break;
+ case 'c':
+ name++;
+ switch (*name) {
+ case 'l':
+ oper = "operator()";
+ break;
+ case 'm':
+ oper = "operator,";
+ break;
+ case 'o':
+ oper = "operator~";
+ break;
+ }
+ break;
+ case 'd':
+ name++;
+ switch (*name) {
+ case 'a':
+ oper = "operator delete[]";
+ break;
+ case 'e':
+ oper = "operator*";
+ break;
+ case 'l':
+ oper = "operator delete";
+ break;
+ case 'v':
+ oper = "operator/";
+ break;
+ case 'V':
+ oper = "operator/=";
+ break;
+ }
+ break;
+ case 'e':
+ name++;
+ switch (*name) {
+ case 'o':
+ oper = "operator^";
+ break;
+ case 'O':
+ oper = "operator^=";
+ break;
+ case 'q':
+ oper = "operator==";
+ break;
+ }
+ break;
+ case 'g':
+ name++;
+ switch (*name) {
+ case 'e':
+ oper = "operator>=";
+ break;
+ case 't':
+ oper = "operator>";
+ break;
+ }
+ break;
+ case 'i':
+ name++;
+ switch (*name) {
+ case 'x':
+ oper = "operator[]";
+ break;
+ }
+ break;
+ case 'l':
+ name++;
+ switch (*name) {
+ case 'e':
+ oper = "operator<=";
+ break;
+ case 's':
+ oper = "operator<<";
+ break;
+ case 'S':
+ oper = "operator<<=";
+ break;
+ case 't':
+ oper = "operator<";
+ break;
+ }
+ break;
+ case 'm':
+ name++;
+ switch (*name) {
+ case 'i':
+ oper = "operator-";
+ break;
+ case 'I':
+ oper = "operator-=";
+ break;
+ case 'l':
+ oper = "operator*";
+ break;
+ case 'L':
+ oper = "operator*=";
+ break;
+ case 'm':
+ oper = "operator--";
+ break;
+ }
+ break;
+ case 'n':
+ name++;
+ switch (*name) {
+ case 'a':
+ oper = "operator new[]";
+ break;
+ case 'e':
+ oper = "operator!=";
+ break;
+ case 'g':
+ oper = "operator-";
+ break;
+ case 't':
+ oper = "operator!";
+ break;
+ case 'w':
+ oper = "operator new";
+ break;
+ }
+ break;
+ case 'o':
+ name++;
+ switch (*name) {
+ case 'o':
+ oper = "operator||";
+ break;
+ case 'r':
+ oper = "operator|";
+ break;
+ case 'R':
+ oper = "operator|=";
+ break;
+ }
+ break;
+ case 'p':
+ name++;
+ switch (*name) {
+ case 'm':
+ oper = "operator->*";
+ break;
+ case 'l':
+ oper = "operator+";
+ break;
+ case 'L':
+ oper = "operator+=";
+ break;
+ case 'p':
+ oper = "operator++";
+ break;
+ case 's':
+ oper = "operator+";
+ break;
+ case 't':
+ oper = "operator->";
+ break;
+ }
+ break;
+ case 'q':
+ name++;
+ switch (*name) {
+ case 'u':
+ oper = "operator?";
+ break;
+ }
+ break;
+ case 'r':
+ name++;
+ switch (*name) {
+ case 'm':
+ oper = "operator%";
+ break;
+ case 'M':
+ oper = "operator%=";
+ break;
+ case 's':
+ oper = "operator>>";
+ break;
+ case 'S':
+ oper = "operator>>=";
+ break;
+ }
+ break;
+ }
+ if (oper == nullptr) {
+ return nullptr;
+ }
+ AppendCurrent(oper);
+ cur_state_.last_save = oper;
+ return name + 1;
+}
+
+const char* Demangler::GetStringFromLength(const char* name, std::string* str) {
+ assert(std::isdigit(*name));
+
+ size_t length = *name - '0';
+ name++;
+ while (*name != '\0' && std::isdigit(*name)) {
+ length = length * 10 + *name - '0';
+ name++;
+ }
+
+ std::string read_str;
+ while (*name != '\0' && length != 0) {
+ read_str += *name;
+ name++;
+ length--;
+ }
+ if (length != 0) {
+ return nullptr;
+ }
+ // Special replacement of _GLOBAL__N_1 to (anonymous namespace).
+ if (read_str == "_GLOBAL__N_1") {
+ *str += "(anonymous namespace)";
+ } else {
+ *str += read_str;
+ }
+ return name;
+}
+
+void Demangler::AppendCurrent(const std::string& str) {
+ if (!cur_state_.str.empty()) {
+ cur_state_.str += "::";
+ }
+ cur_state_.str += str;
+}
+
+void Demangler::AppendCurrent(const char* str) {
+ if (!cur_state_.str.empty()) {
+ cur_state_.str += "::";
+ }
+ cur_state_.str += str;
+}
+
+const char* Demangler::ParseS(const char* name) {
+ if (std::islower(*name)) {
+ const char* type = kSTypes[*name - 'a'];
+ if (type == nullptr) {
+ return nullptr;
+ }
+ AppendCurrent(type);
+ return name + 1;
+ }
+
+ if (saves_.empty()) {
+ return nullptr;
+ }
+
+ if (*name == '_') {
+ last_save_name_ = false;
+ AppendCurrent(saves_[0]);
+ return name + 1;
+ }
+
+ bool isdigit = std::isdigit(*name);
+ if (!isdigit && !std::isupper(*name)) {
+ return nullptr;
+ }
+
+ size_t index;
+ if (isdigit) {
+ index = *name - '0' + 1;
+ } else {
+ index = *name - 'A' + 11;
+ }
+ name++;
+ if (*name != '_') {
+ return nullptr;
+ }
+
+ if (index >= saves_.size()) {
+ return nullptr;
+ }
+
+ last_save_name_ = false;
+ AppendCurrent(saves_[index]);
+ return name + 1;
+}
+
+const char* Demangler::ParseFunctionName(const char* name) {
+ if (*name == 'E') {
+ if (parse_funcs_.empty()) {
+ return nullptr;
+ }
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+
+ // Remove the last saved part so that the full function name is not saved.
+ // But only if the last save was not something like a substitution.
+ if (!saves_.empty() && last_save_name_) {
+ saves_.pop_back();
+ }
+
+ function_name_ = cur_state_.str;
+ while (!cur_state_.suffixes.empty()) {
+ function_suffix_ += cur_state_.suffixes.back();
+ cur_state_.suffixes.pop_back();
+ }
+ cur_state_.Clear();
+
+ return name + 1;
+ }
+
+ return ParseComplexString(name);
+}
+
+const char* Demangler::ParseComplexArgument(const char* name) {
+ if (*name == 'E') {
+ if (parse_funcs_.empty()) {
+ return nullptr;
+ }
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+
+ AppendArgument(cur_state_.str);
+ cur_state_.str.clear();
+
+ return name + 1;
+ }
+
+ return ParseComplexString(name);
+}
+
+void Demangler::FinalizeTemplate() {
+ std::string arg_str(GetArgumentsString());
+ cur_state_ = state_stack_.top();
+ state_stack_.pop();
+ cur_state_.str += '<' + arg_str + '>';
+}
+
+const char* Demangler::ParseComplexString(const char* name) {
+ if (*name == 'S') {
+ name++;
+ if (*name == 't') {
+ AppendCurrent("std");
+ return name + 1;
+ }
+ return ParseS(name);
+ }
+ if (*name == 'L') {
+ name++;
+ if (!std::isdigit(*name)) {
+ return nullptr;
+ }
+ }
+ if (std::isdigit(*name)) {
+ std::string str;
+ name = GetStringFromLength(name, &str);
+ if (name == nullptr) {
+ return name;
+ }
+ AppendCurrent(str);
+ Save(cur_state_.str, true);
+ cur_state_.last_save = std::move(str);
+ return name;
+ }
+ if (*name == 'D') {
+ name++;
+ if (saves_.empty() || (*name != '0' && *name != '1' && *name != '2'
+ && *name != '5')) {
+ return nullptr;
+ }
+ last_save_name_ = false;
+ AppendCurrent("~" + cur_state_.last_save);
+ return name + 1;
+ }
+ if (*name == 'C') {
+ name++;
+ if (saves_.empty() || (*name != '1' && *name != '2' && *name != '3'
+ && *name != '5')) {
+ return nullptr;
+ }
+ last_save_name_ = false;
+ AppendCurrent(cur_state_.last_save);
+ return name + 1;
+ }
+ if (*name == 'K') {
+ cur_state_.suffixes.push_back(" const");
+ return name + 1;
+ }
+ if (*name == 'V') {
+ cur_state_.suffixes.push_back(" volatile");
+ return name + 1;
+ }
+ if (*name == 'I') {
+ // Save the current argument state.
+ state_stack_.push(cur_state_);
+ cur_state_.Clear();
+
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseTemplateArgumentsComplex;
+ return name + 1;
+ }
+ name = AppendOperatorString(name);
+ if (name != nullptr) {
+ Save(cur_state_.str, true);
+ }
+ return name;
+}
+
+void Demangler::AppendArgument(const std::string& str) {
+ std::string arg(str);
+ while (!cur_state_.suffixes.empty()) {
+ arg += cur_state_.suffixes.back();
+ cur_state_.suffixes.pop_back();
+ Save(arg, false);
+ }
+ cur_state_.args.push_back(arg);
+}
+
+const char* Demangler::ParseFunctionArgument(const char* name) {
+ if (*name == 'E') {
+ // The first argument is the function modifier.
+ // The second argument is the function type.
+ // The third argument is the return type of the function.
+ // The rest of the arguments are the function arguments.
+ size_t num_args = cur_state_.args.size();
+ if (num_args < 4) {
+ return nullptr;
+ }
+ std::string function_modifier = cur_state_.args[0];
+ std::string function_type = cur_state_.args[1];
+
+ std::string str = cur_state_.args[2] + ' ';
+ if (!cur_state_.args[1].empty()) {
+ str += '(' + cur_state_.args[1] + ')';
+ }
+
+ if (num_args == 4 && cur_state_.args[3] == "void") {
+ str += "()";
+ } else {
+ str += '(' + cur_state_.args[3];
+ for (size_t i = 4; i < num_args; i++) {
+ str += ", " + cur_state_.args[i];
+ }
+ str += ')';
+ }
+ str += cur_state_.args[0];
+
+ cur_state_ = state_stack_.top();
+ state_stack_.pop();
+ cur_state_.args.emplace_back(std::move(str));
+
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+ return name + 1;
+ }
+ return ParseArguments(name);
+}
+
+const char* Demangler::ParseArguments(const char* name) {
+ switch (*name) {
+ case 'P':
+ cur_state_.suffixes.push_back("*");
+ return name + 1;
+
+ case 'R':
+ // This should always be okay because the string is guaranteed to have
+ // at least two characters before this. A mangled string always starts
+ // with _Z.
+ if (name[-1] != 'R') {
+ // Multiple 'R's in a row only add a single &.
+ cur_state_.suffixes.push_back("&");
+ }
+ return name + 1;
+
+ case 'K':
+ case 'V': {
+ const char* suffix;
+ if (*name == 'K') {
+ suffix = " const";
+ } else {
+ suffix = " volatile";
+ }
+ if (name[-1] == 'K' || name[-1] == 'V') {
+ // Special case, const/volatile apply as a single entity.
+ assert(!cur_state_.suffixes.empty());
+ size_t index = cur_state_.suffixes.size();
+ cur_state_.suffixes[index-1].insert(0, suffix);
+ } else {
+ cur_state_.suffixes.push_back(suffix);
+ }
+ return name + 1;
+ }
+
+ case 'F': {
+ std::string function_modifier;
+ std::string function_type;
+ if (!cur_state_.suffixes.empty()) {
+ // If the first element starts with a ' ', then this modifies the
+ // function itself.
+ if (cur_state_.suffixes.back()[0] == ' ') {
+ function_modifier = cur_state_.suffixes.back();
+ cur_state_.suffixes.pop_back();
+ }
+ while (!cur_state_.suffixes.empty()) {
+ function_type += cur_state_.suffixes.back();
+ cur_state_.suffixes.pop_back();
+ }
+ }
+
+ state_stack_.push(cur_state_);
+
+ cur_state_.Clear();
+
+ // The function parameter has this format:
+ // First argument is the function modifier.
+ // Second argument is the function type.
+ // Third argument will be the return function type but has not
+ // been parsed yet.
+ // Any other parameters are the arguments to the function. There
+ // must be at least one or this isn't valid.
+ cur_state_.args.push_back(function_modifier);
+ cur_state_.args.push_back(function_type);
+
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseFunctionArgument;
+ return name + 1;
+ }
+
+ case 'N':
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseComplexArgument;
+ return name + 1;
+
+ case 'S':
+ name++;
+ if (*name == 't') {
+ cur_state_.str = "std::";
+ return name + 1;
+ }
+ name = ParseS(name);
+ if (name == nullptr) {
+ return nullptr;
+ }
+ AppendArgument(cur_state_.str);
+ cur_state_.str.clear();
+ return name;
+
+ case 'D':
+ name++;
+ if (*name >= 'a' && *name <= 'z') {
+ const char* arg = Demangler::kDTypes[*name - 'a'];
+ if (arg == nullptr) {
+ return nullptr;
+ }
+ AppendArgument(arg);
+ return name + 1;
+ }
+ return nullptr;
+
+ case 'I':
+ // Save the current argument state.
+ state_stack_.push(cur_state_);
+ cur_state_.Clear();
+
+ parse_funcs_.push_back(parse_func_);
+ parse_func_ = &Demangler::ParseTemplateArguments;
+ return name + 1;
+
+ case 'v':
+ AppendArgument("void");
+ return name + 1;
+
+ default:
+ if (*name >= 'a' && *name <= 'z') {
+ const char* arg = Demangler::kTypes[*name - 'a'];
+ if (arg == nullptr) {
+ return nullptr;
+ }
+ AppendArgument(arg);
+ return name + 1;
+ } else if (std::isdigit(*name)) {
+ std::string arg = cur_state_.str;
+ name = GetStringFromLength(name, &arg);
+ if (name == nullptr) {
+ return nullptr;
+ }
+ Save(arg, true);
+ if (*name == 'I') {
+ // There is one case where this argument is not complete, and that's
+ // where this is a template argument.
+ cur_state_.str = arg;
+ } else {
+ AppendArgument(arg);
+ cur_state_.str.clear();
+ }
+ return name;
+ }
+ }
+ return nullptr;
+}
+
+const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
+ if (*name == 'E') {
+ if (parse_funcs_.empty()) {
+ return nullptr;
+ }
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+ FinalizeTemplate();
+ Save(cur_state_.str, false);
+ return name + 1;
+ }
+ return ParseArguments(name);
+}
+
+const char* Demangler::ParseTemplateArguments(const char* name) {
+ if (*name == 'E') {
+ if (parse_funcs_.empty()) {
+ return nullptr;
+ }
+ parse_func_ = parse_funcs_.back();
+ parse_funcs_.pop_back();
+ FinalizeTemplate();
+ AppendArgument(cur_state_.str);
+ cur_state_.str.clear();
+ return name + 1;
+ }
+ return ParseArguments(name);
+}
+
+const char* Demangler::FindFunctionName(const char* name) {
+ if (*name == 'N') {
+ parse_funcs_.push_back(&Demangler::ParseArguments);
+ parse_func_ = &Demangler::ParseFunctionName;
+ return name + 1;
+ }
+
+ if (std::isdigit(*name)) {
+ name = GetStringFromLength(name, &function_name_);
+ } else {
+ name = AppendOperatorString(name);
+ function_name_ = cur_state_.str;
+ }
+ parse_func_ = &Demangler::ParseArguments;
+ cur_state_.Clear();
+ return name;
+}
+
+std::string Demangler::Parse(const char* name, size_t max_length) {
+ if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') {
+ // Name is not mangled.
+ return name;
+ }
+
+ Clear();
+
+ parse_func_ = &Demangler::FindFunctionName;
+ parse_funcs_.push_back(&Demangler::Fail);
+ const char* cur_name = name + 2;
+ while (cur_name != nullptr && *cur_name != '\0'
+ && static_cast<size_t>(cur_name - name) < max_length) {
+ cur_name = (this->*parse_func_)(cur_name);
+ }
+ if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty()) {
+ return name;
+ }
+
+ std::string arg_str;
+ if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") {
+ // If the only argument is void, then don't print any args.
+ arg_str = "()";
+ } else {
+ arg_str = GetArgumentsString();
+ if (!arg_str.empty()) {
+ arg_str = '(' + arg_str + ')';
+ }
+ }
+ return function_name_ + arg_str + function_suffix_;
+}
+
+std::string demangle(const char* name) {
+ Demangler demangler;
+ return demangler.Parse(name);
+}
diff --git a/demangle/Demangler.h b/demangle/Demangler.h
new file mode 100644
index 0000000..3bd4f3c
--- /dev/null
+++ b/demangle/Demangler.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2017 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 __LIB_DEMANGLE_DEMANGLER_H
+#define __LIB_DEMANGLE_DEMANGLER_H
+
+#include <assert.h>
+
+#include <stack>
+#include <string>
+#include <vector>
+
+class Demangler {
+ public:
+ Demangler() = default;
+
+ // NOTE: The max_length is not guaranteed to be the absolute max length
+ // of a string that will be rejected. Under certain circumstances the
+ // length check will not occur until after the second letter of a pair
+ // is checked.
+ std::string Parse(const char* name, size_t max_length = kMaxDefaultLength);
+
+ void AppendCurrent(const std::string& str);
+ void AppendCurrent(const char* str);
+ void AppendArgument(const std::string& str);
+ std::string GetArgumentsString();
+ void FinalizeTemplate();
+ const char* ParseS(const char* name);
+ const char* AppendOperatorString(const char* name);
+ void Save(const std::string& str, bool is_name);
+
+ private:
+ void Clear() {
+ parse_funcs_.clear();
+ function_name_.clear();
+ function_suffix_.clear();
+ first_save_.clear();
+ cur_state_.Clear();
+ saves_.clear();
+ while (!state_stack_.empty()) {
+ state_stack_.pop();
+ }
+ last_save_name_ = false;
+ }
+
+ using parse_func_type = const char* (Demangler::*)(const char*);
+ parse_func_type parse_func_;
+ std::vector<parse_func_type> parse_funcs_;
+ std::vector<std::string> saves_;
+ bool last_save_name_;
+
+ std::string function_name_;
+ std::string function_suffix_;
+
+ struct StateData {
+ void Clear() {
+ str.clear();
+ args.clear();
+ prefix.clear();
+ suffixes.clear();
+ last_save.clear();
+ }
+
+ std::string str;
+ std::vector<std::string> args;
+ std::string prefix;
+ std::vector<std::string> suffixes;
+ std::string last_save;
+ };
+ std::stack<StateData> state_stack_;
+ std::string first_save_;
+ StateData cur_state_;
+
+ static const char* GetStringFromLength(const char* name, std::string* str);
+
+ // Parsing functions.
+ const char* ParseComplexString(const char* name);
+ const char* ParseComplexArgument(const char* name);
+ const char* ParseArguments(const char* name);
+ const char* ParseTemplateArguments(const char* name);
+ const char* ParseTemplateArgumentsComplex(const char* name);
+ const char* ParseFunctionArgument(const char* name);
+ const char* ParseFunctionName(const char* name);
+ const char* FindFunctionName(const char* name);
+ const char* Fail(const char*) { return nullptr; }
+
+ // The default maximum string length string to process.
+ static constexpr size_t kMaxDefaultLength = 2048;
+
+ static constexpr const char* kTypes[] = {
+ "signed char", // a
+ "bool", // b
+ "char", // c
+ "double", // d
+ "long double", // e
+ "float", // f
+ "__float128", // g
+ "unsigned char", // h
+ "int", // i
+ "unsigned int", // j
+ nullptr, // k
+ "long", // l
+ "unsigned long", // m
+ "__int128", // n
+ "unsigned __int128", // o
+ nullptr, // p
+ nullptr, // q
+ nullptr, // r
+ "short", // s
+ "unsigned short", // t
+ nullptr, // u
+ "void", // v
+ "wchar_t", // w
+ "long long", // x
+ "unsigned long long", // y
+ "...", // z
+ };
+
+ static constexpr const char* kDTypes[] = {
+ "auto", // a
+ nullptr, // b
+ nullptr, // c
+ "decimal64", // d
+ "decimal128", // e
+ "decimal32", // f
+ nullptr, // g
+ "half", // h
+ "char32_t", // i
+ nullptr, // j
+ nullptr, // k
+ nullptr, // l
+ nullptr, // m
+ "decltype(nullptr)", // n
+ nullptr, // o
+ nullptr, // p
+ nullptr, // q
+ nullptr, // r
+ "char16_t", // s
+ nullptr, // t
+ nullptr, // u
+ nullptr, // v
+ nullptr, // w
+ nullptr, // x
+ nullptr, // y
+ nullptr, // z
+ };
+
+ static constexpr const char* kSTypes[] = {
+ "std::allocator", // a
+ "std::basic_string", // b
+ nullptr, // c
+ "std::iostream", // d
+ nullptr, // e
+ nullptr, // f
+ nullptr, // g
+ nullptr, // h
+ "std::istream", // i
+ nullptr, // j
+ nullptr, // k
+ nullptr, // l
+ nullptr, // m
+ nullptr, // n
+ "std::ostream", // o
+ nullptr, // p
+ nullptr, // q
+ nullptr, // r
+ "std::string", // s
+ nullptr, // t
+ nullptr, // u
+ nullptr, // v
+ nullptr, // w
+ nullptr, // x
+ nullptr, // y
+ nullptr, // z
+ };
+};
+
+#endif // __LIB_DEMANGLE_DEMANGLER_H
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
new file mode 100644
index 0000000..be4d2dd
--- /dev/null
+++ b/demangle/demangle.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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 <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <demangle.h>
+
+extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
+
+void usage(const char* prog_name) {
+ printf("Usage: %s [-c] <NAME_TO_DEMANGLE>\n", prog_name);
+ printf(" -c\n");
+ printf(" Compare the results of __cxa_demangle against the current\n");
+ printf(" demangler.\n");
+}
+
+std::string DemangleWithCxa(const char* name) {
+ const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
+
+ if (cxa_demangle == nullptr) {
+ return name;
+ }
+
+ // The format of our demangler is slightly different from the cxa demangler
+ // so modify the cxa demangler output. Specifically, for templates, remove
+ // the spaces between '>' and '>'.
+ std::string demangled_str;
+ for (size_t i = 0; i < strlen(cxa_demangle); i++) {
+ if (i > 2 && cxa_demangle[i] == '>' && std::isspace(cxa_demangle[i - 1]) &&
+ cxa_demangle[i - 2] == '>') {
+ demangled_str.resize(demangled_str.size() - 1);
+ }
+ demangled_str += cxa_demangle[i];
+ }
+ return demangled_str;
+}
+
+int main(int argc, char** argv) {
+#ifdef __BIONIC__
+ const char* prog_name = getprogname();
+#else
+ const char* prog_name = argv[0];
+#endif
+
+ bool compare = false;
+ int opt_char;
+ while ((opt_char = getopt(argc, argv, "c")) != -1) {
+ if (opt_char == 'c') {
+ compare = true;
+ } else {
+ usage(prog_name);
+ return 1;
+ }
+ }
+ if (optind >= argc || argc - optind != 1) {
+ printf("Must supply a single argument.\n\n");
+ usage(prog_name);
+ return 1;
+ }
+ const char* name = argv[optind];
+
+ std::string demangled_name = demangle(name);
+
+ printf("%s\n", demangled_name.c_str());
+
+ if (compare) {
+ std::string cxa_demangle_str(DemangleWithCxa(name));
+
+ if (cxa_demangle_str != demangled_name) {
+ printf("Mismatch\n");
+ printf("cxa demangle: %s\n", cxa_demangle_str.c_str());
+ return 1;
+ } else {
+ printf("Match\n");
+ }
+ }
+ return 0;
+}
diff --git a/bootstat/histogram_logger.h b/demangle/include/demangle.h
similarity index 61%
copy from bootstat/histogram_logger.h
copy to demangle/include/demangle.h
index 60c7776..01f1b80 100644
--- a/bootstat/histogram_logger.h
+++ b/demangle/include/demangle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include <cstdint>
+#ifndef __LIB_DEMANGLE_H_
+#define __LIB_DEMANGLE_H_
+
#include <string>
-namespace bootstat {
+// If the name cannot be demangled, the original name will be returned as
+// a std::string. If the name can be demangled, then the demangled name
+// will be returned as a std::string.
+std::string demangle(const char* name);
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+#endif // __LIB_DEMANGLE_H_
diff --git a/fastboot/.clang-format b/fastboot/.clang-format
deleted file mode 100644
index bcb8d8a..0000000
--- a/fastboot/.clang-format
+++ /dev/null
@@ -1,15 +0,0 @@
-BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: Inline
-
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-IndentWidth: 4
-ContinuationIndentWidth: 8
-ConstructorInitializerIndentWidth: 8
-AccessModifierOffset: -2
-PointerAlignment: Left
-TabWidth: 4
-UseTab: Never
-PenaltyExcessCharacter: 32
diff --git a/fastboot/.clang-format b/fastboot/.clang-format
new file mode 120000
index 0000000..1af4f51
--- /dev/null
+++ b/fastboot/.clang-format
@@ -0,0 +1 @@
+../.clang-format-4
\ No newline at end of file
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e7f1a07..2927b16 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1245,20 +1245,17 @@
return 0;
}
-static int do_oem_command(int argc, char **argv)
-{
- char command[256];
+static int do_oem_command(int argc, char** argv) {
if (argc <= 1) return 0;
- command[0] = 0;
- while(1) {
- strcat(command,*argv);
+ std::string command;
+ while (argc > 0) {
+ command += *argv;
skip(1);
- if(argc == 0) break;
- strcat(command," ");
+ if (argc != 0) command += " ";
}
- fb_queue_command(command,"");
+ fb_queue_command(command.c_str(), "");
return 0;
}
@@ -1303,6 +1300,36 @@
return num;
}
+static std::string fb_fix_numeric_var(std::string var) {
+ // Some bootloaders (angler, for example), send spurious leading whitespace.
+ var = android::base::Trim(var);
+ // Some bootloaders (hammerhead, for example) use implicit hex.
+ // This code used to use strtol with base 16.
+ if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
+ return var;
+}
+
+static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
+ std::string sizeString;
+ if (!fb_getvar(transport, name.c_str(), &sizeString)) {
+ /* This device does not report flash block sizes, so return 0 */
+ return 0;
+ }
+ sizeString = fb_fix_numeric_var(sizeString);
+
+ unsigned size;
+ if (!android::base::ParseUint(sizeString, &size)) {
+ fprintf(stderr, "Couldn't parse %s '%s'.\n", name.c_str(), sizeString.c_str());
+ return 0;
+ }
+ if (size < 4096 || (size & (size - 1)) != 0) {
+ fprintf(stderr, "Invalid %s %u: must be a power of 2 and at least 4096.\n",
+ name.c_str(), size);
+ return 0;
+ }
+ return size;
+}
+
static void fb_perform_format(Transport* transport,
const char* partition, int skip_if_not_supported,
const char* type_override, const char* size_override,
@@ -1345,11 +1372,7 @@
}
partition_size = size_override;
}
- // Some bootloaders (angler, for example), send spurious leading whitespace.
- partition_size = android::base::Trim(partition_size);
- // Some bootloaders (hammerhead, for example) use implicit hex.
- // This code used to use strtol with base 16.
- if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
+ partition_size = fb_fix_numeric_var(partition_size);
gen = fs_get_generator(partition_type);
if (!gen) {
@@ -1370,7 +1393,12 @@
}
fd = fileno(tmpfile());
- if (fs_generator_generate(gen, fd, size, initial_dir)) {
+
+ unsigned eraseBlkSize, logicalBlkSize;
+ eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
+ logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
+
+ if (fs_generator_generate(gen, fd, size, initial_dir, eraseBlkSize, logicalBlkSize)) {
fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
close(fd);
return;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9b73165..5d9ccfe 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -14,18 +14,21 @@
#include <ext4_utils/make_ext4fs.h>
#include <sparse/sparse.h>
-static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir,
+ unsigned eraseBlkSize, unsigned logicalBlkSize)
{
if (initial_dir.empty()) {
- make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+ make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
} else {
- make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+ make_ext4fs_sparse_fd_directory_align(fd, partSize, NULL, NULL, initial_dir.c_str(),
+ eraseBlkSize, logicalBlkSize);
}
return 0;
}
#ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir,
+ unsigned /* unused */, unsigned /* unused */)
{
if (!initial_dir.empty()) {
fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
@@ -39,7 +42,8 @@
const char* fs_type; //must match what fastboot reports for partition type
//returns 0 or error value
- int (*generate)(int fd, long long partSize, const std::string& initial_dir);
+ int (*generate)(int fd, long long partSize, const std::string& initial_dir,
+ unsigned eraseBlkSize, unsigned logicalBlkSize);
} generators[] = {
{ "ext4", generate_ext4_image},
@@ -58,7 +62,7 @@
}
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
- const std::string& initial_dir)
+ const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
{
- return gen->generate(tmpFileNo, partSize, initial_dir);
+ return gen->generate(tmpFileNo, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
}
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 0a68507..0a5f5a4 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -8,6 +8,6 @@
const struct fs_generator* fs_get_generator(const std::string& fs_type);
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
- const std::string& initial_dir);
+ const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
#endif
diff --git a/fs_mgr/.clang-format b/fs_mgr/.clang-format
new file mode 120000
index 0000000..4e6d9dd
--- /dev/null
+++ b/fs_mgr/.clang-format
@@ -0,0 +1 @@
+../init/.clang-format
\ No newline at end of file
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 956c702..2863a26 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -25,24 +25,22 @@
fs_mgr_slotselect.cpp \
fs_mgr_verity.cpp \
fs_mgr_avb.cpp \
- fs_mgr_avb_ops.cpp
+ fs_mgr_avb_ops.cpp \
+ fs_mgr_boot_config.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
system/vold \
- system/extras/ext4_utils \
- bootable/recovery
+ system/extras/ext4_utils
LOCAL_MODULE:= libfs_mgr
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Werror
-ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- ifeq ($(TARGET_USES_MKE2FS), true)
- LOCAL_CFLAGS += -DTARGET_USES_MKE2FS
- endif
-endif
ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
endif
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DALLOW_SKIP_SECURE_CHECK=1
+endif
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index be84e8a..6c84d73 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,6 +31,8 @@
#include <time.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
@@ -48,7 +50,6 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb.h"
-#include "fs_mgr_priv_verity.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
@@ -65,6 +66,21 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+// record fs stat
+enum FsStatFlags {
+ FS_STAT_IS_EXT4 = 0x0001,
+ FS_STAT_NEW_IMAGE_VERSION = 0x0002,
+ FS_STAT_E2FSCK_F_ALWAYS = 0x0004,
+ FS_STAT_UNCLEAN_SHUTDOWN = 0x0008,
+ FS_STAT_QUOTA_ENABLED = 0x0010,
+ FS_STAT_TUNE2FS_FAILED = 0x0020,
+ FS_STAT_RO_MOUNT_FAILED = 0x0040,
+ FS_STAT_RO_UNMOUNT_FAILED = 0x0080,
+ FS_STAT_FULL_MOUNT_FAILED = 0x0100,
+ FS_STAT_E2FSCK_FAILED = 0x0200,
+ FS_STAT_E2FSCK_FS_FIXED = 0x0400,
+};
+
/*
* gettime() - returns the time in seconds of the system's monotonic clock or
* zero on error.
@@ -95,7 +111,18 @@
return ret;
}
-static void check_fs(const char *blk_device, char *fs_type, char *target)
+static void log_fs_stat(const char* blk_device, int fs_stat)
+{
+ if ((fs_stat & FS_STAT_IS_EXT4) == 0) return; // only log ext4
+ std::string msg = android::base::StringPrintf("\nfs_stat,%s,0x%x\n", blk_device, fs_stat);
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(FSCK_LOG_FILE, O_WRONLY | O_CLOEXEC |
+ O_APPEND | O_CREAT, 0664)));
+ if (fd == -1 || !android::base::WriteStringToFd(msg, fd)) {
+ LWARNING << __FUNCTION__ << "() cannot log " << msg;
+ }
+}
+
+static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat)
{
int status;
int ret;
@@ -103,9 +130,7 @@
char tmpmnt_opts[64] = "errors=remount-ro";
const char *e2fsck_argv[] = {
E2FSCK_BIN,
-#ifndef TARGET_USES_MKE2FS // "-f" only for old ext4 generation tool
"-f",
-#endif
"-y",
blk_device
};
@@ -144,10 +169,13 @@
<< ") succeeded";
break;
}
+ *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
PERROR << __FUNCTION__ << "(): umount(" << target << ")="
<< result;
sleep(1);
}
+ } else {
+ *fs_stat |= FS_STAT_RO_MOUNT_FAILED;
}
/*
@@ -160,6 +188,7 @@
} else {
LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;
+ *fs_stat |= FS_STAT_E2FSCK_F_ALWAYS;
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv),
const_cast<char **>(e2fsck_argv),
&status, true, LOG_KLOG | LOG_FILE,
@@ -170,6 +199,10 @@
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
LERROR << "Failed trying to run " << E2FSCK_BIN;
+ *fs_stat |= FS_STAT_E2FSCK_FAILED;
+ } else if (status != 0) {
+ LINFO << "e2fsck returned status 0x" << std::hex << status;
+ *fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
}
}
} else if (!strcmp(fs_type, "f2fs")) {
@@ -224,7 +257,8 @@
le32_to_cpu(es->s_r_blocks_count_lo);
}
-static int do_quota(char *blk_device, char *fs_type, struct fstab_rec *rec)
+static int do_quota_with_shutdown_check(char *blk_device, char *fs_type,
+ struct fstab_rec *rec, int *fs_stat)
{
int force_check = 0;
if (!strcmp(fs_type, "ext4")) {
@@ -249,7 +283,16 @@
PERROR << "Can't read '" << blk_device << "' super block";
return force_check;
}
-
+ *fs_stat |= FS_STAT_IS_EXT4;
+ //TODO check if it is new version or not
+ if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
+ (sb.s_state & EXT4_VALID_FS) == 0) {
+ LINFO << __FUNCTION__ << "(): was not clealy shutdown, state flag:"
+ << std::hex << sb.s_state
+ << "incompat flag:" << std::hex << sb.s_feature_incompat;
+ force_check = 1;
+ *fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
+ }
int has_quota = (sb.s_feature_ro_compat
& cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
int want_quota = fs_mgr_is_quota(rec) != 0;
@@ -262,6 +305,7 @@
arg1 = "-Oquota";
arg2 = "-Qusrquota,grpquota";
force_check = 1;
+ *fs_stat |= FS_STAT_QUOTA_ENABLED;
} else {
LINFO << "Disabling quota on " << blk_device;
arg1 = "-Q^usrquota,^grpquota";
@@ -285,13 +329,14 @@
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
LERROR << "Failed trying to run " << TUNE2FS_BIN;
+ *fs_stat |= FS_STAT_TUNE2FS_FAILED;
}
}
}
return force_check;
}
-static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec)
+static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec, int *fs_stat)
{
/* Check for the types of filesystems we know how to check */
if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
@@ -350,6 +395,7 @@
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
LERROR << "Failed trying to run " << TUNE2FS_BIN;
+ *fs_stat |= FS_STAT_TUNE2FS_FAILED;
}
}
}
@@ -438,16 +484,6 @@
return ret;
}
-static int device_is_secure() {
- int ret = -1;
- char value[PROP_VALUE_MAX];
- ret = __system_property_get("ro.secure", value);
- /* If error, we want to fail secure */
- if (ret < 0)
- return 1;
- return strcmp(value, "0") ? 1 : 0;
-}
-
static int device_is_force_encrypted() {
int ret = -1;
char value[PROP_VALUE_MAX];
@@ -500,17 +536,19 @@
continue;
}
- int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- &fstab->recs[i]);
+ int fs_stat = 0;
+ int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
+ fstab->recs[i].fs_type,
+ &fstab->recs[i], &fs_stat);
if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point);
+ fstab->recs[i].mount_point, &fs_stat);
}
if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- &fstab->recs[i]);
+ &fstab->recs[i], &fs_stat);
}
if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
@@ -524,9 +562,13 @@
<< fstab->recs[start_idx].fs_type;
}
} else {
- /* back up errno for crypto decisions */
- mount_errno = errno;
+ fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
+ /* back up the first errno for crypto decisions */
+ if (mount_errno == 0) {
+ mount_errno = errno;
+ }
}
+ log_fs_stat(fstab->recs[i].blk_device, fs_stat);
}
/* Adjust i for the case where it was still withing the recs[] */
@@ -663,6 +705,8 @@
}
}
+// TODO: add ueventd notifiers if they don't exist.
+// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
int tries = 25;
while (tries--) {
@@ -674,6 +718,23 @@
return -1;
}
+bool is_device_secure() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.secure", value);
+ if (ret == 0) {
+#ifdef ALLOW_SKIP_SECURE_CHECK
+ // Allow eng builds to skip this check if the property
+ // is not readable (happens during early mount)
+ return false;
+#else
+ // If error and not an 'eng' build, we want to fail secure.
+ return true;
+#endif
+ }
+ return strcmp(value, "0") ? true : false;
+}
+
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
@@ -751,7 +812,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -882,6 +943,24 @@
}
}
+/* wrapper to __mount() and expects a fully prepared fstab_rec,
+ * unlike fs_mgr_do_mount which does more things with avb / verity
+ * etc.
+ */
+int fs_mgr_do_mount_one(struct fstab_rec *rec)
+{
+ if (!rec) {
+ return FS_MGR_DOMNT_FAILED;
+ }
+
+ int ret = __mount(rec->blk_device, rec->mount_point, rec);
+ if (ret) {
+ ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
+ }
+
+ return ret;
+}
+
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
* tmp mount we do to check the user password
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
@@ -926,16 +1005,18 @@
wait_for_file(n_blk_device, WAIT_TIMEOUT);
}
- int force_check = do_quota(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- &fstab->recs[i]);
+ int fs_stat = 0;
+ int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
+ fstab->recs[i].fs_type,
+ &fstab->recs[i], &fs_stat);
if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
check_fs(n_blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point);
+ fstab->recs[i].mount_point, &fs_stat);
}
if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
- do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
+ do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
}
if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
@@ -953,7 +1034,7 @@
/* Skips mounting the device. */
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && is_device_secure()) {
int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
LINFO << "Verity disabled";
@@ -972,9 +1053,12 @@
if (__mount(n_blk_device, m, &fstab->recs[i])) {
if (!first_mount_errno) first_mount_errno = errno;
mount_errors++;
+ fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
+ log_fs_stat(fstab->recs[i].blk_device, fs_stat);
continue;
} else {
ret = 0;
+ log_fs_stat(fstab->recs[i].blk_device, fs_stat);
goto out;
}
}
@@ -1003,7 +1087,7 @@
* mount a tmpfs filesystem at the given point.
* return 0 on success, non-zero on failure.
*/
-int fs_mgr_do_tmpfs_mount(char *n_name)
+int fs_mgr_do_tmpfs_mount(const char *n_name)
{
int ret;
@@ -1173,22 +1257,3 @@
return 0;
}
-
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
-{
- if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
- int rc = fs_mgr_setup_verity(fstab_rec, false);
- if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
- LINFO << "Verity disabled";
- return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
- } else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
- return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
- } else {
- return FS_MGR_EARLY_SETUP_VERITY_FAIL;
- }
- } else if (device_is_secure()) {
- LERROR << "Verity must be enabled for early mounted partitions on secured devices";
- return FS_MGR_EARLY_SETUP_VERITY_FAIL;
- }
- return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
-}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 70140d8..2cb7e34 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -51,14 +51,12 @@
"%u %s %s %u %u " \
"%" PRIu64 " %" PRIu64 " %s %s %s "
-#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt) \
- hashtree_desc.dm_verity_version, blk_device, blk_device, \
- hashtree_desc.data_block_size, hashtree_desc.hash_block_size, \
- hashtree_desc.image_size / \
- hashtree_desc.data_block_size, /* num_data_blocks. */ \
- hashtree_desc.tree_offset / \
- hashtree_desc.hash_block_size, /* hash_start_block. */ \
- (char *)hashtree_desc.hash_algorithm, digest, salt
+#define VERITY_TABLE_PARAMS(hashtree_desc, blk_device, digest, salt) \
+ hashtree_desc.dm_verity_version, blk_device, blk_device, hashtree_desc.data_block_size, \
+ hashtree_desc.hash_block_size, \
+ hashtree_desc.image_size / hashtree_desc.data_block_size, /* num_data_blocks. */ \
+ hashtree_desc.tree_offset / hashtree_desc.hash_block_size, /* hash_start_block. */ \
+ (char*)hashtree_desc.hash_algorithm, digest, salt
#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
@@ -67,32 +65,28 @@
* <#opt_params> ignore_zero_blocks restart_on_corruption
*/
#define VERITY_TABLE_OPT_DEFAULT_FORMAT "2 %s %s"
-#define VERITY_TABLE_OPT_DEFAULT_PARAMS \
- VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
+#define VERITY_TABLE_OPT_DEFAULT_PARAMS VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
/* The FEC (forward error correction) format of dm-verity optional parameters:
* <#opt_params> use_fec_from_device <fec_dev>
* fec_roots <num> fec_blocks <num> fec_start <offset>
* ignore_zero_blocks restart_on_corruption
*/
-#define VERITY_TABLE_OPT_FEC_FORMAT \
- "10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 \
- " fec_start %" PRIu64 " %s %s"
+#define VERITY_TABLE_OPT_FEC_FORMAT \
+ "10 use_fec_from_device %s fec_roots %u fec_blocks %" PRIu64 " fec_start %" PRIu64 " %s %s"
/* Note that fec_blocks is the size that FEC covers, *not* the
* size of the FEC data. Since we use FEC for everything up until
* the FEC data, it's the same as the offset (fec_start).
*/
-#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \
- blk_device, hashtree_desc.fec_num_roots, \
- hashtree_desc.fec_offset / \
- hashtree_desc.data_block_size, /* fec_blocks */ \
- hashtree_desc.fec_offset / \
- hashtree_desc.data_block_size, /* fec_start */ \
+#define VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device) \
+ blk_device, hashtree_desc.fec_num_roots, \
+ hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_blocks */ \
+ hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */ \
VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
-AvbSlotVerifyData *fs_mgr_avb_verify_data = nullptr;
-AvbOps *fs_mgr_avb_ops = nullptr;
+AvbSlotVerifyData* fs_mgr_avb_verify_data = nullptr;
+AvbOps* fs_mgr_avb_ops = nullptr;
enum HashAlgorithm {
kInvalid = 0,
@@ -109,8 +103,7 @@
androidboot_vbmeta fs_mgr_vbmeta_prop;
-static inline bool nibble_value(const char &c, uint8_t *value)
-{
+static inline bool nibble_value(const char& c, uint8_t* value) {
FS_MGR_CHECK(value != nullptr);
switch (c) {
@@ -130,10 +123,7 @@
return true;
}
-static bool hex_to_bytes(uint8_t *bytes,
- size_t bytes_len,
- const std::string &hex)
-{
+static bool hex_to_bytes(uint8_t* bytes, size_t bytes_len, const std::string& hex) {
FS_MGR_CHECK(bytes != nullptr);
if (hex.size() % 2 != 0) {
@@ -156,11 +146,10 @@
return true;
}
-static std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len)
-{
+static std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
FS_MGR_CHECK(bytes != nullptr);
- static const char *hex_digits = "0123456789abcdef";
+ static const char* hex_digits = "0123456789abcdef";
std::string hex;
for (size_t i = 0; i < bytes_len; i++) {
@@ -170,8 +159,7 @@
return hex;
}
-static bool load_vbmeta_prop(androidboot_vbmeta *vbmeta_prop)
-{
+static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) {
FS_MGR_CHECK(vbmeta_prop != nullptr);
std::string cmdline;
@@ -180,19 +168,17 @@
std::string hash_alg;
std::string digest;
- for (const auto &entry :
- android::base::Split(android::base::Trim(cmdline), " ")) {
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
- const std::string &key = pieces[0];
- const std::string &value = pieces[1];
+ const std::string& key = pieces[0];
+ const std::string& value = pieces[1];
if (key == "androidboot.vbmeta.device_state") {
vbmeta_prop->allow_verification_error = (value == "unlocked");
} else if (key == "androidboot.vbmeta.hash_alg") {
hash_alg = value;
} else if (key == "androidboot.vbmeta.size") {
- if (!android::base::ParseUint(value.c_str(),
- &vbmeta_prop->vbmeta_size)) {
+ if (!android::base::ParseUint(value.c_str(), &vbmeta_prop->vbmeta_size)) {
return false;
}
} else if (key == "androidboot.vbmeta.digest") {
@@ -215,15 +201,13 @@
// Reads digest.
if (digest.size() != expected_digest_size) {
- LERROR << "Unexpected digest size: " << digest.size() << " (expected: "
- << expected_digest_size << ")";
+ LERROR << "Unexpected digest size: " << digest.size()
+ << " (expected: " << expected_digest_size << ")";
return false;
}
- if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest),
- digest)) {
- LERROR << "Hash digest contains non-hexidecimal character: "
- << digest.c_str();
+ if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest), digest)) {
+ LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str();
return false;
}
@@ -231,9 +215,8 @@
}
template <typename Hasher>
-static std::pair<size_t, bool> verify_vbmeta_digest(
- const AvbSlotVerifyData &verify_data, const androidboot_vbmeta &vbmeta_prop)
-{
+static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
+ const androidboot_vbmeta& vbmeta_prop) {
size_t total_size = 0;
Hasher hasher;
for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
@@ -242,15 +225,13 @@
total_size += verify_data.vbmeta_images[n].vbmeta_size;
}
- bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest,
- Hasher::DIGEST_SIZE) == 0);
+ bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest, Hasher::DIGEST_SIZE) == 0);
return std::make_pair(total_size, matched);
}
-static bool verify_vbmeta_images(const AvbSlotVerifyData &verify_data,
- const androidboot_vbmeta &vbmeta_prop)
-{
+static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data,
+ const androidboot_vbmeta& vbmeta_prop) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
@@ -281,23 +262,17 @@
return true;
}
-static bool hashtree_load_verity_table(
- struct dm_ioctl *io,
- const std::string &dm_device_name,
- int fd,
- const std::string &blk_device,
- const AvbHashtreeDescriptor &hashtree_desc,
- const std::string &salt,
- const std::string &root_digest)
-{
+static bool hashtree_load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name,
+ int fd, const std::string& blk_device,
+ const AvbHashtreeDescriptor& hashtree_desc,
+ const std::string& salt, const std::string& root_digest) {
fs_mgr_verity_ioctl_init(io, dm_device_name, DM_STATUS_TABLE_FLAG);
// The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
- char *buffer = (char *)io;
+ char* buffer = (char*)io;
// Builds the dm_target_spec arguments.
- struct dm_target_spec *dm_target =
- (struct dm_target_spec *)&buffer[sizeof(struct dm_ioctl)];
+ struct dm_target_spec* dm_target = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
io->target_count = 1;
dm_target->status = 0;
dm_target->sector_start = 0;
@@ -305,23 +280,19 @@
strcpy(dm_target->target_type, "verity");
// Builds the verity params.
- char *verity_params =
- buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+ char* verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
size_t bufsize = DM_BUF_SIZE - (verity_params - buffer);
int res = 0;
if (hashtree_desc.fec_size > 0) {
- res = snprintf(
- verity_params, bufsize,
- VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT,
- VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
- root_digest.c_str(), salt.c_str()),
- VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str()));
+ res = snprintf(verity_params, bufsize, VERITY_TABLE_FORMAT VERITY_TABLE_OPT_FEC_FORMAT,
+ VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(), root_digest.c_str(),
+ salt.c_str()),
+ VERITY_TABLE_OPT_FEC_PARAMS(hashtree_desc, blk_device.c_str()));
} else {
- res = snprintf(verity_params, bufsize,
- VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT,
- VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(),
- root_digest.c_str(), salt.c_str()),
+ res = snprintf(verity_params, bufsize, VERITY_TABLE_FORMAT VERITY_TABLE_OPT_DEFAULT_FORMAT,
+ VERITY_TABLE_PARAMS(hashtree_desc, blk_device.c_str(), root_digest.c_str(),
+ salt.c_str()),
VERITY_TABLE_OPT_DEFAULT_PARAMS);
}
@@ -334,7 +305,7 @@
// Sets ext target boundary.
verity_params += strlen(verity_params) + 1;
- verity_params = (char *)(((unsigned long)verity_params + 7) & ~7);
+ verity_params = (char*)(((unsigned long)verity_params + 7) & ~7);
dm_target->next = verity_params - buffer;
// Sends the ioctl to load the verity table.
@@ -346,11 +317,9 @@
return true;
}
-static bool hashtree_dm_verity_setup(struct fstab_rec *fstab_entry,
- const AvbHashtreeDescriptor &hashtree_desc,
- const std::string &salt,
- const std::string &root_digest)
-{
+static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry,
+ const AvbHashtreeDescriptor& hashtree_desc,
+ const std::string& salt, const std::string& root_digest) {
// Gets the device mapper fd.
android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
if (fd < 0) {
@@ -360,7 +329,7 @@
// Creates the device.
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- struct dm_ioctl *io = (struct dm_ioctl *)buffer;
+ struct dm_ioctl* io = (struct dm_ioctl*)buffer;
const std::string mount_point(basename(fstab_entry->mount_point));
if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
LERROR << "Couldn't create verity device!";
@@ -375,8 +344,7 @@
}
// Loads the verity mapping table.
- if (!hashtree_load_verity_table(io, mount_point, fd,
- std::string(fstab_entry->blk_device),
+ if (!hashtree_load_verity_table(io, mount_point, fd, std::string(fstab_entry->blk_device),
hashtree_desc, salt, root_digest)) {
LERROR << "Couldn't load verity table!";
return false;
@@ -403,24 +371,20 @@
return true;
}
-static bool get_hashtree_descriptor(const std::string &partition_name,
- const AvbSlotVerifyData &verify_data,
- AvbHashtreeDescriptor *out_hashtree_desc,
- std::string *out_salt,
- std::string *out_digest)
-{
+static bool get_hashtree_descriptor(const std::string& partition_name,
+ const AvbSlotVerifyData& verify_data,
+ AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
+ std::string* out_digest) {
bool found = false;
- const uint8_t *desc_partition_name;
+ const uint8_t* desc_partition_name;
for (size_t i = 0; i < verify_data.num_vbmeta_images && !found; i++) {
// Get descriptors from vbmeta_images[i].
size_t num_descriptors;
- std::unique_ptr<const AvbDescriptor *[], decltype(&avb_free)>
- descriptors(
- avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
- verify_data.vbmeta_images[i].vbmeta_size,
- &num_descriptors),
- avb_free);
+ std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
+ avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+ verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
+ avb_free);
if (!descriptors || num_descriptors < 1) {
continue;
@@ -428,12 +392,9 @@
// Ensures that hashtree descriptor is either in /vbmeta or in
// the same partition for verity setup.
- std::string vbmeta_partition_name(
- verify_data.vbmeta_images[i].partition_name);
- if (vbmeta_partition_name != "vbmeta" &&
- vbmeta_partition_name != partition_name) {
- LWARNING << "Skip vbmeta image at "
- << verify_data.vbmeta_images[i].partition_name
+ std::string vbmeta_partition_name(verify_data.vbmeta_images[i].partition_name);
+ if (vbmeta_partition_name != "vbmeta" && vbmeta_partition_name != partition_name) {
+ LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
<< " for partition: " << partition_name.c_str();
continue;
}
@@ -445,21 +406,18 @@
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
- desc_partition_name = (const uint8_t *)descriptors[j] +
- sizeof(AvbHashtreeDescriptor);
+ desc_partition_name =
+ (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
- (AvbHashtreeDescriptor *)descriptors[j],
- out_hashtree_desc)) {
+ (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
continue;
}
- if (out_hashtree_desc->partition_name_len !=
- partition_name.length()) {
+ if (out_hashtree_desc->partition_name_len != partition_name.length()) {
continue;
}
// Notes that desc_partition_name is not NUL-terminated.
- std::string hashtree_partition_name(
- (const char *)desc_partition_name,
- out_hashtree_desc->partition_name_len);
+ std::string hashtree_partition_name((const char*)desc_partition_name,
+ out_hashtree_desc->partition_name_len);
if (hashtree_partition_name == partition_name) {
found = true;
}
@@ -472,68 +430,47 @@
return false;
}
- const uint8_t *desc_salt =
- desc_partition_name + out_hashtree_desc->partition_name_len;
+ const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len;
*out_salt = bytes_to_hex(desc_salt, out_hashtree_desc->salt_len);
- const uint8_t *desc_digest = desc_salt + out_hashtree_desc->salt_len;
+ const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len;
*out_digest = bytes_to_hex(desc_digest, out_hashtree_desc->root_digest_len);
return true;
}
-static inline bool polling_vbmeta_blk_device(struct fstab *fstab)
-{
- // It needs the block device symlink: fstab_rec->blk_device to read
- // /vbmeta partition. However, the symlink created by ueventd might
- // not be ready at this point. Use test_access() to poll it before
- // trying to read the partition.
- struct fstab_rec *fstab_entry =
- fs_mgr_get_entry_for_mount_point(fstab, "/vbmeta");
-
- // Makes sure /vbmeta block device is ready to access.
- if (fs_mgr_test_access(fstab_entry->blk_device) < 0) {
- return false;
- }
- return true;
-}
-
-static bool init_is_avb_used()
-{
+static bool init_is_avb_used() {
// When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
- // size, digest} in kernel cmdline. They will then be imported by init
- // process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+ // size, digest} in kernel cmdline or in device tree. They will then be
+ // imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
+ //
+ // In case of early mount, init properties are not initialized, so we also
+ // ensure we look into kernel command line and device tree if the property is
+ // not found
//
// Checks hash_alg as an indicator for whether AVB is used.
// We don't have to parse and check all of them here. The check will
// be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
// be returned when there is an error.
- std::string hash_alg =
- android::base::GetProperty("ro.boot.vbmeta.hash_alg", "");
-
- if (hash_alg == "sha256" || hash_alg == "sha512") {
- return true;
+ std::string hash_alg;
+ if (fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg) == 0) {
+ if (hash_alg == "sha256" || hash_alg == "sha512") {
+ return true;
+ }
}
return false;
}
-bool fs_mgr_is_avb_used()
-{
+bool fs_mgr_is_avb_used() {
static bool result = init_is_avb_used();
return result;
}
-int fs_mgr_load_vbmeta_images(struct fstab *fstab)
-{
+int fs_mgr_load_vbmeta_images(struct fstab* fstab) {
FS_MGR_CHECK(fstab != nullptr);
- if (!polling_vbmeta_blk_device(fstab)) {
- LERROR << "Failed to find block device of /vbmeta";
- return FS_MGR_SETUP_AVB_FAIL;
- }
-
// Gets the expected hash value of vbmeta images from
// kernel cmdline.
if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
@@ -551,11 +488,11 @@
// of HASH partitions into fs_mgr_avb_verify_data, which is not required as
// fs_mgr only deals with HASHTREE partitions.
const char *requested_partitions[] = {nullptr};
- const char *ab_suffix =
- android::base::GetProperty("ro.boot.slot_suffix", "").c_str();
- AvbSlotVerifyResult verify_result = avb_slot_verify(
- fs_mgr_avb_ops, requested_partitions, ab_suffix,
- fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
+ std::string ab_suffix;
+ fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
+ AvbSlotVerifyResult verify_result =
+ avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
+ fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
@@ -578,12 +515,11 @@
// Checks whether FLAGS_HASHTREE_DISABLED is set.
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
- (AvbVBMetaImageHeader *)fs_mgr_avb_verify_data->vbmeta_images[0]
- .vbmeta_data,
+ (AvbVBMetaImageHeader*)fs_mgr_avb_verify_data->vbmeta_images[0].vbmeta_data,
&vbmeta_header);
- bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
- AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ bool hashtree_disabled =
+ ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
return FS_MGR_SETUP_AVB_HASHTREE_DISABLED;
}
@@ -598,8 +534,7 @@
return FS_MGR_SETUP_AVB_FAIL;
}
-void fs_mgr_unload_vbmeta_images()
-{
+void fs_mgr_unload_vbmeta_images() {
if (fs_mgr_avb_verify_data != nullptr) {
avb_slot_verify_data_free(fs_mgr_avb_verify_data);
}
@@ -609,32 +544,27 @@
}
}
-int fs_mgr_setup_avb(struct fstab_rec *fstab_entry)
-{
- if (!fstab_entry || !fs_mgr_avb_verify_data ||
- fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
+int fs_mgr_setup_avb(struct fstab_rec* fstab_entry) {
+ if (!fstab_entry || !fs_mgr_avb_verify_data || fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
return FS_MGR_SETUP_AVB_FAIL;
}
std::string partition_name(basename(fstab_entry->mount_point));
- if (!avb_validate_utf8((const uint8_t *)partition_name.c_str(),
- partition_name.length())) {
- LERROR << "Partition name: " << partition_name.c_str()
- << " is not valid UTF-8.";
+ if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
+ LERROR << "Partition name: " << partition_name.c_str() << " is not valid UTF-8.";
return FS_MGR_SETUP_AVB_FAIL;
}
AvbHashtreeDescriptor hashtree_descriptor;
std::string salt;
std::string root_digest;
- if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data,
- &hashtree_descriptor, &salt, &root_digest)) {
+ if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data, &hashtree_descriptor,
+ &salt, &root_digest)) {
return FS_MGR_SETUP_AVB_FAIL;
}
// Converts HASHTREE descriptor to verity_table_params.
- if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt,
- root_digest)) {
+ if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) {
return FS_MGR_SETUP_AVB_FAIL;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 7683166..dd8c7e7 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,15 +39,11 @@
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-static struct fstab *fs_mgr_fstab = nullptr;
+static struct fstab* fs_mgr_fstab = nullptr;
-static AvbIOResult read_from_partition(AvbOps *ops ATTRIBUTE_UNUSED,
- const char *partition,
- int64_t offset,
- size_t num_bytes,
- void *buffer,
- size_t *out_num_read)
-{
+static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
+ int64_t offset, size_t num_bytes, void* buffer,
+ size_t* out_num_read) {
// The input |partition| name is with ab_suffix, e.g. system_a.
// Slot suffix (e.g. _a) will be appended to the device file path
// for partitions having 'slotselect' optin in fstab file, but it
@@ -62,11 +58,10 @@
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
- struct fstab_rec *fstab_entry =
- fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
+ struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
if (fstab_entry == nullptr) {
- LERROR << "Partition (" << partition << ") not found in fstab";
+ LERROR << "/misc mount point not found in fstab";
return AVB_IO_RESULT_ERROR_IO;
}
@@ -79,8 +74,14 @@
path = by_name_prefix + partition_name;
}
- android::base::unique_fd fd(
- TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ // Ensures the device path (a symlink created by init) is ready to
+ // access. fs_mgr_test_access() will test a few iterations if the
+ // path doesn't exist yet.
+ if (fs_mgr_test_access(path.c_str()) < 0) {
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
PERROR << "Failed to open " << path.c_str();
@@ -105,12 +106,11 @@
// On Linux, we never get partial reads from block devices (except
// for EOF).
- ssize_t num_read =
- TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
+ ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
- PERROR << "Failed to read " << num_bytes << " bytes from "
- << path.c_str() << " offset " << offset;
+ PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
+ << offset;
return AVB_IO_RESULT_ERROR_IO;
}
@@ -121,11 +121,9 @@
return AVB_IO_RESULT_OK;
}
-static AvbIOResult dummy_read_rollback_index(AvbOps *ops ATTRIBUTE_UNUSED,
- size_t rollback_index_location
- ATTRIBUTE_UNUSED,
- uint64_t *out_rollback_index)
-{
+static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
+ size_t rollback_index_location ATTRIBUTE_UNUSED,
+ uint64_t* out_rollback_index) {
// rollback_index has been checked in bootloader phase.
// In user-space, returns the smallest value 0 to pass the check.
*out_rollback_index = 0;
@@ -133,13 +131,9 @@
}
static AvbIOResult dummy_validate_vbmeta_public_key(
- AvbOps *ops ATTRIBUTE_UNUSED,
- const uint8_t *public_key_data ATTRIBUTE_UNUSED,
- size_t public_key_length ATTRIBUTE_UNUSED,
- const uint8_t *public_key_metadata ATTRIBUTE_UNUSED,
- size_t public_key_metadata_length ATTRIBUTE_UNUSED,
- bool *out_is_trusted)
-{
+ AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
+ size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
+ size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
// vbmeta public key has been checked in bootloader phase.
// In user-space, returns true to pass the check.
//
@@ -151,9 +145,8 @@
return AVB_IO_RESULT_OK;
}
-static AvbIOResult dummy_read_is_device_unlocked(AvbOps *ops ATTRIBUTE_UNUSED,
- bool *out_is_unlocked)
-{
+static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
+ bool* out_is_unlocked) {
// The function is for bootloader to update the value into
// androidboot.vbmeta.device_state in kernel cmdline.
// In user-space, returns true as we don't need to update it anymore.
@@ -161,12 +154,9 @@
return AVB_IO_RESULT_OK;
}
-static AvbIOResult dummy_get_unique_guid_for_partition(
- AvbOps *ops ATTRIBUTE_UNUSED,
- const char *partition ATTRIBUTE_UNUSED,
- char *guid_buf,
- size_t guid_buf_size)
-{
+static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
+ const char* partition ATTRIBUTE_UNUSED,
+ char* guid_buf, size_t guid_buf_size) {
// The function is for bootloader to set the correct UUID
// for a given partition in kernel cmdline.
// In user-space, returns a faking one as we don't need to update
@@ -175,14 +165,13 @@
return AVB_IO_RESULT_OK;
}
-AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab)
-{
- AvbOps *ops;
+AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
+ AvbOps* ops;
// Assigns the fstab to the static variable for later use.
fs_mgr_fstab = fstab;
- ops = (AvbOps *)calloc(1, sizeof(AvbOps));
+ ops = (AvbOps*)calloc(1, sizeof(AvbOps));
if (ops == nullptr) {
LERROR << "Error allocating memory for AvbOps";
return nullptr;
@@ -200,7 +189,4 @@
return ops;
}
-void fs_mgr_dummy_avb_ops_free(AvbOps *ops)
-{
- free(ops);
-}
+void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); }
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h
index 9f99be8..bfdec9a 100644
--- a/fs_mgr/fs_mgr_avb_ops.h
+++ b/fs_mgr/fs_mgr_avb_ops.h
@@ -49,10 +49,10 @@
*
* Frees with fs_mgr_dummy_avb_ops_free().
*/
-AvbOps *fs_mgr_dummy_avb_ops_new(struct fstab *fstab);
+AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab);
/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
-void fs_mgr_dummy_avb_ops_free(AvbOps *ops);
+void fs_mgr_dummy_avb_ops_free(AvbOps* ops);
__END_DECLS
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
new file mode 100644
index 0000000..5b2f218
--- /dev/null
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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 <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/properties.h>
+
+#include "fs_mgr_priv.h"
+
+// Tries to get the boot config value in properties, kernel cmdline and
+// device tree (in that order). returns 'true' if successfully found, 'false'
+// otherwise
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
+ FS_MGR_CHECK(out_val != nullptr);
+
+ // first check if we have "ro.boot" property already
+ *out_val = android::base::GetProperty("ro.boot." + key, "");
+ if (!out_val->empty()) {
+ return true;
+ }
+
+ // fallback to kernel cmdline, properties may not be ready yet
+ std::string cmdline;
+ std::string cmdline_key("androidboot." + key);
+ if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+ std::vector<std::string> pieces = android::base::Split(entry, "=");
+ if (pieces.size() == 2) {
+ if (pieces[0] == cmdline_key) {
+ *out_val = pieces[1];
+ return true;
+ }
+ }
+ }
+ }
+
+ // lastly, check the device tree
+ if (is_dt_compatible()) {
+ std::string file_name = kAndroidDtDir + "/" + key;
+ // DT entries terminate with '\0' but so do the properties
+ if (android::base::ReadFileToString(file_name, out_val)) {
+ return true;
+ }
+
+ LERROR << "Error finding '" << key << "' in device tree";
+ }
+
+ return false;
+}
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
index 6012a39..4cbd5a8 100644
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -23,10 +23,7 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
-void fs_mgr_verity_ioctl_init(struct dm_ioctl *io,
- const std::string &name,
- unsigned flags)
-{
+void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags) {
memset(io, 0, DM_BUF_SIZE);
io->data_size = DM_BUF_SIZE;
io->data_start = sizeof(struct dm_ioctl);
@@ -39,10 +36,7 @@
}
}
-bool fs_mgr_create_verity_device(struct dm_ioctl *io,
- const std::string &name,
- int fd)
-{
+bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 1);
if (ioctl(fd, DM_DEV_CREATE, io)) {
PERROR << "Error creating device mapping";
@@ -51,10 +45,7 @@
return true;
}
-bool fs_mgr_destroy_verity_device(struct dm_ioctl *io,
- const std::string &name,
- int fd)
-{
+bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_REMOVE, io)) {
PERROR << "Error removing device mapping";
@@ -63,11 +54,8 @@
return true;
}
-bool fs_mgr_get_verity_device_name(struct dm_ioctl *io,
- const std::string &name,
- int fd,
- std::string *out_dev_name)
-{
+bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+ std::string* out_dev_name) {
FS_MGR_CHECK(out_dev_name != nullptr);
fs_mgr_verity_ioctl_init(io, name, 0);
@@ -82,10 +70,7 @@
return true;
}
-bool fs_mgr_resume_verity_table(struct dm_ioctl *io,
- const std::string &name,
- int fd)
-{
+bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd) {
fs_mgr_verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
PERROR << "Error activating verity device";
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 48ddf29..2e54d69 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,6 +23,10 @@
#include <sys/mount.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
#include "fs_mgr_priv.h"
struct fs_mgr_flag_values {
@@ -130,6 +135,24 @@
return size;
}
+/* fills 'dt_value' with the underlying device tree value string without
+ * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
+ * otherwise.
+ */
+static bool read_dt_file(const std::string& file_name, std::string* dt_value)
+{
+ if (android::base::ReadFileToString(file_name, dt_value)) {
+ if (!dt_value->empty()) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value->resize(dt_value->size() - 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
@@ -290,7 +313,98 @@
return f;
}
-struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = kAndroidDtDir + "/fstab/compatible";
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,fstab") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static std::string read_fstab_from_dt() {
+ std::string fstab;
+ if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+ return fstab;
+ }
+
+ std::string fstabdir_name = kAndroidDtDir + "/fstab";
+ std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+ if (!fstabdir) return fstab;
+
+ dirent* dp;
+ while ((dp = readdir(fstabdir.get())) != NULL) {
+ // skip over name and compatible
+ if (dp->d_type != DT_DIR) {
+ continue;
+ }
+
+ // skip if its not 'vendor', 'odm' or 'system'
+ if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+ strcmp(dp->d_name, "vendor")) {
+ continue;
+ }
+
+ // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
+ std::vector<std::string> fstab_entry;
+ std::string file_name;
+ std::string value;
+ file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+ fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
+
+ file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!read_dt_file(file_name, &value)) {
+ LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ fstab_entry.push_back(value);
+
+ fstab += android::base::Join(fstab_entry, " ");
+ fstab += '\n';
+ }
+
+ return fstab;
+}
+
+bool is_dt_compatible() {
+ std::string file_name = kAndroidDtDir + "/compatible";
+ std::string dt_value;
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == "android,firmware") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
{
int cnt, entries;
ssize_t len;
@@ -426,6 +540,41 @@
return NULL;
}
+/* merges fstab entries from both a and b, then returns the merged result.
+ * note that the caller should only manage the return pointer without
+ * doing further memory management for the two inputs, i.e. only need to
+ * frees up memory of the return value without touching a and b. */
+static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
+{
+ if (!a) return b;
+ if (!b) return a;
+
+ int total_entries = a->num_entries + b->num_entries;
+ a->recs = static_cast<struct fstab_rec *>(realloc(
+ a->recs, total_entries * (sizeof(struct fstab_rec))));
+ if (!a->recs) {
+ LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
+ // If realloc() fails the original block is left untouched;
+ // it is not freed or moved. So we have to free both a and b here.
+ fs_mgr_free_fstab(a);
+ fs_mgr_free_fstab(b);
+ return nullptr;
+ }
+
+ for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
+ // copy the pointer directly *without* malloc and memcpy
+ a->recs[i] = b->recs[j];
+ }
+
+ // Frees up b, but don't free b->recs[X] to make sure they are
+ // accessible through a->recs[X].
+ free(b->fstab_filename);
+ free(b);
+
+ a->num_entries = total_entries;
+ return a;
+}
+
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
FILE *fstab_file;
@@ -433,17 +582,82 @@
fstab_file = fopen(fstab_path, "r");
if (!fstab_file) {
- LERROR << "Cannot open file " << fstab_path;
- return NULL;
+ PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
+ return nullptr;
}
+
fstab = fs_mgr_read_fstab_file(fstab_file);
if (fstab) {
fstab->fstab_filename = strdup(fstab_path);
+ } else {
+ LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
}
+
fclose(fstab_file);
return fstab;
}
+/* Returns fstab entries parsed from the device tree if they
+ * exist
+ */
+struct fstab *fs_mgr_read_fstab_dt()
+{
+ std::string fstab_buf = read_fstab_from_dt();
+ if (fstab_buf.empty()) {
+ LERROR << __FUNCTION__ << "(): failed to read fstab from dt";
+ return nullptr;
+ }
+
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+ fstab_buf.length(), "r"), fclose);
+ if (!fstab_file) {
+ PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ return nullptr;
+ }
+
+ struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+ if (!fstab) {
+ LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
+ << std::endl << fstab_buf;
+ }
+
+ return fstab;
+}
+
+/* combines fstab entries passed in from device tree with
+ * the ones found from fstab_path
+ */
+struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path)
+{
+ struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
+ struct fstab *fstab = fs_mgr_read_fstab(fstab_path);
+
+ return in_place_merge(fstab_dt, fstab);
+}
+
+/*
+ * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
+ * or /. loads the first one found and also combines fstab entries passed
+ * in from device tree.
+ */
+struct fstab *fs_mgr_read_fstab_default()
+{
+ std::string hw;
+ std::string default_fstab;
+
+ if (fs_mgr_get_boot_config("hardware", &hw)) {
+ for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
+ default_fstab = prefix + hw;
+ if (access(default_fstab.c_str(), F_OK) == 0) break;
+ }
+ } else {
+ LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
+ }
+
+ return fs_mgr_read_fstab_with_dt(default_fstab.c_str());
+}
+
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
@@ -557,6 +771,11 @@
return fstab->fs_mgr_flags & MF_VERIFY;
}
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
+}
+
int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 79c27c4..377d2ec 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <fs_mgr.h>
+#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
* Thus, the log will have prefix "init: " when libfs_mgr is statically
@@ -114,6 +115,8 @@
int fs_mgr_set_blk_ro(const char *blockdev);
int fs_mgr_test_access(const char *device);
int fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool is_dt_compatible();
+bool is_device_secure();
__END_DECLS
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h
index 6d0171c..dce9f61 100644
--- a/fs_mgr/fs_mgr_priv_avb.h
+++ b/fs_mgr/fs_mgr_priv_avb.h
@@ -45,11 +45,11 @@
* developers to make the filesystem writable to allow replacing
* binaries on the device.
*/
-int fs_mgr_load_vbmeta_images(struct fstab *fstab);
+int fs_mgr_load_vbmeta_images(struct fstab* fstab);
void fs_mgr_unload_vbmeta_images();
-int fs_mgr_setup_avb(struct fstab_rec *fstab_entry);
+int fs_mgr_setup_avb(struct fstab_rec* fstab_entry);
__END_DECLS
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_boot_config.h
similarity index 63%
rename from fs_mgr/fs_mgr_priv_verity.h
rename to fs_mgr/fs_mgr_priv_boot_config.h
index 1a6d215..8773d33 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_boot_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
+#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+
#include <sys/cdefs.h>
+#include <string>
-#define FS_MGR_SETUP_VERITY_DISABLED (-2)
-#define FS_MGR_SETUP_VERITY_FAIL (-1)
-#define FS_MGR_SETUP_VERITY_SUCCESS 0
+const std::string kAndroidDtDir("/proc/device-tree/firmware/android");
-__BEGIN_DECLS
+bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev);
-
-__END_DECLS
+#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
diff --git a/fs_mgr/fs_mgr_priv_dm_ioctl.h b/fs_mgr/fs_mgr_priv_dm_ioctl.h
index eeae4dd..a00a9c1 100644
--- a/fs_mgr/fs_mgr_priv_dm_ioctl.h
+++ b/fs_mgr/fs_mgr_priv_dm_ioctl.h
@@ -17,28 +17,18 @@
#ifndef __CORE_FS_MGR_PRIV_DM_IOCTL_H
#define __CORE_FS_MGR_PRIV_DM_IOCTL_H
-#include <string>
#include <linux/dm-ioctl.h>
+#include <string>
-void fs_mgr_verity_ioctl_init(struct dm_ioctl *io,
- const std::string &name,
- unsigned flags);
+void fs_mgr_verity_ioctl_init(struct dm_ioctl* io, const std::string& name, unsigned flags);
-bool fs_mgr_create_verity_device(struct dm_ioctl *io,
- const std::string &name,
- int fd);
+bool fs_mgr_create_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
-bool fs_mgr_destroy_verity_device(struct dm_ioctl *io,
- const std::string &name,
- int fd);
+bool fs_mgr_destroy_verity_device(struct dm_ioctl* io, const std::string& name, int fd);
-bool fs_mgr_get_verity_device_name(struct dm_ioctl *io,
- const std::string &name,
- int fd,
- std::string *out_dev_name);
+bool fs_mgr_get_verity_device_name(struct dm_ioctl* io, const std::string& name, int fd,
+ std::string* out_dev_name);
-bool fs_mgr_resume_verity_table(struct dm_ioctl *io,
- const std::string &name,
- int fd);
+bool fs_mgr_resume_verity_table(struct dm_ioctl* io, const std::string& name, int fd);
#endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/fs_mgr_priv_sha.h
index 1abc273..882411b 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/fs_mgr_priv_sha.h
@@ -19,8 +19,7 @@
#include <openssl/sha.h>
-class SHA256Hasher
-{
+class SHA256Hasher {
private:
SHA256_CTX sha256_ctx;
uint8_t hash[SHA256_DIGEST_LENGTH];
@@ -28,25 +27,17 @@
public:
enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH };
- SHA256Hasher()
- {
- SHA256_Init(&sha256_ctx);
- }
+ SHA256Hasher() { SHA256_Init(&sha256_ctx); }
- void update(const void *data, size_t data_size)
- {
- SHA256_Update(&sha256_ctx, data, data_size);
- }
+ void update(const void* data, size_t data_size) { SHA256_Update(&sha256_ctx, data, data_size); }
- const uint8_t *finalize()
- {
+ const uint8_t* finalize() {
SHA256_Final(hash, &sha256_ctx);
return hash;
}
};
-class SHA512Hasher
-{
+class SHA512Hasher {
private:
SHA512_CTX sha512_ctx;
uint8_t hash[SHA512_DIGEST_LENGTH];
@@ -54,18 +45,13 @@
public:
enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
- SHA512Hasher()
- {
- SHA512_Init(&sha512_ctx);
- }
+ SHA512Hasher() { SHA512_Init(&sha512_ctx); }
- void update(const uint8_t *data, size_t data_size)
- {
+ void update(const uint8_t* data, size_t data_size) {
SHA512_Update(&sha512_ctx, data, data_size);
}
- const uint8_t *finalize()
- {
+ const uint8_t* finalize() {
SHA512_Final(hash, &sha512_ctx);
return hash;
}
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 94b43e4..f3bba7b 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -14,120 +14,31 @@
* limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <ctype.h>
-#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/properties.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-#include "bootloader.h"
-
-// Copies slot_suffix from misc into |out_suffix|. Returns 0 on
-// success, -1 on error or if there is no non-empty slot_suffix.
-static int get_active_slot_suffix_from_misc(struct fstab *fstab,
- char *out_suffix,
- size_t suffix_len)
-{
- int n;
- int misc_fd;
- ssize_t num_read;
- struct bootloader_message_ab msg;
-
- misc_fd = -1;
- for (n = 0; n < fstab->num_entries; n++) {
- if (strcmp(fstab->recs[n].mount_point, "/misc") == 0) {
- misc_fd = open(fstab->recs[n].blk_device, O_RDONLY);
- if (misc_fd == -1) {
- PERROR << "Error opening misc partition '"
- << fstab->recs[n].blk_device << "'";
- return -1;
- } else {
- break;
- }
- }
- }
-
- if (misc_fd == -1) {
- LERROR << "Error finding misc partition";
- return -1;
- }
-
- num_read = TEMP_FAILURE_RETRY(read(misc_fd, &msg, sizeof(msg)));
- // Linux will never return partial reads when reading from block
- // devices so no need to worry about them.
- if (num_read != sizeof(msg)) {
- PERROR << "Error reading bootloader_message";
- close(misc_fd);
- return -1;
- }
- close(misc_fd);
- if (msg.slot_suffix[0] == '\0')
- return -1;
- strncpy(out_suffix, msg.slot_suffix, suffix_len);
- return 0;
-}
-
-// Gets slot_suffix from either the kernel cmdline / firmware or the
-// misc partition. Sets |out_suffix| on success and returns 0. Returns
-// -1 if slot_suffix could not be determined.
-static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
- size_t suffix_len)
-{
- char propbuf[PROPERTY_VALUE_MAX];
-
- // Get the suffix from the kernel commandline (note that we don't
- // allow the empty suffix). On bootloaders natively supporting A/B
- // we'll hit this path every time so don't bother logging it.
- property_get("ro.boot.slot_suffix", propbuf, "");
- if (propbuf[0] != '\0') {
- strncpy(out_suffix, propbuf, suffix_len);
- return 0;
- }
-
- // If we couldn't get the suffix from the kernel cmdline, try the
- // the misc partition.
- if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
- LINFO << "Using slot suffix '" << out_suffix << "' from misc";
- return 0;
- }
-
- LERROR << "Error determining slot_suffix";
-
- return -1;
-}
-
// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
int fs_mgr_update_for_slotselect(struct fstab *fstab)
{
int n;
- char suffix[PROPERTY_VALUE_MAX];
int got_suffix = 0;
+ std::string suffix;
for (n = 0; n < fstab->num_entries; n++) {
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
char *tmp;
if (!got_suffix) {
- memset(suffix, '\0', sizeof(suffix));
- if (get_active_slot_suffix(fstab, suffix,
- sizeof(suffix) - 1) != 0) {
+ if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
return -1;
}
got_suffix = 1;
}
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
- suffix) > 0) {
+ suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 1ec4540..54a6f71 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <crypto_utils/android_pubkey.h>
@@ -45,9 +46,6 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
-#include "fs_mgr_priv_verity.h"
-
-#define FSTAB_PREFIX "/fstab."
#define VERITY_TABLE_RSA_KEY "/verity_key"
#define VERITY_TABLE_HASH_IDX 8
@@ -658,7 +656,6 @@
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
- char propbuf[PROPERTY_VALUE_MAX];
int match = 0;
off64_t offset = 0;
@@ -666,10 +663,9 @@
*mode = VERITY_MODE_EIO;
/* use the kernel parameter if set */
- property_get("ro.boot.veritymode", propbuf, "");
-
- if (*propbuf != '\0') {
- if (!strcmp(propbuf, "enforcing")) {
+ std::string veritymode;
+ if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
+ if (veritymode.compare("enforcing")) {
*mode = VERITY_MODE_DEFAULT;
}
return 0;
@@ -697,8 +693,6 @@
int fs_mgr_load_verity_state(int *mode)
{
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
- char propbuf[PROPERTY_VALUE_MAX];
int rc = -1;
int i;
int current;
@@ -708,13 +702,9 @@
* logging mode, in which case return that */
*mode = VERITY_MODE_DEFAULT;
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -748,7 +738,6 @@
{
alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
bool system_root = false;
- char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
std::string mount_point;
char propbuf[PROPERTY_VALUE_MAX];
const char *status;
@@ -768,22 +757,16 @@
}
fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
-
if (fd == -1) {
PERROR << "Error opening device mapper";
goto out;
}
- property_get("ro.hardware", propbuf, "");
- snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
-
property_get("ro.build.system_root_image", propbuf, "");
system_root = !strcmp(propbuf, "true");
-
- fstab = fs_mgr_read_fstab(fstab_filename);
-
+ fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- LERROR << "Failed to read " << fstab_filename;
+ LERROR << "Failed to read default fstab";
goto out;
}
@@ -859,7 +842,10 @@
*table = strdup(result.c_str());
}
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev)
+// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
+// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
+// verity device to get created before return
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
{
int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
@@ -873,6 +859,13 @@
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
+ // This is a public API and so deserves its own check to see if verity
+ // setup is needed at all.
+ if (!is_device_secure()) {
+ LINFO << "Verity setup skipped for " << mount_point;
+ return FS_MGR_SETUP_VERITY_SUCCESS;
+ }
+
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
@@ -882,6 +875,11 @@
// read verity metadata
if (fec_verity_get_metadata(f, &verity) < 0) {
PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
+ // Allow verity disabled when the device is unlocked without metadata
+ if ("0" == android::base::GetProperty("ro.boot.flash.locked", "")) {
+ retval = FS_MGR_SETUP_VERITY_DISABLED;
+ LWARNING << "Allow invalid metadata when the device is unlocked";
+ }
goto out;
}
@@ -1026,7 +1024,7 @@
}
// make sure we've set everything up properly
- if (verify_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
+ if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
goto out;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index d959798..e4aeb48 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -85,8 +85,10 @@
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
-struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
+struct fstab *fs_mgr_read_fstab_default();
+struct fstab *fs_mgr_read_fstab_dt();
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
+struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
@@ -103,7 +105,8 @@
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
-int fs_mgr_do_tmpfs_mount(char *n_name);
+int fs_mgr_do_mount_one(struct fstab_rec *rec);
+int fs_mgr_do_tmpfs_mount(const char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
char *real_blk_device, int size);
@@ -116,6 +119,7 @@
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
int fs_mgr_is_verified(const struct fstab_rec *fstab);
+int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab);
int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
@@ -123,6 +127,7 @@
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_slotselect(struct fstab_rec *fstab);
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_is_latemount(struct fstab_rec *fstab);
int fs_mgr_is_quota(struct fstab_rec *fstab);
@@ -130,10 +135,10 @@
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
-#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
-#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
-#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
-int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
+#define FS_MGR_SETUP_VERITY_SUCCESS 0
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
#ifdef __cplusplus
}
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 0c90a54..45b6eda 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -129,7 +129,7 @@
}
int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
- if (android::base::ReadFileToString(String8::std_string(path), buf)) {
+ if (android::base::ReadFileToString(path.c_str(), buf)) {
*buf = android::base::Trim(*buf);
}
return buf->length();
diff --git a/include/system/qemu_pipe.h b/include/system/qemu_pipe.h
deleted file mode 100644
index af25079..0000000
--- a/include/system/qemu_pipe.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 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 ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-
-// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
-// occurs during pipe operations. The macro should simply take a printf-style
-// formatting string followed by optional arguments.
-#ifndef QEMU_PIPE_DEBUG
-# define QEMU_PIPE_DEBUG(...) (void)0
-#endif
-
-// Try to open a new Qemu fast-pipe. This function returns a file descriptor
-// that can be used to communicate with a named service managed by the
-// emulator.
-//
-// This file descriptor can be used as a standard pipe/socket descriptor.
-//
-// 'pipeName' is the name of the emulator service you want to connect to,
-// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
-//
-// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
-//
-// EINVAL -> unknown/unsupported pipeName
-// ENOSYS -> fast pipes not available in this system.
-//
-// ENOSYS should never happen, except if you're trying to run within a
-// misconfigured emulator.
-//
-// You should be able to open several pipes to the same pipe service,
-// except for a few special cases (e.g. GSM modem), where EBUSY will be
-// returned if more than one client tries to connect to it.
-static __inline__ int qemu_pipe_open(const char* pipeName) {
- // Sanity check.
- if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
- errno = EINVAL;
- return -1;
- }
-
- int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
- if (fd < 0) {
- QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
- strerror(errno));
- return -1;
- }
-
- // Write the pipe name, *including* the trailing zero which is necessary.
- size_t pipeNameLen = strlen(pipeName);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
- if (ret != (ssize_t)pipeNameLen + 1) {
- QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
- __FUNCTION__, pipeName, strerror(errno));
- if (ret == 0) {
- errno = ECONNRESET;
- } else if (ret > 0) {
- errno = EINVAL;
- }
- return -1;
- }
- return fd;
-}
-
-// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
-// This really adds a 4-hexchar prefix describing the payload size.
-// Returns 0 on success, and -1 on error.
-static int __inline__ qemu_pipe_frame_send(int fd,
- const void* buff,
- size_t len) {
- char header[5];
- snprintf(header, sizeof(header), "%04zx", len);
- ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
- if (ret != (ssize_t)len) {
- QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
-// If the framed message is larger than |len|, then this returns -1 and the
-// content is lost. Otherwise, this returns the size of the message. NOTE:
-// empty messages are possible in a framed wire protocol and do not mean
-// end-of-stream.
-static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
- char header[5];
- ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
- if (ret != 4) {
- QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
- return -1;
- }
- header[4] = '\0';
- size_t size;
- if (sscanf(header, "%04zx", &size) != 1) {
- QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
- return -1;
- }
- if (size > len) {
- QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
- len);
- return -1;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
- if (ret != (ssize_t)size) {
- QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
- strerror(errno));
- return -1;
- }
- return size;
-}
-
-#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/init/.clang-format b/init/.clang-format
new file mode 120000
index 0000000..1af4f51
--- /dev/null
+++ b/init/.clang-format
@@ -0,0 +1 @@
+../.clang-format-4
\ No newline at end of file
diff --git a/init/Android.mk b/init/Android.mk
index 9e61fb2..2a1ad9c 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -17,6 +17,7 @@
-Wall -Wextra \
-Wno-unused-parameter \
-Werror \
+ -std=gnu++1z \
# --
@@ -107,6 +108,34 @@
libnl \
libavb
+# Include SELinux policy. We do this here because different modules
+# need to be included based on the value of PRODUCT_FULL_TREBLE. This
+# type of conditional inclusion cannot be done in top-level files such
+# as build/target/product/embedded.mk.
+# This conditional inclusion closely mimics the conditional logic
+# inside init/init.cpp for loading SELinux policy from files.
+ifeq ($(PRODUCT_FULL_TREBLE),true)
+# Use split SELinux policy
+LOCAL_REQUIRED_MODULES += \
+ mapping_sepolicy.cil \
+ nonplat_sepolicy.cil \
+ plat_sepolicy.cil \
+ plat_sepolicy.cil.sha256 \
+ secilc \
+ nonplat_file_contexts \
+ plat_file_contexts
+
+# Include precompiled policy, unless told otherwise
+ifneq ($(PRODUCT_PRECOMPILED_SEPOLICY),false)
+LOCAL_REQUIRED_MODULES += precompiled_sepolicy precompiled_sepolicy.plat.sha256
+endif
+
+else
+# Use monolithic SELinux policy
+LOCAL_REQUIRED_MODULES += sepolicy \
+ file_contexts.bin
+endif
+
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
@@ -123,6 +152,7 @@
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
init_parser_test.cpp \
+ property_service_test.cpp \
util_test.cpp \
LOCAL_SHARED_LIBRARIES += \
@@ -134,3 +164,8 @@
LOCAL_CLANG := true
LOCAL_CPPFLAGS := -Wall -Wextra -Werror
include $(BUILD_NATIVE_TEST)
+
+
+# Include targets in subdirs.
+# =========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/init/README.md b/init/README.md
index c76a33b..d3dd73a 100644
--- a/init/README.md
+++ b/init/README.md
@@ -26,7 +26,7 @@
Init .rc Files
--------------
The init language is used in plain text files that take the .rc file
-extension. These are typically multiple of these in multiple
+extension. There are typically multiple of these in multiple
locations on the system, described below.
/init.rc is the primary .rc file and is loaded by the init executable
diff --git a/init/action.cpp b/init/action.cpp
index 65bf292..1bba0f2 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -146,8 +146,7 @@
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
- auto res = property_triggers_.emplace(prop_name, prop_value);
- if (res.second == false) {
+ if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
*err = "multiple property triggers found for same property";
return false;
}
@@ -212,9 +211,7 @@
}
bool found = name.empty();
- for (const auto& t : property_triggers_) {
- const auto& trigger_name = t.first;
- const auto& trigger_value = t.second;
+ for (const auto& [trigger_name, trigger_value] : property_triggers_) {
if (trigger_name == name) {
if (trigger_value != "*" && trigger_value != value) {
return false;
@@ -249,20 +246,16 @@
}
std::string Action::BuildTriggersString() const {
- std::string result;
+ std::vector<std::string> triggers;
- for (const auto& t : property_triggers_) {
- result += t.first;
- result += '=';
- result += t.second;
- result += ' ';
+ for (const auto& [trigger_name, trigger_value] : property_triggers_) {
+ triggers.emplace_back(trigger_name + '=' + trigger_value);
}
if (!event_trigger_.empty()) {
- result += event_trigger_;
- result += ' ';
+ triggers.emplace_back(event_trigger_);
}
- result.pop_back();
- return result;
+
+ return Join(triggers, " && ");
}
void Action::DumpState() const {
@@ -271,7 +264,7 @@
for (const auto& c : commands_) {
std::string cmd_str = c.BuildCommandString();
- LOG(INFO) << " %s" << cmd_str;
+ LOG(INFO) << " " << cmd_str;
}
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2388edc..0b2e761 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -476,21 +476,28 @@
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
Parser& parser = Parser::GetInstance();
if (end_index <= start_index) {
- // Use the default set if no path is given
- static const std::vector<std::string> init_directories = {
- "/system/etc/init",
- "/vendor/etc/init",
- "/odm/etc/init"
- };
-
- for (const auto& dir : init_directories) {
- parser.ParseConfig(dir);
+ // Fallbacks for partitions on which early mount isn't enabled.
+ if (!parser.is_system_etc_init_loaded()) {
+ parser.ParseConfig("/system/etc/init");
+ parser.set_is_system_etc_init_loaded(true);
+ }
+ if (!parser.is_vendor_etc_init_loaded()) {
+ parser.ParseConfig("/vendor/etc/init");
+ parser.set_is_vendor_etc_init_loaded(true);
+ }
+ if (!parser.is_odm_etc_init_loaded()) {
+ parser.ParseConfig("/odm/etc/init");
+ parser.set_is_odm_etc_init_loaded(true);
}
} else {
for (size_t i = start_index; i < end_index; ++i) {
parser.ParseConfig(args[i]);
}
}
+
+ // Turning this on and letting the INFO logging be discarded adds 0.2s to
+ // Nexus 9 boot time, so it's disabled by default.
+ if (false) parser.DumpState();
}
/* mount_fstab
@@ -601,20 +608,27 @@
int mount_mode = MOUNT_MODE_DEFAULT;
const char* fstabfile = args[1].c_str();
std::size_t path_arg_end = args.size();
+ const char* prop_post_fix = "default";
for (na = args.size() - 1; na > 1; --na) {
if (args[na] == "--early") {
path_arg_end = na;
queue_event = false;
mount_mode = MOUNT_MODE_EARLY;
+ prop_post_fix = "early";
} else if (args[na] == "--late") {
path_arg_end = na;
import_rc = false;
mount_mode = MOUNT_MODE_LATE;
+ prop_post_fix = "late";
}
}
+ std::string prop_name = android::base::StringPrintf("ro.boottime.init.mount_all.%s",
+ prop_post_fix);
+ Timer t;
int ret = mount_fstab(fstabfile, mount_mode);
+ property_set(prop_name.c_str(), std::to_string(t.duration_ms()).c_str());
if (import_rc) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
diff --git a/init/devices.cpp b/init/devices.cpp
index 6af237c..405f92e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -62,19 +62,7 @@
extern struct selabel_handle *sehandle;
-static int device_fd = -1;
-
-struct uevent {
- const char *action;
- const char *path;
- const char *subsystem;
- const char *firmware;
- const char *partition_name;
- const char *device_name;
- int partition_num;
- int major;
- int minor;
-};
+static android::base::unique_fd device_fd;
struct perms_ {
char *name;
@@ -249,11 +237,13 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
- PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
- return;
+ if (sehandle) {
+ if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
+ return;
+ }
+ setfscreatecon(secontext);
}
- setfscreatecon(secontext);
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
@@ -261,10 +251,13 @@
* some device nodes, so the uid has to be set with chown() and is still
* racy. Fixing the gid race at least fixed the issue with system_server
* opening dynamic input devices under the AID_INPUT gid. */
- setegid(gid);
+ if (setegid(gid)) {
+ PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
+ goto out;
+ }
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
- if (mknod(path, mode, dev) && (errno == EEXIST)) {
+ if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
char* fcon = nullptr;
int rc = lgetfilecon(path, &fcon);
@@ -283,10 +276,14 @@
out:
chown(path, uid, -1);
- setegid(AID_ROOT);
+ if (setegid(AID_ROOT)) {
+ PLOG(FATAL) << "setegid(AID_ROOT) failed";
+ }
- freecon(secontext);
- setfscreatecon(NULL);
+ if (secontext) {
+ freecon(secontext);
+ setfscreatecon(NULL);
+ }
}
static void add_platform_device(const char *path)
@@ -349,6 +346,19 @@
}
}
+static void destroy_platform_devices() {
+ struct listnode* node;
+ struct listnode* n;
+ struct platform_node* bus;
+
+ list_for_each_safe(node, n, &platform_names) {
+ list_remove(node);
+ bus = node_to_item(node, struct platform_node, list);
+ free(bus->path);
+ free(bus);
+ }
+}
+
/* Given a path that may start with a PCI device, populate the supplied buffer
* with the PCI domain/bus number and the peripheral ID and return 0.
* If it doesn't start with a PCI device, or there is some error, return -1 */
@@ -380,6 +390,34 @@
return 0;
}
+/* Given a path that may start with a virtual block device, populate
+ * the supplied buffer with the virtual block device ID and return 0.
+ * If it doesn't start with a virtual block device, or there is some
+ * error, return -1 */
+static int find_vbd_device_prefix(const char *path, char *buf, ssize_t buf_sz)
+{
+ const char *start, *end;
+
+ /* Beginning of the prefix is the initial "vbd-" after "/devices/" */
+ if (strncmp(path, "/devices/vbd-", 13))
+ return -1;
+
+ /* End of the prefix is one path '/' later, capturing the
+ virtual block device ID. Example: 768 */
+ start = path + 13;
+ end = strchr(start, '/');
+ if (!end)
+ return -1;
+
+ /* Make sure we have enough room for the string plus null terminator */
+ if (end - start + 1 > buf_sz)
+ return -1;
+
+ strncpy(buf, start, end - start);
+ buf[end - start] = '\0';
+ return 0;
+}
+
static void parse_event(const char *msg, struct uevent *uevent)
{
uevent->action = "";
@@ -506,6 +544,9 @@
} else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
device = buf;
type = "pci";
+ } else if (!find_vbd_device_prefix(uevent->path, buf, sizeof(buf))) {
+ device = buf;
+ type = "vbd";
} else {
return NULL;
}
@@ -515,7 +556,7 @@
return NULL;
memset(links, 0, sizeof(char *) * 4);
- LOG(INFO) << "found " << type << " device " << device;
+ LOG(VERBOSE) << "found " << type << " device " << device;
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
@@ -875,9 +916,15 @@
}
}
+static bool inline should_stop_coldboot(coldboot_action_t act)
+{
+ return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
+}
+
#define UEVENT_MSG_LEN 2048
-static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
+static inline coldboot_action_t handle_device_fd_with(
+ std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
{
char msg[UEVENT_MSG_LEN+2];
int n;
@@ -890,14 +937,18 @@
struct uevent uevent;
parse_event(msg, &uevent);
- handle_uevent(&uevent);
+ coldboot_action_t act = handle_uevent(&uevent);
+ if (should_stop_coldboot(act))
+ return act;
}
+
+ return COLDBOOT_CONTINUE;
}
-void handle_device_fd()
+coldboot_action_t handle_device_fd(coldboot_callback fn)
{
- handle_device_fd_with(
- [](struct uevent *uevent) {
+ coldboot_action_t ret = handle_device_fd_with(
+ [&](uevent* uevent) -> coldboot_action_t {
if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
@@ -907,9 +958,21 @@
}
}
- handle_device_event(uevent);
- handle_firmware_event(uevent);
+ // default is to always create the devices
+ coldboot_action_t act = COLDBOOT_CREATE;
+ if (fn) {
+ act = fn(uevent);
+ }
+
+ if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
+ handle_device_event(uevent);
+ handle_firmware_event(uevent);
+ }
+
+ return act;
});
+
+ return ret;
}
/* Coldboot walks parts of the /sys tree and pokes the uevent files
@@ -921,21 +984,24 @@
** socket's buffer.
*/
-static void do_coldboot(DIR *d)
+static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
{
struct dirent *de;
int dfd, fd;
+ coldboot_action_t act = COLDBOOT_CONTINUE;
dfd = dirfd(d);
fd = openat(dfd, "uevent", O_WRONLY);
- if(fd >= 0) {
+ if (fd >= 0) {
write(fd, "add\n", 4);
close(fd);
- handle_device_fd();
+ act = handle_device_fd(fn);
+ if (should_stop_coldboot(act))
+ return act;
}
- while((de = readdir(d))) {
+ while (!should_stop_coldboot(act) && (de = readdir(d))) {
DIR *d2;
if(de->d_type != DT_DIR || de->d_name[0] == '.')
@@ -949,89 +1015,40 @@
if(d2 == 0)
close(fd);
else {
- do_coldboot(d2);
+ act = do_coldboot(d2, fn);
closedir(d2);
}
}
+
+ // default is always to continue looking for uevents
+ return act;
}
-static void coldboot(const char *path)
+static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
{
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
- if(d) {
- do_coldboot(d.get());
- }
-}
-
-static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
-{
- const char *name;
- char devpath[DEVPATH_LEN];
-
- if (is_block && strncmp(uevent->subsystem, "block", 5))
- return;
-
- name = parse_device_name(uevent, MAX_DEV_NAME);
- if (!name) {
- LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
- << " " << uevent->partition_name << " " << uevent->partition_num
- << " " << uevent->major << ":" << uevent->minor;
- return;
+ if (d) {
+ return do_coldboot(d.get(), fn);
}
- snprintf(devpath, sizeof(devpath), "%s%s", base, name);
- make_dir(base, 0755);
-
- dev_t dev = makedev(uevent->major, uevent->minor);
- mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
- mknod(devpath, mode, dev);
+ return COLDBOOT_CONTINUE;
}
-void early_create_dev(const std::string& syspath, early_device_type dev_type)
-{
- android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
- if (dfd < 0) {
- LOG(ERROR) << "Failed to open " << syspath;
- return;
+void device_init(const char* path, coldboot_callback fn) {
+ if (!sehandle) {
+ sehandle = selinux_android_file_context_handle();
}
-
- android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
- if (fd < 0) {
- LOG(ERROR) << "Failed to open " << syspath << "/uevent";
- return;
- }
-
- fcntl(device_fd, F_SETFL, O_NONBLOCK);
-
- write(fd, "add\n", 4);
- handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/block/", true);
- } :
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/", false);
- });
-}
-
-int early_device_socket_open() {
- device_fd = uevent_open_socket(256*1024, true);
- return device_fd < 0;
-}
-
-void early_device_socket_close() {
- close(device_fd);
-}
-
-void device_init() {
- sehandle = selinux_android_file_context_handle();
- selinux_status_open(true);
-
- /* is 256K enough? udev uses 16MB! */
- device_fd = uevent_open_socket(256*1024, true);
+ // open uevent socket and selinux status only if it hasn't been
+ // done before
if (device_fd == -1) {
- return;
+ /* is 256K enough? udev uses 16MB! */
+ device_fd.reset(uevent_open_socket(256 * 1024, true));
+ if (device_fd == -1) {
+ return;
+ }
+ fcntl(device_fd, F_SETFL, O_NONBLOCK);
+ selinux_status_open(true);
}
- fcntl(device_fd, F_SETFL, O_NONBLOCK);
if (access(COLDBOOT_DONE, F_OK) == 0) {
LOG(VERBOSE) << "Skipping coldboot, already done!";
@@ -1039,13 +1056,34 @@
}
Timer t;
- coldboot("/sys/class");
- coldboot("/sys/block");
- coldboot("/sys/devices");
- close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ coldboot_action_t act;
+ if (!path) {
+ act = coldboot("/sys/class", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/block", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/devices", fn);
+ }
+ }
+ } else {
+ act = coldboot(path, fn);
+ }
+
+ // If we have a callback, then do as it says. If no, then the default is
+ // to always create COLDBOOT_DONE file.
+ if (!fn || (act == COLDBOOT_FINISH)) {
+ close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ }
+
LOG(INFO) << "Coldboot took " << t;
}
+void device_close() {
+ destroy_platform_devices();
+ device_fd.reset();
+ selinux_status_close();
+}
+
int get_device_fd() {
return device_fd;
}
diff --git a/init/devices.h b/init/devices.h
index 8e9ab7d..26a064b 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,16 +17,37 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
+#include <functional>
#include <sys/stat.h>
-extern void handle_device_fd();
-extern void device_init(void);
+enum coldboot_action_t {
+ // coldboot continues without creating the device for the uevent
+ COLDBOOT_CONTINUE = 0,
+ // coldboot continues after creating the device for the uevent
+ COLDBOOT_CREATE,
+ // coldboot stops after creating the device for uevent but doesn't
+ // create the COLDBOOT_DONE file
+ COLDBOOT_STOP,
+ // same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
+ COLDBOOT_FINISH
+};
-enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+struct uevent {
+ const char* action;
+ const char* path;
+ const char* subsystem;
+ const char* firmware;
+ const char* partition_name;
+ const char* device_name;
+ int partition_num;
+ int major;
+ int minor;
+};
-extern int early_device_socket_open();
-extern void early_device_socket_close();
-extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
+extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
+extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
+extern void device_close();
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
diff --git a/init/init.cpp b/init/init.cpp
index 43f601f..4e31865 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -43,14 +43,18 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
#include <cutils/sockets.h>
+#include <libavb/libavb.h>
#include <private/android_filesystem_config.h>
#include <fstream>
#include <memory>
+#include <set>
+#include <vector>
#include "action.h"
#include "bootchart.h"
@@ -495,28 +499,52 @@
}
}
-static void process_kernel_dt() {
- static const char android_dir[] = "/proc/device-tree/firmware/android";
+static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
- std::string file_name = StringPrintf("%s/compatible", android_dir);
+static bool is_dt_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
- std::string dt_file;
- android::base::ReadFileToString(file_name, &dt_file);
- if (!dt_file.compare("android,firmware")) {
- LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
- return;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ // trim the trailing '\0' out, otherwise the comparison
+ // will produce false-negatives.
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,firmware") {
+ return true;
+ }
}
- std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+ return false;
+}
+
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
+
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ dt_value.resize(dt_value.size() - 1);
+ if (dt_value == "android,fstab") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void process_kernel_dt() {
+ if (!is_dt_compatible()) return;
+
+ std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
if (!dir) return;
+ std::string dt_file;
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
continue;
}
- file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
+ std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -591,6 +619,248 @@
return 0;
}
+/*
+ * Forks, executes the provided program in the child, and waits for the completion in the parent.
+ * Child's stderr is captured and logged using LOG(ERROR).
+ *
+ * Returns true if the child exited with status code 0, returns false otherwise.
+ */
+static bool fork_execve_and_wait_for_completion(const char* filename, char* const argv[],
+ char* const envp[]) {
+ // Create a pipe used for redirecting child process's output.
+ // * pipe_fds[0] is the FD the parent will use for reading.
+ // * pipe_fds[1] is the FD the child will use for writing.
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == -1) {
+ PLOG(ERROR) << "Failed to create pipe";
+ return false;
+ }
+
+ pid_t child_pid = fork();
+ if (child_pid == -1) {
+ PLOG(ERROR) << "Failed to fork for " << filename;
+ return false;
+ }
+
+ if (child_pid == 0) {
+ // fork succeeded -- this is executing in the child process
+
+ // Close the pipe FD not used by this process
+ TEMP_FAILURE_RETRY(close(pipe_fds[0]));
+
+ // Redirect stderr to the pipe FD provided by the parent
+ if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
+ PLOG(ERROR) << "Failed to redirect stderr of " << filename;
+ _exit(127);
+ return false;
+ }
+ TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
+ if (execve(filename, argv, envp) == -1) {
+ PLOG(ERROR) << "Failed to execve " << filename;
+ return false;
+ }
+ // Unreachable because execve will have succeeded and replaced this code
+ // with child process's code.
+ _exit(127);
+ return false;
+ } else {
+ // fork succeeded -- this is executing in the original/parent process
+
+ // Close the pipe FD not used by this process
+ TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
+ // Log the redirected output of the child process.
+ // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
+ // As a result, we're buffering all output and logging it in one go at the end of the
+ // invocation, instead of logging it as it comes in.
+ const int child_out_fd = pipe_fds[0];
+ std::string child_output;
+ if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
+ PLOG(ERROR) << "Failed to capture full output of " << filename;
+ }
+ TEMP_FAILURE_RETRY(close(child_out_fd));
+ if (!child_output.empty()) {
+ // Log captured output, line by line, because LOG expects to be invoked for each line
+ std::istringstream in(child_output);
+ std::string line;
+ while (std::getline(in, line)) {
+ LOG(ERROR) << filename << ": " << line;
+ }
+ }
+
+ // Wait for child to terminate
+ int status;
+ if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
+ PLOG(ERROR) << "Failed to wait for " << filename;
+ return false;
+ }
+
+ if (WIFEXITED(status)) {
+ int status_code = WEXITSTATUS(status);
+ if (status_code == 0) {
+ return true;
+ } else {
+ LOG(ERROR) << filename << " exited with status " << status_code;
+ }
+ } else if (WIFSIGNALED(status)) {
+ LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
+ } else if (WIFSTOPPED(status)) {
+ LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
+ } else {
+ LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
+ }
+
+ return false;
+ }
+}
+
+static bool read_first_line(const char* file, std::string* line) {
+ line->clear();
+
+ std::string contents;
+ if (!android::base::ReadFileToString(file, &contents, true /* follow symlinks */)) {
+ return false;
+ }
+ std::istringstream in(contents);
+ std::getline(in, *line);
+ return true;
+}
+
+static bool selinux_find_precompiled_split_policy(std::string* file) {
+ file->clear();
+
+ static constexpr const char precompiled_sepolicy[] = "/vendor/etc/selinux/precompiled_sepolicy";
+ if (access(precompiled_sepolicy, R_OK) == -1) {
+ return false;
+ }
+ std::string actual_plat_id;
+ if (!read_first_line("/system/etc/selinux/plat_sepolicy.cil.sha256", &actual_plat_id)) {
+ PLOG(INFO) << "Failed to read /system/etc/selinux/plat_sepolicy.cil.sha256";
+ return false;
+ }
+ std::string precompiled_plat_id;
+ if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat.sha256",
+ &precompiled_plat_id)) {
+ PLOG(INFO) << "Failed to read /vendor/etc/selinux/precompiled_sepolicy.plat.sha256";
+ return false;
+ }
+ if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
+ return false;
+ }
+
+ *file = precompiled_sepolicy;
+ return true;
+}
+
+static constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
+
+static bool selinux_is_split_policy_device() { return access(plat_policy_cil_file, R_OK) != -1; }
+
+/*
+ * Loads SELinux policy split across platform/system and non-platform/vendor files.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_split_policy() {
+ // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
+ // * platform -- policy needed due to logic contained in the system image,
+ // * non-platform -- policy needed due to logic contained in the vendor image,
+ // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
+ // with newer versions of platform policy.
+ //
+ // secilc is invoked to compile the above three policy files into a single monolithic policy
+ // file. This file is then loaded into the kernel.
+
+ // Load precompiled policy from vendor image, if a matching policy is found there. The policy
+ // must match the platform policy on the system image.
+ std::string precompiled_sepolicy_file;
+ if (selinux_find_precompiled_split_policy(&precompiled_sepolicy_file)) {
+ android::base::unique_fd fd(
+ open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
+ if (fd != -1) {
+ if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
+ LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
+ return false;
+ }
+ return true;
+ }
+ }
+ // No suitable precompiled policy could be loaded
+
+ LOG(INFO) << "Compiling SELinux policy";
+
+ // Determine the highest policy language version supported by the kernel
+ set_selinuxmnt("/sys/fs/selinux");
+ int max_policy_version = security_policyvers();
+ if (max_policy_version == -1) {
+ PLOG(ERROR) << "Failed to determine highest policy version supported by kernel";
+ return false;
+ }
+
+ // We store the output of the compilation on /dev because this is the most convenient tmpfs
+ // storage mount available this early in the boot sequence.
+ char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
+ android::base::unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
+ if (compiled_sepolicy_fd < 0) {
+ PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
+ return false;
+ }
+
+ // clang-format off
+ const char* compile_args[] = {
+ "/system/bin/secilc",
+ plat_policy_cil_file,
+ "-M", "true",
+ // Target the highest policy language version supported by the kernel
+ "-c", std::to_string(max_policy_version).c_str(),
+ "/vendor/etc/selinux/mapping_sepolicy.cil",
+ "/vendor/etc/selinux/nonplat_sepolicy.cil",
+ "-o", compiled_sepolicy,
+ // We don't care about file_contexts output by the compiler
+ "-f", "/sys/fs/selinux/null", // /dev/null is not yet available
+ nullptr};
+ // clang-format on
+
+ if (!fork_execve_and_wait_for_completion(compile_args[0], (char**)compile_args, (char**)ENV)) {
+ unlink(compiled_sepolicy);
+ return false;
+ }
+ unlink(compiled_sepolicy);
+
+ LOG(INFO) << "Loading compiled SELinux policy";
+ if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) {
+ LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy;
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Loads SELinux policy from a monolithic file.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_monolithic_policy() {
+ LOG(VERBOSE) << "Loading SELinux policy from monolithic file";
+ if (selinux_android_load_policy() < 0) {
+ PLOG(ERROR) << "Failed to load monolithic SELinux policy";
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Loads SELinux policy into the kernel.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_policy() {
+ return selinux_is_split_policy_device() ? selinux_load_split_policy()
+ : selinux_load_monolithic_policy();
+}
+
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -601,10 +871,9 @@
selinux_set_callback(SELINUX_CB_AUDIT, cb);
if (in_kernel_domain) {
- LOG(INFO) << "Loading SELinux policy...";
- if (selinux_android_load_policy() < 0) {
- PLOG(ERROR) << "failed to load policy";
- security_failure();
+ LOG(INFO) << "Loading SELinux policy";
+ if (!selinux_load_policy()) {
+ panic();
}
bool kernel_enforcing = (security_getenforce() == 1);
@@ -643,102 +912,191 @@
}
}
-/* Returns a new path consisting of base_path and the file name in reference_path. */
-static std::string get_path(const std::string& base_path, const std::string& reference_path) {
- std::string::size_type pos = reference_path.rfind('/');
- if (pos == std::string::npos) {
- return base_path + '/' + reference_path;
- } else {
- return base_path + reference_path.substr(pos);
- }
-}
+static bool early_mount_one(struct fstab_rec* rec) {
+ if (rec && fs_mgr_is_verified(rec)) {
+ // setup verity and create the dm-XX block device
+ // needed to mount this partition
+ int ret = fs_mgr_setup_verity(rec, false);
+ if (ret == FS_MGR_SETUP_VERITY_FAIL) {
+ PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'";
+ return false;
+ }
-/* Imports the fstab info from cmdline. */
-static std::string import_cmdline_fstab() {
- std::string prefix, fstab, fstab_full;
-
- import_kernel_cmdline(false,
- [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
- if (key == "android.early.prefix") {
- prefix = value;
- } else if (key == "android.early.fstab") {
- fstab = value;
+ // The exact block device name is added as a mount source by
+ // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX"
+ // We create that device by running coldboot on /sys/block/dm-XX
+ std::string dm_device(basename(rec->blk_device));
+ std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str());
+ device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+ if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) {
+ LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+ return COLDBOOT_STOP;
}
+ return COLDBOOT_CONTINUE;
});
- if (!fstab.empty()) {
- // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
- std::replace(fstab.begin(), fstab.end(), '+', ' ');
- for (const auto& entry : android::base::Split(fstab, "\n")) {
- fstab_full += prefix + entry + '\n';
- }
}
- return fstab_full;
+
+ if (rec && fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
+ return false;
+ }
+
+ return true;
}
-/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
-static void early_mount() {
- std::string fstab_string = import_cmdline_fstab();
- if (fstab_string.empty()) {
- LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
+// Creates devices with uevent->partition_name matching one in the in/out
+// partition_names. Note that the partition_names MUST have A/B suffix
+// when A/B is used. Found partitions will then be removed from the
+// partition_names for caller to check which devices are NOT created.
+static void early_device_init(std::set<std::string>* partition_names) {
+ if (partition_names->empty()) {
return;
}
- FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
- if (!fstab_file) {
- PLOG(ERROR) << "Failed to open fstab string as FILE";
- return;
- }
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
- fclose(fstab_file);
- if (!fstab) {
- LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
- return;
- }
- LOG(INFO) << "Loaded vendor fstab from cmdline";
-
- if (early_device_socket_open()) {
- LOG(ERROR) << "Failed to open device uevent socket";
- return;
- }
-
- /* Create /dev/device-mapper for dm-verity */
- early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
-
- for (int i = 0; i < fstab->num_entries; ++i) {
- struct fstab_rec *rec = &fstab->recs[i];
- std::string mount_point = rec->mount_point;
- std::string syspath = rec->blk_device;
-
- if (mount_point != "/vendor" && mount_point != "/odm")
- continue;
-
- /* Create mount target under /dev/block/ from sysfs via uevent */
- LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
- char *devpath = strdup(get_path("/dev/block", syspath).c_str());
- if (!devpath) {
- PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
- continue;
- }
- rec->blk_device = devpath;
- early_create_dev(syspath, EARLY_BLOCK_DEV);
-
- int rc = fs_mgr_early_setup_verity(rec);
- if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
- /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
- early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
- } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
- LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
- continue;
- } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
- LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+ device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
+ if (!strncmp(uevent->subsystem, "firmware", 8)) {
+ return COLDBOOT_CONTINUE;
}
- mkdir(mount_point.c_str(), 0755);
- rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
- if (rc) {
- PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+ // we need platform devices to create symlinks
+ if (!strncmp(uevent->subsystem, "platform", 8)) {
+ return COLDBOOT_CREATE;
+ }
+
+ // Ignore everything that is not a block device
+ if (strncmp(uevent->subsystem, "block", 5)) {
+ return COLDBOOT_CONTINUE;
+ }
+
+ if (uevent->partition_name) {
+ // match partition names to create device nodes for partitions
+ // both partition_names and uevent->partition_name have A/B suffix when A/B is used
+ auto iter = partition_names->find(uevent->partition_name);
+ if (iter != partition_names->end()) {
+ LOG(VERBOSE) << "early_mount: found partition: " << *iter;
+ partition_names->erase(iter);
+ if (partition_names->empty()) {
+ return COLDBOOT_STOP; // found all partitions, stop coldboot
+ } else {
+ return COLDBOOT_CREATE; // create this device and continue to find others
+ }
+ }
+ }
+ // Not found a partition or find an unneeded partition, continue to find others
+ return COLDBOOT_CONTINUE;
+ });
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions, bool* out_need_verity) {
+ std::string meta_partition;
+ out_partitions->clear();
+ *out_need_verity = false;
+
+ for (auto fstab_rec : early_fstab_recs) {
+ // don't allow verifyatboot for early mounted partitions
+ if (fs_mgr_is_verifyatboot(fstab_rec)) {
+ LOG(ERROR) << "early_mount: partitions can't be verified at boot";
+ return false;
+ }
+ // check for verified partitions
+ if (fs_mgr_is_verified(fstab_rec)) {
+ *out_need_verity = true;
+ }
+ // check if verity metadata is on a separate partition and get partition
+ // name from the end of the ->verity_loc path. verity state is not partition
+ // specific, so there must be only 1 additional partition that carries
+ // verity state.
+ if (fstab_rec->verity_loc) {
+ if (!meta_partition.empty()) {
+ LOG(ERROR) << "early_mount: more than one meta partition found: " << meta_partition
+ << ", " << basename(fstab_rec->verity_loc);
+ return false;
+ } else {
+ meta_partition = basename(fstab_rec->verity_loc);
+ }
}
}
- early_device_socket_close();
+
+ // includes those early mount partitions and meta_partition (if any)
+ // note that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used
+ for (auto fstab_rec : early_fstab_recs) {
+ out_partitions->emplace(basename(fstab_rec->blk_device));
+ }
+
+ if (!meta_partition.empty()) {
+ out_partitions->emplace(std::move(meta_partition));
+ }
+
+ return true;
+}
+
+/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
+static bool early_mount() {
+ // skip early mount if we're in recovery mode
+ if (access("/sbin/recovery", F_OK) == 0) {
+ LOG(INFO) << "Early mount skipped (recovery mode)";
+ return true;
+ }
+
+ // first check if device tree fstab entries are compatible
+ if (!is_dt_fstab_compatible()) {
+ LOG(INFO) << "Early mount skipped (missing/incompatible fstab in device tree)";
+ return true;
+ }
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> tab(
+ fs_mgr_read_fstab_dt(), fs_mgr_free_fstab);
+ if (!tab) {
+ LOG(ERROR) << "Early mount failed to read fstab from device tree";
+ return false;
+ }
+
+ // find out fstab records for odm, system and vendor
+ std::vector<fstab_rec*> early_fstab_recs;
+ for (auto mount_point : {"/odm", "/system", "/vendor"}) {
+ fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(tab.get(), mount_point);
+ if (fstab_rec != nullptr) {
+ early_fstab_recs.push_back(fstab_rec);
+ }
+ }
+
+ // nothing to early mount
+ if (early_fstab_recs.empty()) return true;
+
+ bool need_verity;
+ std::set<std::string> partition_names;
+ // partition_names MUST have A/B suffix when A/B is used
+ if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
+ return false;
+ }
+
+ bool success = false;
+ // create the devices we need..
+ early_device_init(&partition_names);
+
+ // early_device_init will remove found partitions from partition_names
+ // So if the partition_names is not empty here, means some partitions
+ // are not found
+ if (!partition_names.empty()) {
+ LOG(ERROR) << "early_mount: partition(s) not found: "
+ << android::base::Join(partition_names, ", ");
+ goto done;
+ }
+
+ if (need_verity) {
+ // create /dev/device mapper
+ device_init("/sys/devices/virtual/misc/device-mapper",
+ [&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
+ }
+
+ for (auto fstab_rec : early_fstab_recs) {
+ if (!early_mount_one(fstab_rec)) goto done;
+ }
+ success = true;
+
+done:
+ device_close();
+ return success;
}
int main(int argc, char** argv) {
@@ -787,8 +1145,10 @@
LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
if (is_first_stage) {
- // Mount devices defined in android.early.* kernel commandline
- early_mount();
+ if (!early_mount()) {
+ LOG(ERROR) << "Failed to mount required partitions early ...";
+ panic();
+ }
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
@@ -831,6 +1191,9 @@
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
+ // Set libavb version for Framework-only OTA match in Treble build.
+ property_set("ro.boot.init.avb_version", std::to_string(AVB_MAJOR_VERSION).c_str());
+
// Clean up our environment.
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
@@ -879,10 +1242,22 @@
std::string bootscript = property_get("ro.boot.init_rc");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
+ parser.set_is_system_etc_init_loaded(
+ parser.ParseConfig("/system/etc/init"));
+ parser.set_is_vendor_etc_init_loaded(
+ parser.ParseConfig("/vendor/etc/init"));
+ parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
} else {
parser.ParseConfig(bootscript);
+ parser.set_is_system_etc_init_loaded(true);
+ parser.set_is_vendor_etc_init_loaded(true);
+ parser.set_is_odm_etc_init_loaded(true);
}
+ // Turning this on and letting the INFO logging be discarded adds 0.2s to
+ // Nexus 9 boot time, so it's disabled by default.
+ if (false) parser.DumpState();
+
ActionManager& am = ActionManager::GetInstance();
am.QueueEventTrigger("early-init");
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 406b339..326ebf2 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -106,10 +106,6 @@
sp.second->EndFile(path);
}
- // Turning this on and letting the INFO logging be discarded adds 0.2s to
- // Nexus 9 boot time, so it's disabled by default.
- if (false) DumpState();
-
LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
return true;
}
diff --git a/init/init_parser.h b/init/init_parser.h
index 5ed30ad..f66ba52 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -41,6 +41,18 @@
bool ParseConfig(const std::string& path);
void AddSectionParser(const std::string& name,
std::unique_ptr<SectionParser> parser);
+ void set_is_system_etc_init_loaded(bool loaded) {
+ is_system_etc_init_loaded_ = loaded;
+ }
+ void set_is_vendor_etc_init_loaded(bool loaded) {
+ is_vendor_etc_init_loaded_ = loaded;
+ }
+ void set_is_odm_etc_init_loaded(bool loaded) {
+ is_odm_etc_init_loaded_ = loaded;
+ }
+ bool is_system_etc_init_loaded() { return is_system_etc_init_loaded_; }
+ bool is_vendor_etc_init_loaded() { return is_vendor_etc_init_loaded_; }
+ bool is_odm_etc_init_loaded() { return is_odm_etc_init_loaded_; }
private:
Parser();
@@ -50,6 +62,9 @@
bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
+ bool is_system_etc_init_loaded_ = false;
+ bool is_vendor_etc_init_loaded_ = false;
+ bool is_odm_etc_init_loaded_ = false;
};
#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index ce197ee..983e684 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -49,6 +50,7 @@
#include <fs_mgr.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "bootimg.h"
@@ -57,8 +59,9 @@
#include "util.h"
#include "log.h"
+using android::base::StringPrintf;
+
#define PERSISTENT_PROPERTY_DIR "/data/property"
-#define FSTAB_PREFIX "/fstab."
#define RECOVERY_MOUNT_POINT "/recovery"
static int persistent_properties_loaded = 0;
@@ -245,6 +248,13 @@
return true;
}
+ // http://b/35166374: don't allow init to make arbitrarily large allocations.
+ if (len > 0xffff) {
+ LOG(ERROR) << "sys_prop: RecvString asked to read huge string: " << len;
+ errno = ENOMEM;
+ return false;
+ }
+
std::vector<char> chars(len);
if (!RecvChars(&chars[0], len, timeout_ms)) {
return false;
@@ -386,12 +396,11 @@
return;
}
- /* Check socket options here */
struct ucred cr;
socklen_t cr_size = sizeof(cr);
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
- PLOG(ERROR) << "Unable to receive socket options";
+ PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
return;
}
@@ -399,14 +408,13 @@
uint32_t timeout_ms = kDefaultSocketTimeout;
uint32_t cmd = 0;
-
if (!socket.RecvUint32(&cmd, &timeout_ms)) {
PLOG(ERROR) << "sys_prop: error while reading command from the socket";
socket.SendUint32(PROP_ERROR_READ_CMD);
return;
}
- switch(cmd) {
+ switch (cmd) {
case PROP_MSG_SETPROP: {
char prop_name[PROP_NAME_MAX];
char prop_value[PROP_VALUE_MAX];
@@ -437,7 +445,9 @@
handle_property_set(socket, name, value, false);
break;
}
+
default:
+ LOG(ERROR) << "sys_prop: invalid command " << cmd;
socket.SendUint32(PROP_ERROR_INVALID_CMD);
break;
}
@@ -598,24 +608,18 @@
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
+ property_set("ro.persistent_properties.ready", "true");
}
void load_recovery_id_prop() {
- std::string ro_hardware = property_get("ro.hardware");
- if (ro_hardware.empty()) {
- LOG(ERROR) << "ro.hardware not set - unable to load recovery id";
- return;
- }
- std::string fstab_filename = FSTAB_PREFIX + ro_hardware;
-
- std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename.c_str()),
- fs_mgr_free_fstab);
- if (!tab) {
- PLOG(ERROR) << "unable to read fstab " << fstab_filename;
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) {
+ PLOG(ERROR) << "unable to read default fstab";
return;
}
- fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
+ fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), RECOVERY_MOUNT_POINT);
if (rec == NULL) {
LOG(ERROR) << "/recovery not specified in fstab";
return;
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
new file mode 100644
index 0000000..4d784aa
--- /dev/null
+++ b/init/property_service_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+#include <gtest/gtest.h>
+
+TEST(property_service, very_long_name_35166374) {
+ // Connect to the property service directly...
+ int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_NE(fd, -1);
+
+ static const char* property_service_socket = "/dev/socket/" PROP_SERVICE_NAME;
+ sockaddr_un addr = {};
+ addr.sun_family = AF_LOCAL;
+ strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
+
+ socklen_t addr_len = strlen(property_service_socket) + offsetof(sockaddr_un, sun_path) + 1;
+ ASSERT_NE(connect(fd, reinterpret_cast<sockaddr*>(&addr), addr_len), -1);
+
+ // ...so we can send it a malformed request.
+ uint32_t msg = PROP_MSG_SETPROP2;
+ uint32_t size = 0xffffffff;
+ uint32_t data = 0xdeadbeef;
+
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(msg)), send(fd, &msg, sizeof(msg), 0));
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(size)), send(fd, &size, sizeof(size), 0));
+ ASSERT_EQ(static_cast<ssize_t>(sizeof(data)), send(fd, &data, sizeof(data), 0));
+ ASSERT_EQ(0, close(fd));
+}
diff --git a/init/service.cpp b/init/service.cpp
index e186f27..ba901fd 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -180,12 +180,6 @@
}
std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
- if (prop_name.length() >= PROP_NAME_MAX) {
- // If the property name would be too long, we can't set it.
- LOG(ERROR) << "Property name \"init.svc." << name_ << "\" too long; not setting to " << new_state;
- return;
- }
-
property_set(prop_name.c_str(), new_state.c_str());
if (new_state == "running") {
@@ -1040,5 +1034,9 @@
}
bool ServiceParser::IsValidName(const std::string& name) const {
- return is_legal_property_name("init.svc." + name);
+ // Property names can be any length, but may only contain certain characters.
+ // Property values can contain any characters, but may only be a certain length.
+ // (The latter restriction is needed because `start` and `stop` work by writing
+ // the service name to the "ctl.start" and "ctl.stop" properties.)
+ return is_legal_property_name("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
}
diff --git a/init/test_service/Android.mk b/init/test_service/Android.mk
new file mode 100644
index 0000000..30c9e9d
--- /dev/null
+++ b/init/test_service/Android.mk
@@ -0,0 +1,27 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Sample service for testing.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_service
+LOCAL_SRC_FILES := test_service.cpp
+
+LOCAL_SHARED_LIBRARIES += libbase
+
+LOCAL_INIT_RC := test_service.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/init/test_service/README.md b/init/test_service/README.md
new file mode 100644
index 0000000..6773235
--- /dev/null
+++ b/init/test_service/README.md
@@ -0,0 +1,43 @@
+# Sample service for testing
+This is a sample service that can be used for testing init.
+
+## Design
+The service includes a `.rc` file that allows starting it from init.
+
+ service test_service /system/bin/test_service CapAmb 0000000000003000
+ class main
+ user system
+ group system
+ capabilities NET_ADMIN NET_RAW
+ disabled
+ oneshot
+
+The service accepts any even number of arguments on the command line
+(i.e. any number of pairs of arguments.)
+It will attempt to find the first element of each pair of arguments in
+`/proc/self/status`, and attempt to exactly match the second element of the pair
+to the relevant line of `proc/self/status`.
+
+### Example
+In the above case, the service will look for lines containing `CapAmb`:
+
+ cat /proc/self/status
+ ...
+ CapAmb: 0000000000003000
+
+And then attempt to exactly match the token after `:`, `0000000000003000`,
+with the command-line argument.
+If they match, the service exits successfully. If not, the service will exit
+with an error.
+
+## Usage
+ mmma -j <jobs> system/core/init/testservice
+ adb root
+ adb remount
+ adb sync
+ adb reboot
+ adb root
+ adb shell start test_service
+ adb logcat -b all -d | grep test_service
+
+Look for an exit status of 0.
diff --git a/init/test_service/test_service.cpp b/init/test_service/test_service.cpp
new file mode 100644
index 0000000..e7206f8
--- /dev/null
+++ b/init/test_service/test_service.cpp
@@ -0,0 +1,78 @@
+// 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.
+
+#include <unistd.h>
+
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+void Usage(char* argv[]) {
+ printf("Usage: %s <status field> <value> [<status field> <value>]*\n", argv[0]);
+ printf("E.g.: $ %s Uid \"1000 1000 1000 1000\"\n", argv[0]);
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 3) {
+ Usage(argv);
+ LOG(FATAL) << "no status field requested";
+ }
+ if (argc % 2 == 0) {
+ // Since |argc| counts argv[0], if |argc| is odd, then the number of
+ // command-line arguments is even.
+ Usage(argv);
+ LOG(FATAL) << "need even number of command-line arguments";
+ }
+
+ std::string status;
+ bool res = android::base::ReadFileToString("/proc/self/status", &status, true);
+ if (!res) {
+ PLOG(FATAL) << "could not read /proc/self/status";
+ }
+
+ std::map<std::string, std::string> fields;
+ std::vector<std::string> lines = android::base::Split(status, "\n");
+ for (const auto& line : lines) {
+ std::vector<std::string> tokens = android::base::Split(line, ":");
+ if (tokens.size() >= 2) {
+ std::string field = tokens[0];
+ std::string value = android::base::Trim(tokens[1]);
+ if (field.length() > 0) {
+ fields[field] = value;
+ }
+ }
+ }
+
+ bool test_fails = false;
+ size_t uargc = static_cast<size_t>(argc); // |argc| >= 3.
+ for (size_t i = 1; i < static_cast<size_t>(argc); i = i + 2) {
+ std::string expected_value = argv[i + 1];
+ auto f = fields.find(argv[i]);
+ if (f != fields.end()) {
+ if (f->second != expected_value) {
+ LOG(ERROR) << "field '" << argv[i] << "' expected '" << expected_value
+ << "', actual '" << f->second << "'";
+ test_fails = true;
+ }
+ } else {
+ LOG(WARNING) << "could not find field '" << argv[i] << "'";
+ }
+ }
+
+ return test_fails ? 1 : 0;
+}
diff --git a/init/test_service/test_service.rc b/init/test_service/test_service.rc
new file mode 100644
index 0000000..91e1a0f
--- /dev/null
+++ b/init/test_service/test_service.rc
@@ -0,0 +1,7 @@
+service test_service /system/bin/test_service CapAmb 0000000000003000
+ class main
+ user system
+ group system
+ capabilities NET_ADMIN NET_RAW
+ disabled
+ oneshot
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 361b925..915afbd 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -60,9 +60,18 @@
cb.func_log = selinux_klog_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
- std::string hardware = property_get("ro.hardware");
-
ueventd_parse_config_file("/ueventd.rc");
+ ueventd_parse_config_file("/vendor/ueventd.rc");
+ ueventd_parse_config_file("/odm/ueventd.rc");
+
+ /*
+ * keep the current product name base configuration so
+ * we remain backwards compatible and allow it to override
+ * everything
+ * TODO: cleanup platform ueventd.rc to remove vendor specific
+ * device node entries (b/34968103)
+ */
+ std::string hardware = property_get("ro.hardware");
ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
device_init();
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index db35d33..1a1abd5 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -31,7 +31,7 @@
constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
void OpenTempFile(android::base::unique_fd* fd) {
- fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+ fd->reset(open(kTempFile, O_CREAT | O_RDWR, 0600));
ASSERT_NE(-1, *fd) << strerror(errno);
unlink(kTempFile);
ASSERT_NE(-1, *fd) << strerror(errno);
diff --git a/libbacktrace/.clang-format b/libbacktrace/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libbacktrace/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 5b31ecb..0e7c6f3 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -80,6 +80,18 @@
static_libs: ["libcutils"],
host_ldlibs: ["-lrt"],
},
+ linux_bionic: {
+ enabled: true,
+ srcs: libbacktrace_sources,
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libunwind",
+ ],
+
+ static_libs: ["libcutils"],
+ },
android: {
srcs: libbacktrace_sources,
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 5173e2c..d7a3b01 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -95,11 +95,31 @@
static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+// Since errno is stored per thread, changing it in the signal handler
+// modifies the value on the thread in which the signal handler executes.
+// If a signal occurs between a call and an errno check, it's possible
+// to get the errno set here. Always save and restore it just in case
+// code would modify it.
+class ErrnoRestorer {
+ public:
+ ErrnoRestorer() : saved_errno_(errno) {}
+ ~ErrnoRestorer() {
+ errno = saved_errno_;
+ }
+
+ private:
+ int saved_errno_;
+};
+
static void SignalLogOnly(int, siginfo_t*, void*) {
+ ErrnoRestorer restore;
+
BACK_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(), THREAD_SIGNAL);
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+ ErrnoRestorer restore;
+
ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
if (!entry) {
BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 5e54328..0a2f5a3 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -21,6 +21,7 @@
#include <dwarf.h>
}
+#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -30,6 +31,7 @@
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <string>
#include <vector>
@@ -90,9 +92,6 @@
has_debug_frame(false), has_gnu_debugdata(false) { }
};
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>& g_debug_frames =
- *new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
-
void Space::Clear() {
start = 0;
end = 0;
@@ -282,39 +281,14 @@
// vaddr in the elf file.
uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
- if (debug_frame->has_arm_exidx) {
- auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
- if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
- // Use binary search to find the correct function.
- auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
- static_cast<uint32_t>(ip_vaddr));
- if (it != func_vaddrs.begin()) {
- --it;
- // Found the exidx entry.
- size_t index = it - func_vaddrs.begin();
- proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
- proc_info->unwind_info = reinterpret_cast<void*>(
- static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
- debug_frame->arm_exidx.exidx_vaddr +
- debug_frame->min_vaddr));
-
- // Prepare arm_exidx space and arm_extab space.
- arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
- arm_exidx_space_.end = arm_exidx_space_.start +
- debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
- arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
- debug_frame->arm_exidx.exidx_data.data());
-
- arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
- arm_extab_space_.end = arm_extab_space_.start +
- debug_frame->arm_exidx.extab_data.size();
- arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
- return true;
- }
- }
- }
-
+ // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
+ // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
+ // function range for each entry, by matching ip address with the function range, we know exactly
+ // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
+ // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
+ // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
+ // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
if (debug_frame->has_eh_frame) {
if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
ip_vaddr < debug_frame->text_end_vaddr) {
@@ -323,7 +297,6 @@
eh_frame_hdr_space_.end =
eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
-
eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
eh_frame_space_.data = debug_frame->eh_frame.data.data();
@@ -345,7 +318,6 @@
}
}
}
-
if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
unw_dyn_info_t di;
unw_word_t segbase = map.start - map.offset;
@@ -359,6 +331,40 @@
}
}
}
+
+ if (debug_frame->has_arm_exidx) {
+ auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
+ if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
+ // Use binary search to find the correct function.
+ auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
+ static_cast<uint32_t>(ip_vaddr));
+ if (it != func_vaddrs.begin()) {
+ --it;
+ // Found the exidx entry.
+ size_t index = it - func_vaddrs.begin();
+ proc_info->start_ip = *it;
+ proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+ proc_info->unwind_info = reinterpret_cast<void*>(
+ static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
+ debug_frame->arm_exidx.exidx_vaddr +
+ debug_frame->min_vaddr));
+ eh_frame_hdr_space_.Clear();
+ eh_frame_space_.Clear();
+ // Prepare arm_exidx space and arm_extab space.
+ arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
+ arm_exidx_space_.end = arm_exidx_space_.start +
+ debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
+ arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
+ debug_frame->arm_exidx.exidx_data.data());
+
+ arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
+ arm_extab_space_.end = arm_extab_space_.start +
+ debug_frame->arm_exidx.extab_data.size();
+ arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
+ return true;
+ }
+ }
+ }
return false;
}
@@ -549,18 +555,31 @@
return "";
}
+static std::mutex g_lock;
+static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
+
static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
if (cache_file_) {
- auto it = g_debug_frames.find(filename);
- if (it != g_debug_frames.end()) {
- return it->second.get();
+ std::lock_guard<std::mutex> lock(g_lock);
+ if (g_debug_frames != nullptr) {
+ auto it = g_debug_frames->find(filename);
+ if (it != g_debug_frames->end()) {
+ return it->second.get();
+ }
}
}
DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
if (cache_file_) {
- g_debug_frames.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+ std::lock_guard<std::mutex> lock(g_lock);
+ if (g_debug_frames == nullptr) {
+ g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
+ }
+ auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+ if (!pair.second) {
+ debug_frame = pair.first->second.get();
+ }
}
return debug_frame;
}
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 49fcb29..465b3f9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -220,25 +220,7 @@
#endif
}
-static void BacktraceOfflineTest(const std::string& testlib_name) {
- const std::string arch = GetArch();
- if (arch.empty()) {
- GTEST_LOG_(INFO) << "This test does nothing on current arch.";
- return;
- }
- const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
- std::string testdata;
- ASSERT_TRUE(android::base::ReadFileToString(offline_testdata_path, &testdata));
-
- const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
- struct stat st;
- if (stat(testlib_path.c_str(), &st) == -1) {
- GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
- return;
- }
-
- // Parse offline_testdata.
- std::vector<std::string> lines = android::base::Split(testdata, "\n");
+struct OfflineTestData {
int pid;
int tid;
std::vector<backtrace_map_t> maps;
@@ -246,63 +228,93 @@
backtrace_stackinfo_t stack_info;
std::vector<uint8_t> stack;
std::vector<FunctionSymbol> symbols;
+};
+
+bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
+ std::string s;
+ if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
+ return false;
+ }
+ // Parse offline_testdata.
+ std::vector<std::string> lines = android::base::Split(s, "\n");
+ memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
for (const auto& line : lines) {
if (android::base::StartsWith(line, "pid:")) {
- sscanf(line.c_str(), "pid: %d tid: %d", &pid, &tid);
+ sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
} else if (android::base::StartsWith(line, "map:")) {
- maps.resize(maps.size() + 1);
+ testdata->maps.resize(testdata->maps.size() + 1);
+ backtrace_map_t& map = testdata->maps.back();
int pos;
sscanf(line.c_str(),
"map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
" load_base: %" SCNxPTR " flags: %d name: %n",
- &maps.back().start, &maps.back().end, &maps.back().offset,
- &maps.back().load_base, &maps.back().flags, &pos);
- maps.back().name = android::base::Trim(line.substr(pos));
+ &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+ map.name = android::base::Trim(line.substr(pos));
} else if (android::base::StartsWith(line, "registers:")) {
size_t size;
int pos;
sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
- ASSERT_EQ(sizeof(unw_context), size);
- HexStringToRawData(&line[pos], &unw_context, size);
+ if (sizeof(testdata->unw_context) != size) {
+ return false;
+ }
+ HexStringToRawData(&line[pos], &testdata->unw_context, size);
} else if (android::base::StartsWith(line, "stack:")) {
size_t size;
int pos;
sscanf(line.c_str(),
"stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
- &stack_info.start, &stack_info.end, &size, &pos);
- stack.resize(size);
- HexStringToRawData(&line[pos], &stack[0], size);
- stack_info.data = stack.data();
+ &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
+ testdata->stack.resize(size);
+ HexStringToRawData(&line[pos], &testdata->stack[0], size);
+ testdata->stack_info.data = testdata->stack.data();
} else if (android::base::StartsWith(line, "function:")) {
- symbols.resize(symbols.size() + 1);
+ testdata->symbols.resize(testdata->symbols.size() + 1);
+ FunctionSymbol& symbol = testdata->symbols.back();
int pos;
sscanf(line.c_str(),
"function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
- &symbols.back().start, &symbols.back().end,
- &pos);
- symbols.back().name = line.substr(pos);
+ &symbol.start, &symbol.end, &pos);
+ symbol.name = line.substr(pos);
}
}
+ return true;
+}
+
+static void BacktraceOfflineTest(const std::string& testlib_name) {
+ const std::string arch = GetArch();
+ if (arch.empty()) {
+ GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+ return;
+ }
+ const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
+ struct stat st;
+ if (stat(testlib_path.c_str(), &st) == -1) {
+ GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+ return;
+ }
+
+ const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+ OfflineTestData testdata;
+ ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
// Fix path of libbacktrace_testlib.so.
- for (auto& map : maps) {
+ for (auto& map : testdata.maps) {
if (map.name.find("libbacktrace_test.so") != std::string::npos) {
map.name = testlib_path;
}
}
// Do offline backtrace.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid, maps));
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
ASSERT_TRUE(map != nullptr);
std::unique_ptr<Backtrace> backtrace(
- Backtrace::CreateOffline(pid, tid, map.get(), stack_info));
+ Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
ASSERT_TRUE(backtrace != nullptr);
- ucontext_t ucontext = GetUContextFromUnwContext(unw_context);
+ ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
// Collect pc values of the call stack frames.
std::vector<uintptr_t> pc_values;
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
@@ -311,17 +323,20 @@
size_t test_one_index = 0;
for (size_t i = 0; i < pc_values.size(); ++i) {
- if (FunctionNameForAddress(pc_values[i], symbols) == "test_level_one") {
+ if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
test_one_index = i;
break;
}
}
ASSERT_GE(test_one_index, 3u);
- ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], symbols));
- ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], symbols));
- ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2], symbols));
- ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3], symbols));
+ ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
+ ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
+ testdata.symbols));
+ ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
+ testdata.symbols));
+ ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
+ testdata.symbols));
}
TEST(libbacktrace, offline_eh_frame) {
@@ -339,3 +354,47 @@
TEST(libbacktrace, offline_arm_exidx) {
BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
}
+
+// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
+// overlap with each other, which appears in /system/lib/libart.so.
+TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+ const std::string arch = GetArch();
+ if (arch.empty() || arch != "arm") {
+ GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+ return;
+ }
+ const std::string testlib_path = "testdata/" + arch + "/libart.so";
+ struct stat st;
+ ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
+
+ const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata_for_libart";
+ OfflineTestData testdata;
+ ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+
+ // Fix path of /system/lib/libart.so.
+ for (auto& map : testdata.maps) {
+ if (map.name.find("libart.so") != std::string::npos) {
+ map.name = testlib_path;
+ }
+ }
+
+ // Do offline backtrace.
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
+ ASSERT_TRUE(map != nullptr);
+
+ std::unique_ptr<Backtrace> backtrace(
+ Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+ ASSERT_TRUE(backtrace != nullptr);
+
+ ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
+ ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+ // The last frame is outside of libart.so
+ ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
+ for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
+ uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
+ testdata.maps[0].load_base;
+ std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+ ASSERT_EQ(name, testdata.symbols[i].name);
+ }
+}
diff --git a/libbacktrace/testdata/arm/libart.so b/libbacktrace/testdata/arm/libart.so
new file mode 100644
index 0000000..bed8e35
--- /dev/null
+++ b/libbacktrace/testdata/arm/libart.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
new file mode 100644
index 0000000..63f6a07
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -0,0 +1,10 @@
+pid: 32232 tid: 32233
+registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+map: start: e9380000 end: e9766000 offset: 0 load_base: b000 flags: 5 name: /system/lib/libart.so
+stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
+function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
+function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
+function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
+function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
+function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
+function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
\ No newline at end of file
diff --git a/libbinderwrapper/Android.mk b/libbinderwrapper/Android.mk
index b38d262..c768373 100644
--- a/libbinderwrapper/Android.mk
+++ b/libbinderwrapper/Android.mk
@@ -41,7 +41,7 @@
include $(BUILD_SHARED_LIBRARY)
-# libbinderwrapper_test_support shared library
+# libbinderwrapper_test_support static library
# ========================================================
include $(CLEAR_VARS)
@@ -59,4 +59,4 @@
binder_test_base.cc \
stub_binder_wrapper.cc \
-include $(BUILD_SHARED_LIBRARY)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8ba7452..f668f18 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -41,9 +41,12 @@
host_supported: true,
export_include_dirs: ["include"],
target: {
- windows: {
- enabled: true,
- },
+ linux_bionic: {
+ enabled: true,
+ },
+ windows: {
+ enabled: true,
+ },
},
}
@@ -60,7 +63,7 @@
"native_handle.c",
"open_memstream.c",
"record_stream.c",
- "sched_policy.c",
+ "sched_policy.cpp",
"sockets.cpp",
"strdup16to8.c",
"strdup8to16.c",
@@ -68,11 +71,14 @@
"threads.c",
],
-
target: {
host: {
srcs: ["dlmalloc_stubs.c"],
},
+ linux_bionic: {
+ enabled: true,
+ exclude_srcs: ["dlmalloc_stubs.c"],
+ },
not_windows: {
srcs: libcutils_nonwindows_sources + [
"ashmem-host.c",
@@ -141,14 +147,6 @@
header_libs: ["libcutils_headers"],
export_header_lib_headers: ["libcutils_headers"],
- product_variables: {
- cpusets: {
- cflags: ["-DUSE_CPUSETS"],
- },
- schedboost: {
- cflags: ["-DUSE_SCHEDBOOST"],
- },
- },
cflags: [
"-Werror",
"-Wall",
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 159a9d4..6bdcc13 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -209,6 +209,10 @@
LINUX_REBOOT_CMD_RESTART2, arg);
break;
+ case ANDROID_RB_THERMOFF:
+ ret = reboot(RB_POWER_OFF);
+ break;
+
default:
ret = -1;
}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index b701bba..1915ced 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -161,11 +161,11 @@
/* Support wifi_hal_legacy administering a network interface. */
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
- "system/bin/hw/android.hardware.wifi@1.0-service" },
+ "vendor/bin/hw/android.hardware.wifi@1.0-service" },
/* Support Bluetooth legacy hal accessing /sys/class/rfkill */
{ 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
- "system/bin/hw/android.hardware.bluetooth@1.0-service" },
+ "vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
/* A non-privileged zygote that spawns isolated processes for web rendering. */
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
@@ -180,6 +180,7 @@
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
+ { 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index a3861a0..549f258 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -25,6 +25,7 @@
#define ANDROID_RB_RESTART 0xDEAD0001
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
+#define ANDROID_RB_THERMOFF 0xDEAD0004
/* Properties */
#define ANDROID_RB_PROPERTY "sys.powerctl"
diff --git a/libcutils/include/cutils/properties.h b/libcutils/include/cutils/properties.h
index adf670b..b45f58f 100644
--- a/libcutils/include/cutils/properties.h
+++ b/libcutils/include/cutils/properties.h
@@ -43,7 +43,12 @@
** If the property read fails or returns an empty value, the default
** value is used (if nonnull).
*/
-int property_get(const char *key, char *value, const char *default_value);
+int property_get(const char *key, char *value, const char *default_value)
+/* Sometimes we use not-Bionic with this, so we need this check. */
+#if defined(__BIONIC_FORTIFY)
+ __overloadable __RENAME_CLANG(property_get)
+#endif
+ ;
/* property_get_bool: returns the value of key coerced into a
** boolean. If the property is not set, then the default value is returned.
@@ -106,14 +111,40 @@
/* property_set: returns 0 on success, < 0 on failure
*/
int property_set(const char *key, const char *value);
-
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
-#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
+
+#if defined(__BIONIC_FORTIFY)
+#define __property_get_err_str "property_get() called with too small of a buffer"
+
+#if defined(__clang__)
+
+/* Some projects use -Weverything; enable_if is clang-specific.
+** FIXME: This is marked used because we'll otherwise get complaints about an
+** unused static function. This is more robust than marking it unused, since
+** -Wused-but-marked-unused is a thing that will complain if this function is
+** actually used, thus making FORTIFY noisier when an error happens. It's going
+** to go away anyway during our FORTIFY cleanup.
+**/
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int property_get(const char *key, char *value, const char *default_value)
+ __overloadable
+ __enable_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(value) < PROPERTY_VALUE_MAX, __property_get_err_str)
+ __errorattr(__property_get_err_str)
+ __attribute__((used));
+#pragma clang diagnostic pop
+
+/* No object size? No FORTIFY.
+*/
+
+#else /* defined(__clang__) */
extern int __property_get_real(const char *, char *, const char *)
__asm__(__USER_LABEL_PREFIX__ "property_get");
-__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
+__errordecl(__property_get_too_small_error, __property_get_err_str);
__BIONIC_FORTIFY_INLINE
int property_get(const char *key, char *value, const char *default_value) {
@@ -124,7 +155,10 @@
return __property_get_real(key, value, default_value);
}
-#endif
+#endif /* defined(__clang__) */
+
+#undef __property_get_err_str
+#endif /* defined(__BIONIC_FORTIFY) */
#ifdef __cplusplus
}
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index 591bd44..15391d9 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -17,10 +17,27 @@
#ifndef __CUTILS_SCHED_POLICY_H
#define __CUTILS_SCHED_POLICY_H
+#include <stdbool.h>
+
#ifdef __cplusplus
extern "C" {
#endif
+/*
+ * Check if Linux kernel enables CPUSETS feature.
+ *
+ * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ */
+extern bool cpusets_enabled();
+
+/*
+ * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
+ * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
+ *
+ * Return value: 1 if Linux kernel CONFIG_SCHEDTUNE=y; 0 otherwise.
+ */
+extern bool schedboost_enabled();
+
/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
typedef enum {
SP_DEFAULT = -1,
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 43ad574..d2645e6 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -129,7 +129,7 @@
void* cookie;
};
-static void trampoline(void* raw_data, const char* name, const char* value) {
+static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
callback_data* data = reinterpret_cast<callback_data*>(raw_data);
data->callback(name, value, data->cookie);
}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.cpp
similarity index 73%
rename from libcutils/sched_policy.c
rename to libcutils/sched_policy.cpp
index 5c5f3a5..7e3ad59 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.cpp
@@ -58,13 +58,11 @@
static int bg_cgroup_fd = -1;
static int fg_cgroup_fd = -1;
-#ifdef USE_CPUSETS
// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
static int system_bg_cpuset_fd = -1;
static int bg_cpuset_fd = -1;
static int fg_cpuset_fd = -1;
static int ta_cpuset_fd = -1; // special cpuset for top app
-#endif
// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
static int bg_schedboost_fd = -1;
@@ -106,8 +104,53 @@
return 0;
}
-static void __initialize(void) {
- char* filename;
+/*
+ If CONFIG_CPUSETS for Linux kernel is set, "tasks" can be found under
+ /dev/cpuset mounted in init.rc; otherwise, that file does not exist
+ even though the directory, /dev/cpuset, is still created (by init.rc).
+
+ A couple of other candidates (under cpuset mount directory):
+ notify_on_release
+ release_agent
+
+ Yet another way to decide if cpuset is enabled is to parse
+ /proc/self/status and search for lines begin with "Mems_allowed".
+
+ If CONFIG_PROC_PID_CPUSET is set, the existence "/proc/self/cpuset" can
+ be used to decide if CONFIG_CPUSETS is set, so we don't have a dependency
+ on where init.rc mounts cpuset. That's why we'd better require this
+ configuration be set if CONFIG_CPUSETS is set.
+
+ With runtime check using the following function, build time
+ variables like ENABLE_CPUSETS (used in Android.mk) or cpusets (used
+ in Android.bp) are not needed.
+ */
+
+bool cpusets_enabled() {
+ static bool enabled = (access("/dev/cpuset/tasks", F_OK) == 0);
+
+ return enabled;
+}
+
+/*
+ Similar to CONFIG_CPUSETS above, but with a different configuration
+ CONFIG_SCHEDTUNE that's in Android common Linux kernel and Linaro
+ Stable Kernel (LSK), but not in mainline Linux as of v4.9.
+
+ With runtime check using the following function, build time
+ variables like ENABLE_SCHEDBOOST (used in Android.mk) or schedboost
+ (used in Android.bp) are not needed.
+
+ */
+
+bool schedboost_enabled() {
+ static bool enabled = (access("/dev/stune/tasks", F_OK) == 0);
+
+ return enabled;
+}
+
+static void __initialize() {
+ const char* filename;
if (!access("/dev/cpuctl/tasks", W_OK)) {
__sys_supports_schedgroups = 1;
@@ -126,28 +169,28 @@
__sys_supports_schedgroups = 0;
}
-#ifdef USE_CPUSETS
- if (!access("/dev/cpuset/tasks", W_OK)) {
+ if (cpusets_enabled()) {
+ if (!access("/dev/cpuset/tasks", W_OK)) {
- filename = "/dev/cpuset/foreground/tasks";
- fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/background/tasks";
- bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/system-background/tasks";
- system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/cpuset/top-app/tasks";
- ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/foreground/tasks";
+ fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/background/tasks";
+ bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/system-background/tasks";
+ system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/cpuset/top-app/tasks";
+ ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
-#ifdef USE_SCHEDBOOST
- filename = "/dev/stune/top-app/tasks";
- ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/foreground/tasks";
- fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
- filename = "/dev/stune/background/tasks";
- bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
-#endif
+ if (schedboost_enabled()) {
+ filename = "/dev/stune/top-app/tasks";
+ ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/stune/foreground/tasks";
+ fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ filename = "/dev/stune/background/tasks";
+ bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+ }
+ }
}
-#endif
char buf[64];
snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", getpid());
@@ -235,33 +278,34 @@
if (__sys_supports_schedgroups) {
char grpBuf[32];
-#ifdef USE_CPUSETS
- if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
- return -1;
- if (grpBuf[0] == '\0') {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "foreground")) {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "background")) {
- *policy = SP_BACKGROUND;
- } else if (!strcmp(grpBuf, "top-app")) {
- *policy = SP_TOP_APP;
+
+ if (cpusets_enabled()) {
+ if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
+ return -1;
+ if (grpBuf[0] == '\0') {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "foreground")) {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "background")) {
+ *policy = SP_BACKGROUND;
+ } else if (!strcmp(grpBuf, "top-app")) {
+ *policy = SP_TOP_APP;
+ } else {
+ errno = ERANGE;
+ return -1;
+ }
} else {
- errno = ERANGE;
- return -1;
+ if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
+ return -1;
+ if (grpBuf[0] == '\0') {
+ *policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "bg_non_interactive")) {
+ *policy = SP_BACKGROUND;
+ } else {
+ errno = ERANGE;
+ return -1;
+ }
}
-#else
- if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
- return -1;
- if (grpBuf[0] == '\0') {
- *policy = SP_FOREGROUND;
- } else if (!strcmp(grpBuf, "bg_non_interactive")) {
- *policy = SP_BACKGROUND;
- } else {
- errno = ERANGE;
- return -1;
- }
-#endif
} else {
int rc = sched_getscheduler(tid);
if (rc < 0)
@@ -281,9 +325,10 @@
int set_cpuset_policy(int tid, SchedPolicy policy)
{
// in the absence of cpusets, use the old sched policy
-#ifndef USE_CPUSETS
- return set_sched_policy(tid, policy);
-#else
+ if (!cpusets_enabled()) {
+ return set_sched_policy(tid, policy);
+ }
+
if (tid == 0) {
tid = gettid();
}
@@ -320,15 +365,14 @@
return -errno;
}
-#ifdef USE_SCHEDBOOST
- if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
+ if (schedboost_enabled()) {
+ if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+ if (errno != ESRCH && errno != ENOENT)
+ return -errno;
+ }
}
-#endif
return 0;
-#endif
}
static void set_timerslack_ns(int tid, unsigned long long slack) {
@@ -420,18 +464,17 @@
break;
}
-
if (add_tid_to_cgroup(tid, fd) != 0) {
if (errno != ESRCH && errno != ENOENT)
return -errno;
}
-#ifdef USE_SCHEDBOOST
- if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
- if (errno != ESRCH && errno != ENOENT)
- return -errno;
+ if (schedboost_enabled()) {
+ if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+ if (errno != ESRCH && errno != ENOENT)
+ return -errno;
+ }
}
-#endif
} else {
struct sched_param param;
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 0b0dc09..718d76b 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -46,6 +46,12 @@
suffix: "64",
},
},
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
}
test_libraries = [
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index c5f58b4..ae5c416 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -17,59 +17,61 @@
#include <cutils/multiuser.h>
#include <gtest/gtest.h>
+static constexpr auto ERR_GID = static_cast<gid_t>(-1);
+
TEST(MultiuserTest, TestMerge) {
- EXPECT_EQ(0, multiuser_get_uid(0, 0));
- EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
- EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
- EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
- EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
- EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
- EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
- EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+ EXPECT_EQ(0U, multiuser_get_uid(0, 0));
+ EXPECT_EQ(1000U, multiuser_get_uid(0, 1000));
+ EXPECT_EQ(10000U, multiuser_get_uid(0, 10000));
+ EXPECT_EQ(50000U, multiuser_get_uid(0, 50000));
+ EXPECT_EQ(1000000U, multiuser_get_uid(10, 0));
+ EXPECT_EQ(1001000U, multiuser_get_uid(10, 1000));
+ EXPECT_EQ(1010000U, multiuser_get_uid(10, 10000));
+ EXPECT_EQ(1050000U, multiuser_get_uid(10, 50000));
}
TEST(MultiuserTest, TestSplitUser) {
- EXPECT_EQ(0, multiuser_get_user_id(0));
- EXPECT_EQ(0, multiuser_get_user_id(1000));
- EXPECT_EQ(0, multiuser_get_user_id(10000));
- EXPECT_EQ(0, multiuser_get_user_id(50000));
- EXPECT_EQ(10, multiuser_get_user_id(1000000));
- EXPECT_EQ(10, multiuser_get_user_id(1001000));
- EXPECT_EQ(10, multiuser_get_user_id(1010000));
- EXPECT_EQ(10, multiuser_get_user_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_user_id(0));
+ EXPECT_EQ(0U, multiuser_get_user_id(1000));
+ EXPECT_EQ(0U, multiuser_get_user_id(10000));
+ EXPECT_EQ(0U, multiuser_get_user_id(50000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1000000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1001000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1010000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1050000));
}
TEST(MultiuserTest, TestSplitApp) {
- EXPECT_EQ(0, multiuser_get_app_id(0));
- EXPECT_EQ(1000, multiuser_get_app_id(1000));
- EXPECT_EQ(10000, multiuser_get_app_id(10000));
- EXPECT_EQ(50000, multiuser_get_app_id(50000));
- EXPECT_EQ(0, multiuser_get_app_id(1000000));
- EXPECT_EQ(1000, multiuser_get_app_id(1001000));
- EXPECT_EQ(10000, multiuser_get_app_id(1010000));
- EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_app_id(0));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(10000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(50000));
+ EXPECT_EQ(0U, multiuser_get_app_id(1000000));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1001000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(1010000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(1050000));
}
TEST(MultiuserTest, TestCache) {
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 1000));
- EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 50000));
- EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
+ EXPECT_EQ(20000U, multiuser_get_cache_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(1020000U, multiuser_get_cache_gid(10, 10000));
}
TEST(MultiuserTest, TestExt) {
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 1000));
- EXPECT_EQ(30000, multiuser_get_ext_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 50000));
- EXPECT_EQ(1030000, multiuser_get_ext_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 1000));
+ EXPECT_EQ(30000U, multiuser_get_ext_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 50000));
+ EXPECT_EQ(1030000U, multiuser_get_ext_gid(10, 10000));
}
TEST(MultiuserTest, TestShared) {
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
- EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 50000));
- EXPECT_EQ(1050000, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(50000U, multiuser_get_shared_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
+ EXPECT_EQ(1050000U, multiuser_get_shared_gid(10, 10000));
}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0441fb6..b762ac1 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -101,7 +101,7 @@
// should always be able to read its port.
for (int port : {10000, 12345, 15999, 20202, 25000}) {
for (int type : {SOCK_DGRAM, SOCK_STREAM}) {
- server = socket_inaddr_any_server(port, SOCK_DGRAM);
+ server = socket_inaddr_any_server(port, type);
if (server != INVALID_SOCKET) {
EXPECT_EQ(port, socket_get_local_port(server));
}
diff --git a/base/.clang-format b/liblog/.clang-format
similarity index 68%
rename from base/.clang-format
rename to liblog/.clang-format
index 2b83a1f..9db87a8 100644
--- a/base/.clang-format
+++ b/liblog/.clang-format
@@ -1,11 +1,9 @@
BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
-IndentWidth: 2
PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 747fcc8..bb8c3af 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -15,13 +15,18 @@
//
liblog_sources = [
+ "config_read.c",
+ "config_write.c",
+ "local_logger.c",
"log_event_list.c",
"log_event_write.c",
- "logger_write.c",
- "config_write.c",
- "logger_name.c",
- "logger_lock.c",
"log_ratelimit.cpp",
+ "logger_lock.c",
+ "logger_name.c",
+ "logger_read.c",
+ "logger_write.c",
+ "logprint.c",
+ "stderr_write.c",
]
liblog_host_sources = [
"fake_log_device.c",
@@ -29,15 +34,12 @@
]
liblog_target_sources = [
"event_tag_map.cpp",
- "config_read.c",
"log_time.cpp",
"properties.c",
- "logprint.c",
"pmsg_reader.c",
"pmsg_writer.c",
"logd_reader.c",
"logd_writer.c",
- "logger_read.c",
]
// Shared and static library for host and device
diff --git a/liblog/README b/liblog/README
index 610338c..5a845be 100644
--- a/liblog/README
+++ b/liblog/README
@@ -108,6 +108,11 @@
int android_log_destroy(android_log_context *ctx)
+ #include <log/log_transport.h>
+
+ int android_set_log_transport(int transport_flag)
+ int android_get_log_transport()
+
Link with -llog
DESCRIPTION
@@ -162,6 +167,13 @@
when opening the sub-log. It is recommended to open the log
ANDROID_LOG_RDONLY in these cases.
+ android_set_log_transport() selects transport filters. Argument is
+ either LOGGER_DEFAULT, LOGGER_LOGD, LOGGER_NULL or LOGGER_LOCAL. Log to
+ logger daemon for default or logd, drop contents on floor, or log into
+ local memory respectively. Both android_set_log_transport()
+ and android_get_log_transport() return the current transport mask, or
+ a negative errno for any problems.
+
ERRORS
If messages fail, a negative error code will be returned to the caller.
@@ -194,4 +206,4 @@
- 17 Oct 2016 LIBLOG(3)
+ 08 Feb 2017 LIBLOG(3)
diff --git a/liblog/config_read.c b/liblog/config_read.c
index 1f54152..ca80c80 100644
--- a/liblog/config_read.c
+++ b/liblog/config_read.c
@@ -14,49 +14,73 @@
* limitations under the License.
*/
+#include <log/log_transport.h>
+
#include "config_read.h"
#include "logger.h"
-LIBLOG_HIDDEN struct listnode __android_log_transport_read =
- { &__android_log_transport_read, &__android_log_transport_read };
-LIBLOG_HIDDEN struct listnode __android_log_persist_read =
- { &__android_log_persist_read, &__android_log_persist_read };
+LIBLOG_HIDDEN struct listnode __android_log_transport_read = {
+ &__android_log_transport_read, &__android_log_transport_read
+};
+LIBLOG_HIDDEN struct listnode __android_log_persist_read = {
+ &__android_log_persist_read, &__android_log_persist_read
+};
static void __android_log_add_transport(
- struct listnode *list, struct android_log_transport_read *transport) {
- size_t i;
+ struct listnode* list, struct android_log_transport_read* transport) {
+ size_t i;
- /* Try to keep one functioning transport for each log buffer id */
- for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
- struct android_log_transport_read *transp;
+ /* Try to keep one functioning transport for each log buffer id */
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+ struct android_log_transport_read* transp;
- if (list_empty(list)) {
- if (!transport->available || ((*transport->available)(i) >= 0)) {
- list_add_tail(list, &transport->node);
- return;
- }
- } else {
- read_transport_for_each(transp, list) {
- if (!transp->available) {
- return;
- }
- if (((*transp->available)(i) < 0) &&
- (!transport->available ||
- ((*transport->available)(i) >= 0))) {
- list_add_tail(list, &transport->node);
- return;
- }
- }
+ if (list_empty(list)) {
+ if (!transport->available || ((*transport->available)(i) >= 0)) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ } else {
+ read_transport_for_each(transp, list) {
+ if (!transp->available) {
+ return;
}
+ if (((*transp->available)(i) < 0) &&
+ (!transport->available || ((*transport->available)(i) >= 0))) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ }
}
+ }
}
LIBLOG_HIDDEN void __android_log_config_read() {
+ if (__android_log_transport & LOGGER_LOCAL) {
+ extern struct android_log_transport_read localLoggerRead;
+
+ __android_log_add_transport(&__android_log_transport_read, &localLoggerRead);
+ }
+
#if (FAKE_LOG_DEVICE == 0)
+ if ((__android_log_transport == LOGGER_DEFAULT) ||
+ (__android_log_transport & LOGGER_LOGD)) {
extern struct android_log_transport_read logdLoggerRead;
extern struct android_log_transport_read pmsgLoggerRead;
__android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
__android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
+ }
#endif
}
+
+LIBLOG_HIDDEN void __android_log_config_read_close() {
+ struct android_log_transport_read* transport;
+ struct listnode* n;
+
+ read_transport_for_each_safe(transport, n, &__android_log_transport_read) {
+ list_remove(&transport->node);
+ }
+ read_transport_for_each_safe(transport, n, &__android_log_persist_read) {
+ list_remove(&transport->node);
+ }
+}
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 49a3b75..7b29fa4 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -26,24 +26,29 @@
extern LIBLOG_HIDDEN struct listnode __android_log_transport_read;
extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
-#define read_transport_for_each(transp, transports) \
- for ((transp) = node_to_item((transports)->next, \
- struct android_log_transport_read, node); \
- ((transp) != node_to_item(transports, \
- struct android_log_transport_read, node)); \
- (transp) = node_to_item((transp)->node.next, \
- struct android_log_transport_read, node)) \
+#define read_transport_for_each(transp, transports) \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_read, node); \
+ ((transp) != node_to_item((transports), \
+ struct android_log_transport_read, node)) && \
+ ((transp) != node_to_item((transp)->node.next, \
+ struct android_log_transport_read, node)); \
+ (transp) = node_to_item((transp)->node.next, \
+ struct android_log_transport_read, node))
-#define read_transport_for_each_safe(transp, n, transports) \
- for ((transp) = node_to_item((transports)->next, \
- struct android_log_transport_read, node), \
- (n) = (transp)->node.next; \
- ((transp) != node_to_item(transports, \
- struct android_log_transport_read, node)); \
- (transp) = node_to_item(n, struct android_log_transport_read, node), \
- (n) = (transp)->node.next)
+#define read_transport_for_each_safe(transp, n, transports) \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_read, node), \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item((transports), \
+ struct android_log_transport_read, node)) && \
+ ((transp) != \
+ node_to_item((n), struct android_log_transport_read, node)); \
+ (transp) = node_to_item((n), struct android_log_transport_read, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_read();
+LIBLOG_HIDDEN void __android_log_config_read_close();
__END_DECLS
diff --git a/liblog/config_write.c b/liblog/config_write.c
index d689f63..0a8b52f 100644
--- a/liblog/config_write.c
+++ b/liblog/config_write.c
@@ -14,53 +14,105 @@
* limitations under the License.
*/
+#include <log/log_transport.h>
+
#include "config_write.h"
#include "logger.h"
-LIBLOG_HIDDEN struct listnode __android_log_transport_write =
- { &__android_log_transport_write, &__android_log_transport_write };
-LIBLOG_HIDDEN struct listnode __android_log_persist_write =
- { &__android_log_persist_write, &__android_log_persist_write};
+LIBLOG_HIDDEN struct listnode __android_log_transport_write = {
+ &__android_log_transport_write, &__android_log_transport_write
+};
+LIBLOG_HIDDEN struct listnode __android_log_persist_write = {
+ &__android_log_persist_write, &__android_log_persist_write
+};
static void __android_log_add_transport(
- struct listnode *list, struct android_log_transport_write *transport) {
- size_t i;
+ struct listnode* list, struct android_log_transport_write* transport) {
+ size_t i;
- /* Try to keep one functioning transport for each log buffer id */
- for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
- struct android_log_transport_write *transp;
+ /* Try to keep one functioning transport for each log buffer id */
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+ struct android_log_transport_write* transp;
- if (list_empty(list)) {
- if (!transport->available || ((*transport->available)(i) >= 0)) {
- list_add_tail(list, &transport->node);
- return;
- }
- } else {
- write_transport_for_each(transp, list) {
- if (!transp->available) {
- return;
- }
- if (((*transp->available)(i) < 0) &&
- (!transport->available ||
- ((*transport->available)(i) >= 0))) {
- list_add_tail(list, &transport->node);
- return;
- }
- }
+ if (list_empty(list)) {
+ if (!transport->available || ((*transport->available)(i) >= 0)) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ } else {
+ write_transport_for_each(transp, list) {
+ if (!transp->available) {
+ return;
}
+ if (((*transp->available)(i) < 0) &&
+ (!transport->available || ((*transport->available)(i) >= 0))) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ }
}
+ }
}
LIBLOG_HIDDEN void __android_log_config_write() {
+ if (__android_log_transport & LOGGER_LOCAL) {
+ extern struct android_log_transport_write localLoggerWrite;
+
+ __android_log_add_transport(&__android_log_transport_write,
+ &localLoggerWrite);
+ }
+
+ if ((__android_log_transport == LOGGER_DEFAULT) ||
+ (__android_log_transport & LOGGER_LOGD)) {
#if (FAKE_LOG_DEVICE == 0)
extern struct android_log_transport_write logdLoggerWrite;
extern struct android_log_transport_write pmsgLoggerWrite;
- __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
+ __android_log_add_transport(&__android_log_transport_write,
+ &logdLoggerWrite);
__android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
#else
extern struct android_log_transport_write fakeLoggerWrite;
- __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
+ __android_log_add_transport(&__android_log_transport_write,
+ &fakeLoggerWrite);
#endif
+ }
+
+ if (__android_log_transport & LOGGER_STDERR) {
+ extern struct android_log_transport_write stderrLoggerWrite;
+
+ /*
+ * stderr logger should be primary if we can be the only one, or if
+ * already in the primary list. Otherwise land in the persist list.
+ * Remember we can be called here if we are already initialized.
+ */
+ if (list_empty(&__android_log_transport_write)) {
+ __android_log_add_transport(&__android_log_transport_write,
+ &stderrLoggerWrite);
+ } else {
+ struct android_log_transport_write* transp;
+ write_transport_for_each(transp, &__android_log_transport_write) {
+ if (transp == &stderrLoggerWrite) {
+ return;
+ }
+ }
+ __android_log_add_transport(&__android_log_persist_write,
+ &stderrLoggerWrite);
+ }
+ }
+}
+
+LIBLOG_HIDDEN void __android_log_config_write_close() {
+ struct android_log_transport_write* transport;
+ struct listnode* n;
+
+ write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+ transport->logMask = 0;
+ list_remove(&transport->node);
+ }
+ write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+ transport->logMask = 0;
+ list_remove(&transport->node);
+ }
}
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3b01a9a..db1a083 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -26,24 +26,29 @@
extern LIBLOG_HIDDEN struct listnode __android_log_transport_write;
extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
-#define write_transport_for_each(transp, transports) \
- for ((transp) = node_to_item((transports)->next, \
- struct android_log_transport_write, node); \
- ((transp) != node_to_item(transports, \
- struct android_log_transport_write, node)); \
- (transp) = node_to_item((transp)->node.next, \
- struct android_log_transport_write, node)) \
+#define write_transport_for_each(transp, transports) \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node); \
+ ((transp) != node_to_item((transports), \
+ struct android_log_transport_write, node)) && \
+ ((transp) != node_to_item((transp)->node.next, \
+ struct android_log_transport_write, node)); \
+ (transp) = node_to_item((transp)->node.next, \
+ struct android_log_transport_write, node))
-#define write_transport_for_each_safe(transp, n, transports) \
- for ((transp) = node_to_item((transports)->next, \
- struct android_log_transport_write, node), \
- (n) = (transp)->node.next; \
- ((transp) != node_to_item(transports, \
- struct android_log_transport_write, node)); \
- (transp) = node_to_item(n, struct android_log_transport_write, node), \
- (n) = (transp)->node.next)
+#define write_transport_for_each_safe(transp, n, transports) \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node), \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item((transports), \
+ struct android_log_transport_write, node)) && \
+ ((transp) != \
+ node_to_item((n), struct android_log_transport_write, node)); \
+ (transp) = node_to_item((n), struct android_log_transport_write, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_write();
+LIBLOG_HIDDEN void __android_log_config_write_close();
__END_DECLS
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 1f08eb4..bdad2c2 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -31,9 +31,9 @@
#include <unordered_map>
#include <log/event_tag_map.h>
+#include <private/android_logger.h>
#include <utils/FastStrcmp.h>
#include <utils/RWLock.h>
-#include <private/android_logger.h>
#include "log_portability.h"
#include "logd_reader.h"
@@ -41,184 +41,192 @@
#define OUT_TAG "EventTagMap"
class MapString {
-private:
- const std::string* alloc; // HAS-AN
- const std::experimental::string_view str; // HAS-A
+ private:
+ const std::string* alloc; // HAS-AN
+ const std::experimental::string_view str; // HAS-A
-public:
- operator const std::experimental::string_view() const { return str; }
+ public:
+ operator const std::experimental::string_view() const {
+ return str;
+ }
- const char* data() const { return str.data(); }
- size_t length() const { return str.length(); }
+ const char* data() const {
+ return str.data();
+ }
+ size_t length() const {
+ return str.length();
+ }
- bool operator== (const MapString& rval) const {
- if (length() != rval.length()) return false;
- if (length() == 0) return true;
- return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
- }
- bool operator!= (const MapString& rval) const {
- return !(*this == rval);
- }
+ bool operator==(const MapString& rval) const {
+ if (length() != rval.length()) return false;
+ if (length() == 0) return true;
+ return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
+ }
+ bool operator!=(const MapString& rval) const {
+ return !(*this == rval);
+ }
- MapString(const char* str, size_t len) : alloc(NULL), str(str, len) { }
- explicit MapString(const std::string& str) :
- alloc(new std::string(str)),
- str(alloc->data(), alloc->length()) { }
- MapString(MapString &&rval) :
- alloc(rval.alloc),
- str(rval.data(), rval.length()) {
- rval.alloc = NULL;
- }
- explicit MapString(const MapString &rval) :
- alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
- str(alloc ? alloc->data() : rval.data(), rval.length()) { }
+ MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
+ }
+ explicit MapString(const std::string& str)
+ : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
+ }
+ MapString(MapString&& rval)
+ : alloc(rval.alloc), str(rval.data(), rval.length()) {
+ rval.alloc = NULL;
+ }
+ explicit MapString(const MapString& rval)
+ : alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
+ str(alloc ? alloc->data() : rval.data(), rval.length()) {
+ }
- ~MapString() { if (alloc) delete alloc; }
+ ~MapString() {
+ if (alloc) delete alloc;
+ }
};
// Hash for MapString
-template <> struct std::hash<MapString>
- : public std::unary_function<const MapString&, size_t> {
- size_t operator()(const MapString& __t) const noexcept {
- if (!__t.length()) return 0;
- return std::hash<std::experimental::string_view>()(std::experimental::string_view(__t));
- }
+template <>
+struct std::hash<MapString>
+ : public std::unary_function<const MapString&, size_t> {
+ size_t operator()(const MapString& __t) const noexcept {
+ if (!__t.length()) return 0;
+ return std::hash<std::experimental::string_view>()(
+ std::experimental::string_view(__t));
+ }
};
typedef std::pair<MapString, MapString> TagFmt;
-template <> struct std::hash<TagFmt>
- : public std::unary_function<const TagFmt&, size_t> {
- size_t operator()(const TagFmt& __t) const noexcept {
- // Tag is typically unique. Will cost us an extra 100ns for the
- // unordered_map lookup if we instead did a hash that combined
- // both of tag and fmt members, e.g.:
- //
- // return std::hash<MapString>()(__t.first) ^
- // std::hash<MapString>()(__t.second);
- return std::hash<MapString>()(__t.first);
- }
+template <>
+struct std::hash<TagFmt> : public std::unary_function<const TagFmt&, size_t> {
+ size_t operator()(const TagFmt& __t) const noexcept {
+ // Tag is typically unique. Will cost us an extra 100ns for the
+ // unordered_map lookup if we instead did a hash that combined
+ // both of tag and fmt members, e.g.:
+ //
+ // return std::hash<MapString>()(__t.first) ^
+ // std::hash<MapString>()(__t.second);
+ return std::hash<MapString>()(__t.first);
+ }
};
// Map
struct EventTagMap {
-# define NUM_MAPS 2
- // memory-mapped source file; we get strings from here
- void* mapAddr[NUM_MAPS];
- size_t mapLen[NUM_MAPS];
+#define NUM_MAPS 2
+ // memory-mapped source file; we get strings from here
+ void* mapAddr[NUM_MAPS];
+ size_t mapLen[NUM_MAPS];
-private:
- std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
- std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
- std::unordered_map<MapString, uint32_t> Tag2Idx;
- // protect unordered sets
- android::RWLock rwlock;
+ private:
+ std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
+ std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
+ std::unordered_map<MapString, uint32_t> Tag2Idx;
+ // protect unordered sets
+ android::RWLock rwlock;
-public:
- EventTagMap() {
- memset(mapAddr, 0, sizeof(mapAddr));
- memset(mapLen, 0, sizeof(mapLen));
+ public:
+ EventTagMap() {
+ memset(mapAddr, 0, sizeof(mapAddr));
+ memset(mapLen, 0, sizeof(mapLen));
+ }
+
+ ~EventTagMap() {
+ Idx2TagFmt.clear();
+ TagFmt2Idx.clear();
+ Tag2Idx.clear();
+ for (size_t which = 0; which < NUM_MAPS; ++which) {
+ if (mapAddr[which]) {
+ munmap(mapAddr[which], mapLen[which]);
+ mapAddr[which] = 0;
+ }
}
+ }
- ~EventTagMap() {
- Idx2TagFmt.clear();
- TagFmt2Idx.clear();
- Tag2Idx.clear();
- for (size_t which = 0; which < NUM_MAPS; ++which) {
- if (mapAddr[which]) {
- munmap(mapAddr[which], mapLen[which]);
- mapAddr[which] = 0;
- }
- }
- }
-
- bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
- const TagFmt* find(uint32_t tag) const;
- int find(TagFmt&& tagfmt) const;
- int find(MapString&& tag) const;
+ bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
+ const TagFmt* find(uint32_t tag) const;
+ int find(TagFmt&& tagfmt) const;
+ int find(MapString&& tag) const;
};
-bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose) {
- bool ret = true;
- static const char errorFormat[] = OUT_TAG ": duplicate tag entries %" PRIu32
- ":%.*s:%.*s and %" PRIu32
- ":%.*s:%.*s)\n";
- android::RWLock::AutoWLock writeLock(rwlock);
- {
- std::unordered_map<uint32_t, TagFmt>::const_iterator it;
- it = Idx2TagFmt.find(tag);
- if (it != Idx2TagFmt.end()) {
- if (verbose) {
- fprintf(stderr, errorFormat,
- it->first,
- (int)it->second.first.length(), it->second.first.data(),
- (int)it->second.second.length(), it->second.second.data(),
- tag,
- (int)tagfmt.first.length(), tagfmt.first.data(),
- (int)tagfmt.second.length(), tagfmt.second.data());
- }
- ret = false;
- } else {
- Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
- }
+bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
+ bool verbose) {
+ bool ret = true;
+ static const char errorFormat[] =
+ OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
+ ":%.*s:%.*s)\n";
+ android::RWLock::AutoWLock writeLock(rwlock);
+ {
+ std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+ it = Idx2TagFmt.find(tag);
+ if (it != Idx2TagFmt.end()) {
+ if (verbose) {
+ fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
+ it->second.first.data(), (int)it->second.second.length(),
+ it->second.second.data(), tag, (int)tagfmt.first.length(),
+ tagfmt.first.data(), (int)tagfmt.second.length(),
+ tagfmt.second.data());
+ }
+ ret = false;
+ } else {
+ Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
}
+ }
- {
- std::unordered_map<TagFmt, uint32_t>::const_iterator it;
- it = TagFmt2Idx.find(tagfmt);
- if (it != TagFmt2Idx.end()) {
- if (verbose) {
- fprintf(stderr, errorFormat,
- it->second,
- (int)it->first.first.length(), it->first.first.data(),
- (int)it->first.second.length(), it->first.second.data(),
- tag,
- (int)tagfmt.first.length(), tagfmt.first.data(),
- (int)tagfmt.second.length(), tagfmt.second.data());
- }
- ret = false;
- } else {
- TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
- }
+ {
+ std::unordered_map<TagFmt, uint32_t>::const_iterator it;
+ it = TagFmt2Idx.find(tagfmt);
+ if (it != TagFmt2Idx.end()) {
+ if (verbose) {
+ fprintf(stderr, errorFormat, it->second, (int)it->first.first.length(),
+ it->first.first.data(), (int)it->first.second.length(),
+ it->first.second.data(), tag, (int)tagfmt.first.length(),
+ tagfmt.first.data(), (int)tagfmt.second.length(),
+ tagfmt.second.data());
+ }
+ ret = false;
+ } else {
+ TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
}
+ }
- {
- std::unordered_map<MapString, uint32_t>::const_iterator it;
- it = Tag2Idx.find(tagfmt.first);
- if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
- Tag2Idx.erase(it);
- it = Tag2Idx.end();
- }
- if (it == Tag2Idx.end()) {
- Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
- }
+ {
+ std::unordered_map<MapString, uint32_t>::const_iterator it;
+ it = Tag2Idx.find(tagfmt.first);
+ if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
+ Tag2Idx.erase(it);
+ it = Tag2Idx.end();
}
+ if (it == Tag2Idx.end()) {
+ Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
+ }
+ }
- return ret;
+ return ret;
}
const TagFmt* EventTagMap::find(uint32_t tag) const {
- std::unordered_map<uint32_t, TagFmt>::const_iterator it;
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- it = Idx2TagFmt.find(tag);
- if (it == Idx2TagFmt.end()) return NULL;
- return &(it->second);
+ std::unordered_map<uint32_t, TagFmt>::const_iterator it;
+ android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
+ it = Idx2TagFmt.find(tag);
+ if (it == Idx2TagFmt.end()) return NULL;
+ return &(it->second);
}
int EventTagMap::find(TagFmt&& tagfmt) const {
- std::unordered_map<TagFmt, uint32_t>::const_iterator it;
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- it = TagFmt2Idx.find(std::move(tagfmt));
- if (it == TagFmt2Idx.end()) return -1;
- return it->second;
+ std::unordered_map<TagFmt, uint32_t>::const_iterator it;
+ android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
+ it = TagFmt2Idx.find(std::move(tagfmt));
+ if (it == TagFmt2Idx.end()) return -1;
+ return it->second;
}
int EventTagMap::find(MapString&& tag) const {
- std::unordered_map<MapString, uint32_t>::const_iterator it;
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- it = Tag2Idx.find(std::move(tag));
- if (it == Tag2Idx.end()) return -1;
- return it->second;
+ std::unordered_map<MapString, uint32_t>::const_iterator it;
+ android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
+ it = Tag2Idx.find(std::move(tag));
+ if (it == Tag2Idx.end()) return -1;
+ return it->second;
}
// Scan one tag line.
@@ -227,139 +235,165 @@
// successful return, it will be pointing to the last character in the
// tag line (i.e. the character before the start of the next line).
//
+// lineNum = 0 removes verbose comments and requires us to cache the
+// content rather than make direct raw references since the content
+// will disappear after the call. A non-zero lineNum means we own the
+// data and it will outlive the call.
+//
// Returns 0 on success, nonzero on failure.
static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
- char* cp;
- unsigned long val = strtoul(*pData, &cp, 10);
- if (cp == *pData) {
- fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
- errno = EINVAL;
- return -1;
+ char* cp;
+ unsigned long val = strtoul(*pData, &cp, 10);
+ if (cp == *pData) {
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
}
-
- uint32_t tagIndex = val;
- if (tagIndex != val) {
- fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
- errno = ERANGE;
- return -1;
- }
-
- while ((*++cp != '\n') && isspace(*cp)) {
- }
-
- if (*cp == '\n') {
- fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
- errno = EINVAL;
- return -1;
- }
-
- const char* tag = cp;
- // Determine whether "c" is a valid tag char.
- while (isalnum(*++cp) || (*cp == '_')) { }
- size_t tagLen = cp - tag;
-
- if (!isspace(*cp)) {
- fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
- errno = EINVAL;
- return -1;
- }
-
- while (isspace(*cp) && (*cp != '\n')) ++cp;
- const char* fmt = NULL;
- size_t fmtLen = 0;
- if (*cp != '#') {
- fmt = cp;
- while ((*cp != '\n') && (*cp != '#')) ++cp;
- while ((cp > fmt) && isspace(*(cp - 1))) --cp;
- fmtLen = cp - fmt;
- }
-
- // KISS Only report identicals if they are global
- // Ideally we want to check if there are identicals
- // recorded for the same uid, but recording that
- // unused detail in our database is too burdensome.
- bool verbose = true;
- while ((*cp != '#') && (*cp != '\n')) ++cp;
- if (*cp == '#') {
- do {
- ++cp;
- } while (isspace(*cp) && (*cp != '\n'));
- verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
- }
-
- while (*cp != '\n') ++cp;
-#ifdef DEBUG
- fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
-#endif
- *pData = cp;
-
- if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
- MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
- return 0;
- }
- errno = EMLINK;
+ errno = EINVAL;
return -1;
+ }
+
+ uint32_t tagIndex = val;
+ if (tagIndex != val) {
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
+ }
+ errno = ERANGE;
+ return -1;
+ }
+
+ while ((*++cp != '\n') && isspace(*cp)) {
+ }
+
+ if (*cp == '\n') {
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
+ }
+ errno = EINVAL;
+ return -1;
+ }
+
+ const char* tag = cp;
+ // Determine whether "c" is a valid tag char.
+ while (isalnum(*++cp) || (*cp == '_')) {
+ }
+ size_t tagLen = cp - tag;
+
+ if (!isspace(*cp)) {
+ if (lineNum) {
+ fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
+ }
+ errno = EINVAL;
+ return -1;
+ }
+
+ while (isspace(*cp) && (*cp != '\n')) ++cp;
+ const char* fmt = NULL;
+ size_t fmtLen = 0;
+ if (*cp != '#') {
+ fmt = cp;
+ while ((*cp != '\n') && (*cp != '#')) ++cp;
+ while ((cp > fmt) && isspace(*(cp - 1))) --cp;
+ fmtLen = cp - fmt;
+ }
+
+ // KISS Only report identicals if they are global
+ // Ideally we want to check if there are identicals
+ // recorded for the same uid, but recording that
+ // unused detail in our database is too burdensome.
+ bool verbose = true;
+ while ((*cp != '#') && (*cp != '\n')) ++cp;
+ if (*cp == '#') {
+ do {
+ ++cp;
+ } while (isspace(*cp) && (*cp != '\n'));
+ verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
+ }
+
+ while (*cp != '\n') ++cp;
+#ifdef DEBUG
+ fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
+#endif
+ *pData = cp;
+
+ if (lineNum) {
+ if (map->emplaceUnique(tagIndex,
+ TagFmt(std::make_pair(MapString(tag, tagLen),
+ MapString(fmt, fmtLen))),
+ verbose)) {
+ return 0;
+ }
+ } else {
+ // cache
+ if (map->emplaceUnique(
+ tagIndex,
+ TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
+ MapString(std::string(fmt, fmtLen)))))) {
+ return 0;
+ }
+ }
+ errno = EMLINK;
+ return -1;
}
static const char* eventTagFiles[NUM_MAPS] = {
- EVENT_TAG_MAP_FILE,
- "/dev/event-log-tags",
+ EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
};
// Parse the tags out of the file.
static int parseMapLines(EventTagMap* map, size_t which) {
- char* cp = static_cast<char*>(map->mapAddr[which]);
- size_t len = map->mapLen[which];
- char* endp = cp + len;
+ char* cp = static_cast<char*>(map->mapAddr[which]);
+ size_t len = map->mapLen[which];
+ char* endp = cp + len;
- // insist on EOL at EOF; simplifies parsing and null-termination
- if (!len || (*(endp - 1) != '\n')) {
+ // insist on EOL at EOF; simplifies parsing and null-termination
+ if (!len || (*(endp - 1) != '\n')) {
#ifdef DEBUG
- fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
- which, len);
+ fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
+ which, len);
#endif
- if (which) { // do not propagate errors for other files
- return 0;
+ if (which) { // do not propagate errors for other files
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+ }
+
+ bool lineStart = true;
+ int lineNum = 1;
+ while (cp < endp) {
+ if (*cp == '\n') {
+ lineStart = true;
+ lineNum++;
+ } else if (lineStart) {
+ if (*cp == '#') {
+ // comment; just scan to end
+ lineStart = false;
+ } else if (isdigit(*cp)) {
+ // looks like a tag; scan it out
+ if (scanTagLine(map, &cp, lineNum) != 0) {
+ if (!which || (errno != EMLINK)) {
+ return -1;
+ }
}
+ lineNum++; // we eat the '\n'
+ // leave lineStart==true
+ } else if (isspace(*cp)) {
+ // looks like leading whitespace; keep scanning
+ } else {
+ fprintf(stderr,
+ OUT_TAG
+ ": unexpected chars (0x%02x) in tag number on line %d\n",
+ *cp, lineNum);
errno = EINVAL;
return -1;
+ }
+ } else {
+ // this is a blank or comment line
}
+ cp++;
+ }
- bool lineStart = true;
- int lineNum = 1;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = true;
- lineNum++;
- } else if (lineStart) {
- if (*cp == '#') {
- // comment; just scan to end
- lineStart = false;
- } else if (isdigit(*cp)) {
- // looks like a tag; scan it out
- if (scanTagLine(map, &cp, lineNum) != 0) {
- if (!which || (errno != EMLINK)) {
- return -1;
- }
- }
- lineNum++; // we eat the '\n'
- // leave lineStart==true
- } else if (isspace(*cp)) {
- // looks like leading whitespace; keep scanning
- } else {
- fprintf(stderr,
- OUT_TAG ": unexpected chars (0x%02x) in tag number on line %d\n",
- *cp, lineNum);
- errno = EINVAL;
- return -1;
- }
- } else {
- // this is a blank or comment line
- }
- cp++;
- }
-
- return 0;
+ return 0;
}
// Open the map file and allocate a structure to manage it.
@@ -367,113 +401,155 @@
// We create a private mapping because we want to terminate the log tag
// strings with '\0'.
LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
- EventTagMap* newTagMap;
- off_t end[NUM_MAPS];
- int save_errno, fd[NUM_MAPS];
- size_t which;
+ EventTagMap* newTagMap;
+ off_t end[NUM_MAPS];
+ int save_errno, fd[NUM_MAPS];
+ size_t which;
- memset(fd, -1, sizeof(fd));
- memset(end, 0, sizeof(end));
+ memset(fd, -1, sizeof(fd));
+ memset(end, 0, sizeof(end));
- for (which = 0; which < NUM_MAPS; ++which) {
+ for (which = 0; which < NUM_MAPS; ++which) {
+ const char* tagfile = fileName ? fileName : eventTagFiles[which];
+
+ fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
+ if (fd[which] < 0) {
+ if (!which) {
+ save_errno = errno;
+ fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
+ strerror(save_errno));
+ goto fail_errno;
+ }
+ continue;
+ }
+ end[which] = lseek(fd[which], 0L, SEEK_END);
+ save_errno = errno;
+ (void)lseek(fd[which], 0L, SEEK_SET);
+ if (!which && (end[0] < 0)) {
+ fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
+ strerror(save_errno));
+ goto fail_close;
+ }
+ if (fileName) break; // Only allow one as specified
+ }
+
+ newTagMap = new EventTagMap;
+ if (newTagMap == NULL) {
+ save_errno = errno;
+ goto fail_close;
+ }
+
+ for (which = 0; which < NUM_MAPS; ++which) {
+ if (fd[which] >= 0) {
+ newTagMap->mapAddr[which] =
+ mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
+ which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
+ save_errno = errno;
+ close(fd[which]);
+ fd[which] = -1;
+ if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
+ (newTagMap->mapAddr[which] != NULL)) {
+ newTagMap->mapLen[which] = end[which];
+ } else if (!which) {
const char* tagfile = fileName ? fileName : eventTagFiles[which];
- fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
- if (fd[which] < 0) {
- if (!which) {
- save_errno = errno;
- fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n",
- tagfile, strerror(save_errno));
- goto fail_errno;
- }
- continue;
- }
- end[which] = lseek(fd[which], 0L, SEEK_END);
- save_errno = errno;
- (void)lseek(fd[which], 0L, SEEK_SET);
- if (!which && (end[0] < 0)) {
- fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n",
- tagfile, strerror(save_errno));
- goto fail_close;
- }
- if (fileName) break; // Only allow one as specified
+ fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
+ strerror(save_errno));
+ goto fail_unmap;
+ }
}
+ }
- newTagMap = new EventTagMap;
- if (newTagMap == NULL) {
- save_errno = errno;
- goto fail_close;
+ for (which = 0; which < NUM_MAPS; ++which) {
+ if (parseMapLines(newTagMap, which) != 0) {
+ delete newTagMap;
+ return NULL;
}
+ }
- for (which = 0; which < NUM_MAPS; ++which) {
- if (fd[which] >= 0) {
- newTagMap->mapAddr[which] = mmap(NULL, end[which],
- which ?
- PROT_READ :
- PROT_READ | PROT_WRITE,
- which ?
- MAP_SHARED :
- MAP_PRIVATE,
- fd[which], 0);
- save_errno = errno;
- close(fd[which]);
- fd[which] = -1;
- if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
- (newTagMap->mapAddr[which] != NULL)) {
- newTagMap->mapLen[which] = end[which];
- } else if (!which) {
- const char* tagfile = fileName ? fileName : eventTagFiles[which];
-
- fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n",
- tagfile, strerror(save_errno));
- goto fail_unmap;
- }
- }
- }
-
- for (which = 0; which < NUM_MAPS; ++which) {
- if (parseMapLines(newTagMap, which) != 0) {
- delete newTagMap;
- return NULL;
- }
- }
-
- return newTagMap;
+ return newTagMap;
fail_unmap:
- save_errno = EINVAL;
- delete newTagMap;
+ save_errno = EINVAL;
+ delete newTagMap;
fail_close:
- for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
+ for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
fail_errno:
- errno = save_errno;
- return NULL;
+ errno = save_errno;
+ return NULL;
}
// Close the map.
LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
- if (map) delete map;
+ if (map) delete map;
+}
+
+// Cache miss, go to logd to acquire a public reference.
+// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
+static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
+ // call event tag service to arrange for a new tag
+ char* buf = NULL;
+ // Can not use android::base::StringPrintf, asprintf + free instead.
+ static const char command_template[] = "getEventTag id=%u";
+ int ret = asprintf(&buf, command_template, tag);
+ if (ret > 0) {
+ // Add some buffer margin for an estimate of the full return content.
+ char* cp;
+ size_t size =
+ ret - strlen(command_template) +
+ strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
+ if (size > (size_t)ret) {
+ cp = static_cast<char*>(realloc(buf, size));
+ if (cp) {
+ buf = cp;
+ } else {
+ size = ret;
+ }
+ } else {
+ size = ret;
+ }
+ // Ask event log tag service for an existing entry
+ if (__send_log_msg(buf, size) >= 0) {
+ buf[size - 1] = '\0';
+ unsigned long val = strtoul(buf, &cp, 10); // return size
+ if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
+ ++cp;
+ if (!scanTagLine(map, &cp, 0)) {
+ free(buf);
+ return map->find(tag);
+ }
+ }
+ }
+ free(buf);
+ }
+ return NULL;
}
// Look up an entry in the map.
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
- size_t *len,
+ size_t* len,
unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->first.length();
- return str->first.data();
+ if (len) *len = 0;
+ const TagFmt* str = map->find(tag);
+ if (!str) {
+ str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+ }
+ if (!str) return NULL;
+ if (len) *len = str->first.length();
+ return str->first.data();
}
// Look up an entry in the map.
LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
- const EventTagMap* map, size_t *len, unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->second.length();
- return str->second.data();
+ const EventTagMap* map, size_t* len, unsigned int tag) {
+ if (len) *len = 0;
+ const TagFmt* str = map->find(tag);
+ if (!str) {
+ str = __getEventTag(const_cast<EventTagMap*>(map), tag);
+ }
+ if (!str) return NULL;
+ if (len) *len = str->second.length();
+ return str->second.data();
}
// This function is deprecated and replaced with android_lookupEventTag_len
@@ -482,84 +558,84 @@
// deprecating this function everywhere, we save 100s of MB of memory space.
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
unsigned int tag) {
- size_t len;
- const char* tagStr = android_lookupEventTag_len(map, &len, tag);
+ size_t len;
+ const char* tagStr = android_lookupEventTag_len(map, &len, tag);
- if (!tagStr) return tagStr;
- char* cp = const_cast<char*>(tagStr);
- cp += len;
- if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
- return tagStr;
+ if (!tagStr) return tagStr;
+ char* cp = const_cast<char*>(tagStr);
+ cp += len;
+ if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
+ return tagStr;
}
// Look up tagname, generate one if necessary, and return a tag
LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
const char* tagname,
- const char* format,
- int prio) {
- size_t len = strlen(tagname);
- if (!len) {
- errno = EINVAL;
- return -1;
+ const char* format, int prio) {
+ size_t len = strlen(tagname);
+ if (!len) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
+ !__android_log_is_loggable_len(prio, tagname, len,
+ __android_log_is_debuggable()
+ ? ANDROID_LOG_VERBOSE
+ : ANDROID_LOG_DEBUG)) {
+ errno = EPERM;
+ return -1;
+ }
+
+ if (!format) format = "";
+ ssize_t fmtLen = strlen(format);
+ int ret = map->find(TagFmt(
+ std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
+ if (ret != -1) return ret;
+
+ // call event tag service to arrange for a new tag
+ char* buf = NULL;
+ // Can not use android::base::StringPrintf, asprintf + free instead.
+ static const char command_template[] = "getEventTag name=%s format=\"%s\"";
+ ret = asprintf(&buf, command_template, tagname, format);
+ if (ret > 0) {
+ // Add some buffer margin for an estimate of the full return content.
+ char* cp;
+ size_t size =
+ ret - strlen(command_template) +
+ strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
+ if (size > (size_t)ret) {
+ cp = static_cast<char*>(realloc(buf, size));
+ if (cp) {
+ buf = cp;
+ } else {
+ size = ret;
+ }
+ } else {
+ size = ret;
}
-
- if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
- !__android_log_is_loggable_len(prio, tagname, len,
- __android_log_is_debuggable() ?
- ANDROID_LOG_VERBOSE :
- ANDROID_LOG_DEBUG)) {
- errno = EPERM;
- return -1;
- }
-
- if (!format) format="";
- ssize_t fmtLen = strlen(format);
- int ret = map->find(TagFmt(std::make_pair(MapString(tagname, len),
- MapString(format, fmtLen))));
- if (ret != -1) return ret;
-
- // call event tag service to arrange for a new tag
- char *buf = NULL;
- // Can not use android::base::StringPrintf, asprintf + free instead.
- static const char command_template[] = "getEventTag name=%s format=\"%s\"";
- ret = asprintf(&buf, command_template, tagname, format);
- if (ret > 0) {
- // Add some buffer margin for an estimate of the full return content.
- char *cp;
- size_t size = ret - strlen(command_template) +
- strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
- if (size > (size_t)ret) {
- cp = static_cast<char*>(realloc(buf, size));
- if (cp) {
- buf = cp;
- } else {
- size = ret;
- }
- } else {
- size = ret;
+ // Ask event log tag service for an allocation
+ if (__send_log_msg(buf, size) >= 0) {
+ buf[size - 1] = '\0';
+ unsigned long val = strtoul(buf, &cp, 10); // return size
+ if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
+ val = strtoul(cp + 1, &cp, 10); // allocated tag number
+ if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
+ free(buf);
+ ret = val;
+ // cache
+ map->emplaceUnique(ret, TagFmt(std::make_pair(
+ MapString(std::string(tagname, len)),
+ MapString(std::string(format, fmtLen)))));
+ return ret;
}
- // Ask event log tag service for an allocation
- if (__send_log_msg(buf, size) >= 0) {
- buf[size - 1] = '\0';
- unsigned long val = strtoul(buf, &cp, 10); // return size
- if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
- val = strtoul(cp + 1, &cp, 10); // allocated tag number
- if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
- free(buf);
- ret = val;
- // cache
- map->emplaceUnique(ret, TagFmt(std::make_pair(
- MapString(std::string(tagname, len)),
- MapString(std::string(format, fmtLen)))));
- return ret;
- }
- }
- }
- free(buf);
+ }
}
+ free(buf);
+ }
- // Hail Mary
- ret = map->find(MapString(tagname, len));
- if (ret == -1) errno = ESRCH;
- return ret;
+ // Hail Mary
+ ret = map->find(MapString(tagname, len));
+ if (ret == -1) errno = ESRCH;
+ return ret;
}
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 957129e..ae7a334 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -37,9 +37,9 @@
#include "fake_log_device.h"
#include "log_portability.h"
-#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
+#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
-#define kTagSetSize 16 /* arbitrary */
+#define kTagSetSize 16 /* arbitrary */
#if 0
#define TRACE(...) printf("fake_log_device: " __VA_ARGS__)
@@ -49,45 +49,43 @@
/* from the long-dead utils/Log.cpp */
typedef enum {
- FORMAT_OFF = 0,
- FORMAT_BRIEF,
- FORMAT_PROCESS,
- FORMAT_TAG,
- FORMAT_THREAD,
- FORMAT_RAW,
- FORMAT_TIME,
- FORMAT_THREADTIME,
- FORMAT_LONG
+ FORMAT_OFF = 0,
+ FORMAT_BRIEF,
+ FORMAT_PROCESS,
+ FORMAT_TAG,
+ FORMAT_THREAD,
+ FORMAT_RAW,
+ FORMAT_TIME,
+ FORMAT_THREADTIME,
+ FORMAT_LONG
} LogFormat;
-
/*
* Log driver state.
*/
typedef struct LogState {
- /* the fake fd that's seen by the user */
- int fakeFd;
+ /* the fake fd that's seen by the user */
+ int fakeFd;
- /* a printable name for this fake device */
- char debugName[sizeof("/dev/log/security")];
+ /* a printable name for this fake device */
+ char debugName[sizeof("/dev/log/security")];
- /* nonzero if this is a binary log */
- int isBinary;
+ /* nonzero if this is a binary log */
+ int isBinary;
- /* global minimum priority */
- int globalMinPriority;
+ /* global minimum priority */
+ int globalMinPriority;
- /* output format */
- LogFormat outputFormat;
+ /* output format */
+ LogFormat outputFormat;
- /* tags and priorities */
- struct {
- char tag[kMaxTagLen];
- int minPriority;
- } tagSet[kTagSetSize];
+ /* tags and priorities */
+ struct {
+ char tag[kMaxTagLen];
+ int minPriority;
+ } tagSet[kTagSetSize];
} LogState;
-
#if !defined(_WIN32)
/*
* Locking. Since we're emulating a device, we need to be prepared
@@ -97,28 +95,25 @@
*/
static pthread_mutex_t fakeLogDeviceLock = PTHREAD_MUTEX_INITIALIZER;
-static void lock()
-{
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&fakeLogDeviceLock);
+static void lock() {
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ pthread_mutex_lock(&fakeLogDeviceLock);
}
-static void unlock()
-{
- pthread_mutex_unlock(&fakeLogDeviceLock);
+static void unlock() {
+ pthread_mutex_unlock(&fakeLogDeviceLock);
}
-#else // !defined(_WIN32)
+#else // !defined(_WIN32)
#define lock() ((void)0)
#define unlock() ((void)0)
#endif // !defined(_WIN32)
-
/*
* File descriptor management.
*/
@@ -130,45 +125,42 @@
* Allocate an fd and associate a new LogState with it.
* The fd is available via the fakeFd field of the return value.
*/
-static LogState *createLogState()
-{
- size_t i;
+static LogState* createLogState() {
+ size_t i;
- for (i = 0; i < (sizeof(openLogTable) / sizeof(openLogTable[0])); i++) {
- if (openLogTable[i].fakeFd == 0) {
- openLogTable[i].fakeFd = FAKE_FD_BASE + i;
- return &openLogTable[i];
- }
+ for (i = 0; i < (sizeof(openLogTable) / sizeof(openLogTable[0])); i++) {
+ if (openLogTable[i].fakeFd == 0) {
+ openLogTable[i].fakeFd = FAKE_FD_BASE + i;
+ return &openLogTable[i];
}
- return NULL;
+ }
+ return NULL;
}
/*
* Translate an fd to a LogState.
*/
-static LogState *fdToLogState(int fd)
-{
- if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) {
- return &openLogTable[fd - FAKE_FD_BASE];
- }
- return NULL;
+static LogState* fdToLogState(int fd) {
+ if (fd >= FAKE_FD_BASE && fd < FAKE_FD_BASE + MAX_OPEN_LOGS) {
+ return &openLogTable[fd - FAKE_FD_BASE];
+ }
+ return NULL;
}
/*
* Unregister the fake fd and free the memory it pointed to.
*/
-static void deleteFakeFd(int fd)
-{
- LogState *ls;
+static void deleteFakeFd(int fd) {
+ LogState* ls;
- lock();
+ lock();
- ls = fdToLogState(fd);
- if (ls != NULL) {
- memset(&openLogTable[fd - FAKE_FD_BASE], 0, sizeof(openLogTable[0]));
- }
+ ls = fdToLogState(fd);
+ if (ls != NULL) {
+ memset(&openLogTable[fd - FAKE_FD_BASE], 0, sizeof(openLogTable[0]));
+ }
- unlock();
+ unlock();
}
/*
@@ -184,145 +176,154 @@
* We also want to check ANDROID_PRINTF_LOG to determine how the output
* will look.
*/
-static void configureInitialState(const char* pathName, LogState* logState)
-{
- static const int kDevLogLen = sizeof("/dev/log/") - 1;
+static void configureInitialState(const char* pathName, LogState* logState) {
+ static const int kDevLogLen = sizeof("/dev/log/") - 1;
- strncpy(logState->debugName, pathName, sizeof(logState->debugName));
- logState->debugName[sizeof(logState->debugName) - 1] = '\0';
+ strncpy(logState->debugName, pathName, sizeof(logState->debugName));
+ logState->debugName[sizeof(logState->debugName) - 1] = '\0';
- /* identify binary logs */
- if (!strcmp(pathName + kDevLogLen, "events") ||
- !strcmp(pathName + kDevLogLen, "security")) {
- logState->isBinary = 1;
- }
+ /* identify binary logs */
+ if (!strcmp(pathName + kDevLogLen, "events") ||
+ !strcmp(pathName + kDevLogLen, "security")) {
+ logState->isBinary = 1;
+ }
- /* global min priority defaults to "info" level */
- logState->globalMinPriority = ANDROID_LOG_INFO;
+ /* global min priority defaults to "info" level */
+ logState->globalMinPriority = ANDROID_LOG_INFO;
- /*
- * This is based on the the long-dead utils/Log.cpp code.
- */
- const char* tags = getenv("ANDROID_LOG_TAGS");
- TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags);
- if (tags != NULL) {
- int entry = 0;
+ /*
+ * This is based on the the long-dead utils/Log.cpp code.
+ */
+ const char* tags = getenv("ANDROID_LOG_TAGS");
+ TRACE("Found ANDROID_LOG_TAGS='%s'\n", tags);
+ if (tags != NULL) {
+ int entry = 0;
- while (*tags != '\0') {
- char tagName[kMaxTagLen];
- int i, minPrio;
+ while (*tags != '\0') {
+ char tagName[kMaxTagLen];
+ int i, minPrio;
- while (isspace(*tags))
- tags++;
+ while (isspace(*tags)) tags++;
- i = 0;
- while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
- i < kMaxTagLen) {
- tagName[i++] = *tags++;
- }
- if (i == kMaxTagLen) {
- TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen-1);
- return;
- }
- tagName[i] = '\0';
+ i = 0;
+ while (*tags != '\0' && !isspace(*tags) && *tags != ':' &&
+ i < kMaxTagLen) {
+ tagName[i++] = *tags++;
+ }
+ if (i == kMaxTagLen) {
+ TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen - 1);
+ return;
+ }
+ tagName[i] = '\0';
- /* default priority, if there's no ":" part; also zero out '*' */
+ /* default priority, if there's no ":" part; also zero out '*' */
+ minPrio = ANDROID_LOG_VERBOSE;
+ if (tagName[0] == '*' && tagName[1] == '\0') {
+ minPrio = ANDROID_LOG_DEBUG;
+ tagName[0] = '\0';
+ }
+
+ if (*tags == ':') {
+ tags++;
+ if (*tags >= '0' && *tags <= '9') {
+ if (*tags >= ('0' + ANDROID_LOG_SILENT))
minPrio = ANDROID_LOG_VERBOSE;
- if (tagName[0] == '*' && tagName[1] == '\0') {
- minPrio = ANDROID_LOG_DEBUG;
- tagName[0] = '\0';
- }
-
- if (*tags == ':') {
- tags++;
- if (*tags >= '0' && *tags <= '9') {
- if (*tags >= ('0' + ANDROID_LOG_SILENT))
- minPrio = ANDROID_LOG_VERBOSE;
- else
- minPrio = *tags - '\0';
- } else {
- switch (*tags) {
- case 'v': minPrio = ANDROID_LOG_VERBOSE; break;
- case 'd': minPrio = ANDROID_LOG_DEBUG; break;
- case 'i': minPrio = ANDROID_LOG_INFO; break;
- case 'w': minPrio = ANDROID_LOG_WARN; break;
- case 'e': minPrio = ANDROID_LOG_ERROR; break;
- case 'f': minPrio = ANDROID_LOG_FATAL; break;
- case 's': minPrio = ANDROID_LOG_SILENT; break;
- default: minPrio = ANDROID_LOG_DEFAULT; break;
- }
- }
-
- tags++;
- if (*tags != '\0' && !isspace(*tags)) {
- TRACE("ERROR: garbage in tag env; expected whitespace\n");
- TRACE(" env='%s'\n", tags);
- return;
- }
- }
-
- if (tagName[0] == 0) {
- logState->globalMinPriority = minPrio;
- TRACE("+++ global min prio %d\n", logState->globalMinPriority);
- } else {
- logState->tagSet[entry].minPriority = minPrio;
- strcpy(logState->tagSet[entry].tag, tagName);
- TRACE("+++ entry %d: %s:%d\n",
- entry,
- logState->tagSet[entry].tag,
- logState->tagSet[entry].minPriority);
- entry++;
- }
+ else
+ minPrio = *tags - '\0';
+ } else {
+ switch (*tags) {
+ case 'v':
+ minPrio = ANDROID_LOG_VERBOSE;
+ break;
+ case 'd':
+ minPrio = ANDROID_LOG_DEBUG;
+ break;
+ case 'i':
+ minPrio = ANDROID_LOG_INFO;
+ break;
+ case 'w':
+ minPrio = ANDROID_LOG_WARN;
+ break;
+ case 'e':
+ minPrio = ANDROID_LOG_ERROR;
+ break;
+ case 'f':
+ minPrio = ANDROID_LOG_FATAL;
+ break;
+ case 's':
+ minPrio = ANDROID_LOG_SILENT;
+ break;
+ default:
+ minPrio = ANDROID_LOG_DEFAULT;
+ break;
+ }
}
+
+ tags++;
+ if (*tags != '\0' && !isspace(*tags)) {
+ TRACE("ERROR: garbage in tag env; expected whitespace\n");
+ TRACE(" env='%s'\n", tags);
+ return;
+ }
+ }
+
+ if (tagName[0] == 0) {
+ logState->globalMinPriority = minPrio;
+ TRACE("+++ global min prio %d\n", logState->globalMinPriority);
+ } else {
+ logState->tagSet[entry].minPriority = minPrio;
+ strcpy(logState->tagSet[entry].tag, tagName);
+ TRACE("+++ entry %d: %s:%d\n", entry, logState->tagSet[entry].tag,
+ logState->tagSet[entry].minPriority);
+ entry++;
+ }
}
+ }
+ /*
+ * Taken from the long-dead utils/Log.cpp
+ */
+ const char* fstr = getenv("ANDROID_PRINTF_LOG");
+ LogFormat format;
+ if (fstr == NULL) {
+ format = FORMAT_BRIEF;
+ } else {
+ if (strcmp(fstr, "brief") == 0)
+ format = FORMAT_BRIEF;
+ else if (strcmp(fstr, "process") == 0)
+ format = FORMAT_PROCESS;
+ else if (strcmp(fstr, "tag") == 0)
+ format = FORMAT_PROCESS;
+ else if (strcmp(fstr, "thread") == 0)
+ format = FORMAT_PROCESS;
+ else if (strcmp(fstr, "raw") == 0)
+ format = FORMAT_PROCESS;
+ else if (strcmp(fstr, "time") == 0)
+ format = FORMAT_PROCESS;
+ else if (strcmp(fstr, "long") == 0)
+ format = FORMAT_PROCESS;
+ else
+ format = (LogFormat)atoi(fstr); // really?!
+ }
- /*
- * Taken from the long-dead utils/Log.cpp
- */
- const char* fstr = getenv("ANDROID_PRINTF_LOG");
- LogFormat format;
- if (fstr == NULL) {
- format = FORMAT_BRIEF;
- } else {
- if (strcmp(fstr, "brief") == 0)
- format = FORMAT_BRIEF;
- else if (strcmp(fstr, "process") == 0)
- format = FORMAT_PROCESS;
- else if (strcmp(fstr, "tag") == 0)
- format = FORMAT_PROCESS;
- else if (strcmp(fstr, "thread") == 0)
- format = FORMAT_PROCESS;
- else if (strcmp(fstr, "raw") == 0)
- format = FORMAT_PROCESS;
- else if (strcmp(fstr, "time") == 0)
- format = FORMAT_PROCESS;
- else if (strcmp(fstr, "long") == 0)
- format = FORMAT_PROCESS;
- else
- format = (LogFormat) atoi(fstr); // really?!
- }
-
- logState->outputFormat = format;
+ logState->outputFormat = format;
}
/*
* Return a human-readable string for the priority level. Always returns
* a valid string.
*/
-static const char* getPriorityString(int priority)
-{
- /* the first character of each string should be unique */
- static const char* priorityStrings[] = {
- "Verbose", "Debug", "Info", "Warn", "Error", "Assert"
- };
- int idx;
+static const char* getPriorityString(int priority) {
+ /* the first character of each string should be unique */
+ static const char* priorityStrings[] = { "Verbose", "Debug", "Info",
+ "Warn", "Error", "Assert" };
+ int idx;
- idx = (int)priority - (int)ANDROID_LOG_VERBOSE;
- if (idx < 0 ||
- idx >= (int)(sizeof(priorityStrings) / sizeof(priorityStrings[0])))
- return "?unknown?";
- return priorityStrings[idx];
+ idx = (int)priority - (int)ANDROID_LOG_VERBOSE;
+ if (idx < 0 ||
+ idx >= (int)(sizeof(priorityStrings) / sizeof(priorityStrings[0])))
+ return "?unknown?";
+ return priorityStrings[idx];
}
#if defined(_WIN32)
@@ -330,227 +331,229 @@
* WIN32 does not have writev().
* Make up something to replace it.
*/
-static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
- ssize_t result = 0;
- const struct iovec* end = iov + iovcnt;
- for (; iov < end; iov++) {
- ssize_t w = write(fd, iov->iov_base, iov->iov_len);
- if (w != (ssize_t) iov->iov_len) {
- if (w < 0)
- return w;
- return result + w;
- }
- result += w;
+static ssize_t fake_writev(int fd, const struct iovec* iov, int iovcnt) {
+ ssize_t result = 0;
+ const struct iovec* end = iov + iovcnt;
+ for (; iov < end; iov++) {
+ ssize_t w = write(fd, iov->iov_base, iov->iov_len);
+ if (w != (ssize_t)iov->iov_len) {
+ if (w < 0) return w;
+ return result + w;
}
- return result;
+ result += w;
+ }
+ return result;
}
#define writev fake_writev
#endif
-
/*
* Write a filtered log message to stderr.
*
* Log format parsing taken from the long-dead utils/Log.cpp.
*/
-static void showLog(LogState *state,
- int logPrio, const char* tag, const char* msg)
-{
+static void showLog(LogState* state, int logPrio, const char* tag,
+ const char* msg) {
#if !defined(_WIN32)
- struct tm tmBuf;
+ struct tm tmBuf;
#endif
- struct tm* ptm;
- char timeBuf[32];
- char prefixBuf[128], suffixBuf[128];
- char priChar;
- time_t when;
+ struct tm* ptm;
+ char timeBuf[32];
+ char prefixBuf[128], suffixBuf[128];
+ char priChar;
+ time_t when;
#if !defined(_WIN32)
- pid_t pid, tid;
+ pid_t pid, tid;
#else
- uint32_t pid, tid;
+ uint32_t pid, tid;
#endif
- TRACE("LOG %d: %s %s", logPrio, tag, msg);
+ TRACE("LOG %d: %s %s", logPrio, tag, msg);
- priChar = getPriorityString(logPrio)[0];
- when = time(NULL);
- pid = tid = getpid(); // find gettid()?
+ priChar = getPriorityString(logPrio)[0];
+ when = time(NULL);
+ pid = tid = getpid(); // find gettid()?
- /*
- * Get the current date/time in pretty form
- *
- * It's often useful when examining a log with "less" to jump to
- * a specific point in the file by searching for the date/time stamp.
- * For this reason it's very annoying to have regexp meta characters
- * in the time stamp. Don't use forward slashes, parenthesis,
- * brackets, asterisks, or other special chars here.
- */
+/*
+ * Get the current date/time in pretty form
+ *
+ * It's often useful when examining a log with "less" to jump to
+ * a specific point in the file by searching for the date/time stamp.
+ * For this reason it's very annoying to have regexp meta characters
+ * in the time stamp. Don't use forward slashes, parenthesis,
+ * brackets, asterisks, or other special chars here.
+ */
#if !defined(_WIN32)
- ptm = localtime_r(&when, &tmBuf);
+ ptm = localtime_r(&when, &tmBuf);
#else
- ptm = localtime(&when);
+ ptm = localtime(&when);
#endif
- //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
- strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+ // strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+ strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
- /*
- * Construct a buffer containing the log header and log message.
- */
- size_t prefixLen, suffixLen;
+ /*
+ * Construct a buffer containing the log header and log message.
+ */
+ size_t prefixLen, suffixLen;
- switch (state->outputFormat) {
+ switch (state->outputFormat) {
case FORMAT_TAG:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%c/%-8s: ", priChar, tag);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
+ prefixLen =
+ snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s: ", priChar, tag);
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
case FORMAT_PROCESS:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%c(%5d) ", priChar, pid);
- suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
- " (%s)\n", tag);
- break;
+ prefixLen =
+ snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d) ", priChar, pid);
+ suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), " (%s)\n", tag);
+ break;
case FORMAT_THREAD:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%c(%5d:%5d) ", priChar, pid, tid);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
+ prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d:%5d) ",
+ priChar, pid, tid);
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
case FORMAT_RAW:
- prefixBuf[0] = 0; prefixLen = 0;
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
+ prefixBuf[0] = 0;
+ prefixLen = 0;
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
case FORMAT_TIME:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%s %-8s\n\t", timeBuf, tag);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
+ prefixLen =
+ snprintf(prefixBuf, sizeof(prefixBuf), "%s %-8s\n\t", timeBuf, tag);
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
case FORMAT_THREADTIME:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
+ prefixLen =
+ snprintf(prefixBuf, sizeof(prefixBuf), "%s %5d %5d %c %-8s \n\t",
+ timeBuf, pid, tid, priChar, tag);
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
case FORMAT_LONG:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "[ %s %5d:%5d %c/%-8s ]\n",
- timeBuf, pid, tid, priChar, tag);
- strcpy(suffixBuf, "\n\n"); suffixLen = 2;
- break;
+ prefixLen =
+ snprintf(prefixBuf, sizeof(prefixBuf), "[ %s %5d:%5d %c/%-8s ]\n",
+ timeBuf, pid, tid, priChar, tag);
+ strcpy(suffixBuf, "\n\n");
+ suffixLen = 2;
+ break;
default:
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
- "%c/%-8s(%5d): ", priChar, tag, pid);
- strcpy(suffixBuf, "\n"); suffixLen = 1;
- break;
- }
+ prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
+ "%c/%-8s(%5d): ", priChar, tag, pid);
+ strcpy(suffixBuf, "\n");
+ suffixLen = 1;
+ break;
+ }
- /*
- * Figure out how many lines there will be.
- */
- const char* end = msg + strlen(msg);
- size_t numLines = 0;
- const char* p = msg;
- while (p < end) {
- if (*p++ == '\n') numLines++;
+ /*
+ * Figure out how many lines there will be.
+ */
+ const char* end = msg + strlen(msg);
+ size_t numLines = 0;
+ const char* p = msg;
+ while (p < end) {
+ if (*p++ == '\n') numLines++;
+ }
+ if (p > msg && *(p - 1) != '\n') {
+ numLines++;
+ }
+
+ /*
+ * Create an array of iovecs large enough to write all of
+ * the lines with a prefix and a suffix.
+ */
+ const size_t INLINE_VECS = 64;
+ const size_t MAX_LINES = ((size_t)~0) / (3 * sizeof(struct iovec*));
+ struct iovec stackVec[INLINE_VECS];
+ struct iovec* vec = stackVec;
+ size_t numVecs;
+
+ if (numLines > MAX_LINES) numLines = MAX_LINES;
+
+ numVecs = numLines * 3; // 3 iovecs per line.
+ if (numVecs > INLINE_VECS) {
+ vec = (struct iovec*)malloc(sizeof(struct iovec) * numVecs);
+ if (vec == NULL) {
+ msg = "LOG: write failed, no memory";
+ numVecs = INLINE_VECS;
+ numLines = numVecs / 3;
+ vec = stackVec;
}
- if (p > msg && *(p-1) != '\n') {
- numLines++;
+ }
+
+ /*
+ * Fill in the iovec pointers.
+ */
+ p = msg;
+ struct iovec* v = vec;
+ int totalLen = 0;
+ while (numLines > 0 && p < end) {
+ if (prefixLen > 0) {
+ v->iov_base = prefixBuf;
+ v->iov_len = prefixLen;
+ totalLen += prefixLen;
+ v++;
}
-
- /*
- * Create an array of iovecs large enough to write all of
- * the lines with a prefix and a suffix.
- */
- const size_t INLINE_VECS = 64;
- const size_t MAX_LINES = ((size_t)~0)/(3*sizeof(struct iovec*));
- struct iovec stackVec[INLINE_VECS];
- struct iovec* vec = stackVec;
- size_t numVecs;
-
- if (numLines > MAX_LINES)
- numLines = MAX_LINES;
-
- numVecs = numLines * 3; // 3 iovecs per line.
- if (numVecs > INLINE_VECS) {
- vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
- if (vec == NULL) {
- msg = "LOG: write failed, no memory";
- numVecs = INLINE_VECS;
- numLines = numVecs / 3;
- vec = stackVec;
- }
+ const char* start = p;
+ while (p < end && *p != '\n') {
+ p++;
}
-
- /*
- * Fill in the iovec pointers.
- */
- p = msg;
- struct iovec* v = vec;
- int totalLen = 0;
- while (numLines > 0 && p < end) {
- if (prefixLen > 0) {
- v->iov_base = prefixBuf;
- v->iov_len = prefixLen;
- totalLen += prefixLen;
- v++;
- }
- const char* start = p;
- while (p < end && *p != '\n') {
- p++;
- }
- if ((p-start) > 0) {
- v->iov_base = (void*)start;
- v->iov_len = p-start;
- totalLen += p-start;
- v++;
- }
- if (*p == '\n') p++;
- if (suffixLen > 0) {
- v->iov_base = suffixBuf;
- v->iov_len = suffixLen;
- totalLen += suffixLen;
- v++;
- }
- numLines -= 1;
+ if ((p - start) > 0) {
+ v->iov_base = (void*)start;
+ v->iov_len = p - start;
+ totalLen += p - start;
+ v++;
}
-
- /*
- * Write the entire message to the log file with a single writev() call.
- * We need to use this rather than a collection of printf()s on a FILE*
- * because of multi-threading and multi-process issues.
- *
- * If the file was not opened with O_APPEND, this will produce interleaved
- * output when called on the same file from multiple processes.
- *
- * If the file descriptor is actually a network socket, the writev()
- * call may return with a partial write. Putting the writev() call in
- * a loop can result in interleaved data. This can be alleviated
- * somewhat by wrapping the writev call in the Mutex.
- */
-
- for(;;) {
- int cc = writev(fileno(stderr), vec, v-vec);
-
- if (cc == totalLen) break;
-
- if (cc < 0) {
- if(errno == EINTR) continue;
-
- /* can't really log the failure; for now, throw out a stderr */
- fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
- break;
- } else {
- /* shouldn't happen when writing to file or tty */
- fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
- break;
- }
+ if (*p == '\n') p++;
+ if (suffixLen > 0) {
+ v->iov_base = suffixBuf;
+ v->iov_len = suffixLen;
+ totalLen += suffixLen;
+ v++;
}
+ numLines -= 1;
+ }
- /* if we allocated storage for the iovecs, free it */
- if (vec != stackVec)
- free(vec);
+ /*
+ * Write the entire message to the log file with a single writev() call.
+ * We need to use this rather than a collection of printf()s on a FILE*
+ * because of multi-threading and multi-process issues.
+ *
+ * If the file was not opened with O_APPEND, this will produce interleaved
+ * output when called on the same file from multiple processes.
+ *
+ * If the file descriptor is actually a network socket, the writev()
+ * call may return with a partial write. Putting the writev() call in
+ * a loop can result in interleaved data. This can be alleviated
+ * somewhat by wrapping the writev call in the Mutex.
+ */
+
+ for (;;) {
+ int cc = writev(fileno(stderr), vec, v - vec);
+
+ if (cc == totalLen) break;
+
+ if (cc < 0) {
+ if (errno == EINTR) continue;
+
+ /* can't really log the failure; for now, throw out a stderr */
+ fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
+ break;
+ } else {
+ /* shouldn't happen when writing to file or tty */
+ fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen);
+ break;
+ }
+ }
+
+ /* if we allocated storage for the iovecs, free it */
+ if (vec != stackVec) free(vec);
}
-
/*
* Receive a log message. We happen to know that "vector" has three parts:
*
@@ -558,137 +561,135 @@
* tag (N bytes -- null-terminated ASCII string)
* message (N bytes -- null-terminated ASCII string)
*/
-static ssize_t logWritev(int fd, const struct iovec* vector, int count)
-{
- LogState* state;
+static ssize_t logWritev(int fd, const struct iovec* vector, int count) {
+ LogState* state;
- /* Make sure that no-one frees the LogState while we're using it.
- * Also guarantees that only one thread is in showLog() at a given
- * time (if it matters).
- */
- lock();
+ /* Make sure that no-one frees the LogState while we're using it.
+ * Also guarantees that only one thread is in showLog() at a given
+ * time (if it matters).
+ */
+ lock();
- state = fdToLogState(fd);
- if (state == NULL) {
- errno = EBADF;
- goto error;
+ state = fdToLogState(fd);
+ if (state == NULL) {
+ errno = EBADF;
+ goto error;
+ }
+
+ if (state->isBinary) {
+ TRACE("%s: ignoring binary log\n", state->debugName);
+ goto bail;
+ }
+
+ if (count != 3) {
+ TRACE("%s: writevLog with count=%d not expected\n", state->debugName, count);
+ goto error;
+ }
+
+ /* pull out the three fields */
+ int logPrio = *(const char*)vector[0].iov_base;
+ const char* tag = (const char*)vector[1].iov_base;
+ const char* msg = (const char*)vector[2].iov_base;
+
+ /* see if this log tag is configured */
+ int i;
+ int minPrio = state->globalMinPriority;
+ for (i = 0; i < kTagSetSize; i++) {
+ if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
+ break; /* reached end of configured values */
+
+ if (strcmp(state->tagSet[i].tag, tag) == 0) {
+ // TRACE("MATCH tag '%s'\n", tag);
+ minPrio = state->tagSet[i].minPriority;
+ break;
}
+ }
- if (state->isBinary) {
- TRACE("%s: ignoring binary log\n", state->debugName);
- goto bail;
- }
-
- if (count != 3) {
- TRACE("%s: writevLog with count=%d not expected\n",
- state->debugName, count);
- goto error;
- }
-
- /* pull out the three fields */
- int logPrio = *(const char*)vector[0].iov_base;
- const char* tag = (const char*) vector[1].iov_base;
- const char* msg = (const char*) vector[2].iov_base;
-
- /* see if this log tag is configured */
- int i;
- int minPrio = state->globalMinPriority;
- for (i = 0; i < kTagSetSize; i++) {
- if (state->tagSet[i].minPriority == ANDROID_LOG_UNKNOWN)
- break; /* reached end of configured values */
-
- if (strcmp(state->tagSet[i].tag, tag) == 0) {
- //TRACE("MATCH tag '%s'\n", tag);
- minPrio = state->tagSet[i].minPriority;
- break;
- }
- }
-
- if (logPrio >= minPrio) {
- showLog(state, logPrio, tag, msg);
- } else {
- //TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
- }
+ if (logPrio >= minPrio) {
+ showLog(state, logPrio, tag, msg);
+ } else {
+ // TRACE("+++ NOLOG(%d): %s %s", logPrio, tag, msg);
+ }
bail:
- unlock();
- return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;
+ unlock();
+ int len = 0;
+ for (i = 0; i < count; ++i) {
+ len += vector[i].iov_len;
+ }
+ return len;
+
error:
- unlock();
- return -1;
+ unlock();
+ return -1;
}
/*
* Free up our state and close the fake descriptor.
*/
-static int logClose(int fd)
-{
- deleteFakeFd(fd);
- return 0;
+static int logClose(int fd) {
+ deleteFakeFd(fd);
+ return 0;
}
/*
* Open a log output device and return a fake fd.
*/
-static int logOpen(const char* pathName, int flags __unused)
-{
- LogState *logState;
- int fd = -1;
+static int logOpen(const char* pathName, int flags __unused) {
+ LogState* logState;
+ int fd = -1;
- lock();
+ lock();
- logState = createLogState();
- if (logState != NULL) {
- configureInitialState(pathName, logState);
- fd = logState->fakeFd;
- } else {
- errno = ENFILE;
- }
+ logState = createLogState();
+ if (logState != NULL) {
+ configureInitialState(pathName, logState);
+ fd = logState->fakeFd;
+ } else {
+ errno = ENFILE;
+ }
- unlock();
+ unlock();
- return fd;
+ return fd;
}
-
/*
* Runtime redirection. If this binary is running in the simulator,
* just pass log messages to the emulated device. If it's running
* outside of the simulator, write the log messages to stderr.
*/
-static int (*redirectOpen)(const char *pathName, int flags) = NULL;
+static int (*redirectOpen)(const char* pathName, int flags) = NULL;
static int (*redirectClose)(int fd) = NULL;
-static ssize_t (*redirectWritev)(int fd, const struct iovec* vector, int count)
- = NULL;
+static ssize_t (*redirectWritev)(int fd, const struct iovec* vector,
+ int count) = NULL;
-static void setRedirects()
-{
- const char *ws;
+static void setRedirects() {
+ const char* ws;
- /* Wrapsim sets this environment variable on children that it's
- * created using its LD_PRELOAD wrapper.
- */
- ws = getenv("ANDROID_WRAPSIM");
- if (ws != NULL && strcmp(ws, "1") == 0) {
- /* We're running inside wrapsim, so we can just write to the device. */
- redirectOpen = (int (*)(const char *pathName, int flags))open;
- redirectClose = close;
- redirectWritev = writev;
- } else {
- /* There's no device to delegate to; handle the logging ourselves. */
- redirectOpen = logOpen;
- redirectClose = logClose;
- redirectWritev = logWritev;
- }
+ /* Wrapsim sets this environment variable on children that it's
+ * created using its LD_PRELOAD wrapper.
+ */
+ ws = getenv("ANDROID_WRAPSIM");
+ if (ws != NULL && strcmp(ws, "1") == 0) {
+ /* We're running inside wrapsim, so we can just write to the device. */
+ redirectOpen = (int (*)(const char* pathName, int flags))open;
+ redirectClose = close;
+ redirectWritev = writev;
+ } else {
+ /* There's no device to delegate to; handle the logging ourselves. */
+ redirectOpen = logOpen;
+ redirectClose = logClose;
+ redirectWritev = logWritev;
+ }
}
-LIBLOG_HIDDEN int fakeLogOpen(const char *pathName, int flags)
-{
- if (redirectOpen == NULL) {
- setRedirects();
- }
- return redirectOpen(pathName, flags);
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags) {
+ if (redirectOpen == NULL) {
+ setRedirects();
+ }
+ return redirectOpen(pathName, flags);
}
/*
@@ -702,43 +703,37 @@
* call is in the exit handler. Logging can continue in the exit handler to
* help debug HOST tools ...
*/
-LIBLOG_HIDDEN int fakeLogClose(int fd)
-{
- /* Assume that open() was called first. */
- return redirectClose(fd);
+LIBLOG_HIDDEN int fakeLogClose(int fd) {
+ /* Assume that open() was called first. */
+ return redirectClose(fd);
}
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd,
- const struct iovec* vector, int count)
-{
- /* Assume that open() was called first. */
- return redirectWritev(fd, vector, count);
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
+ int count) {
+ /* Assume that open() was called first. */
+ return redirectWritev(fd, vector, count);
}
-LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf __unused,
- size_t buf_size __unused)
-{
- return -ENODEV;
+LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf __unused,
+ size_t buf_size __unused) {
+ return -ENODEV;
}
LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
- const char *tag __unused,
- int def)
-{
- int logLevel = def;
- return logLevel >= 0 && prio >= logLevel;
+ const char* tag __unused,
+ int def) {
+ int logLevel = def;
+ return logLevel >= 0 && prio >= logLevel;
}
LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
- const char *tag __unused,
+ const char* tag __unused,
size_t len __unused,
- int def)
-{
- int logLevel = def;
- return logLevel >= 0 && prio >= logLevel;
+ int def) {
+ int logLevel = def;
+ return logLevel >= 0 && prio >= logLevel;
}
-LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
-{
- return 1;
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() {
+ return 1;
}
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 4529b5d..462d026 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -23,9 +23,9 @@
struct iovec;
-LIBLOG_HIDDEN int fakeLogOpen(const char *pathName, int flags);
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags);
LIBLOG_HIDDEN int fakeLogClose(int fd);
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd,
- const struct iovec* vector, int count);
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
+ int count);
-#endif // _LIBLOG_FAKE_LOG_DEVICE_H
+#endif // _LIBLOG_FAKE_LOG_DEVICE_H
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index dab8bc5..969661a 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -27,56 +27,77 @@
static int fakeOpen();
static void fakeClose();
-static int fakeWrite(log_id_t log_id, struct timespec *ts,
- struct iovec *vec, size_t nr);
+static int fakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec,
+ size_t nr);
static int logFds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = {
- .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node },
- .context.private = &logFds,
- .name = "fake",
- .available = NULL,
- .open = fakeOpen,
- .close = fakeClose,
- .write = fakeWrite,
+ .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node },
+ .context.priv = &logFds,
+ .name = "fake",
+ .available = NULL,
+ .open = fakeOpen,
+ .close = fakeClose,
+ .write = fakeWrite,
};
static int fakeOpen() {
- int i;
+ int i;
- for (i = 0; i < LOG_ID_MAX; i++) {
- char buf[sizeof("/dev/log_security")];
- snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
- logFds[i] = fakeLogOpen(buf, O_WRONLY);
+ for (i = 0; i < LOG_ID_MAX; i++) {
+ /*
+ * Known maximum size string, plus an 8 character margin to deal with
+ * possible independent changes to android_log_id_to_name().
+ */
+ char buf[sizeof("/dev/log_security") + 8];
+ if (logFds[i] >= 0) {
+ continue;
}
- return 0;
+ snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+ logFds[i] = fakeLogOpen(buf, O_WRONLY);
+ if (logFds[i] < 0) {
+ fprintf(stderr, "fakeLogOpen(%s, O_WRONLY) failed\n", buf);
+ }
+ }
+ return 0;
}
static void fakeClose() {
- int i;
+ int i;
- for (i = 0; i < LOG_ID_MAX; i++) {
- fakeLogClose(logFds[i]);
- logFds[i] = -1;
- }
+ for (i = 0; i < LOG_ID_MAX; i++) {
+ fakeLogClose(logFds[i]);
+ logFds[i] = -1;
+ }
}
-static int fakeWrite(log_id_t log_id, struct timespec *ts __unused,
- struct iovec *vec, size_t nr)
-{
- ssize_t ret;
- int logFd;
+static int fakeWrite(log_id_t log_id, struct timespec* ts __unused,
+ struct iovec* vec, size_t nr) {
+ ssize_t ret;
+ size_t i;
+ int logFd, len;
- if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
- return -EBADF;
- }
+ if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
+ return -EINVAL;
+ }
- logFd = logFds[(int)log_id];
- ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
- if (ret < 0) {
- ret = -errno;
- }
+ len = 0;
+ for (i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
- return ret;
+ if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ len = LOGGER_ENTRY_MAX_PAYLOAD;
+ }
+
+ logFd = logFds[(int)log_id];
+ ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
+ if (ret < 0) {
+ ret = -errno;
+ } else if (ret > len) {
+ ret = len;
+ }
+
+ return ret;
}
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 9f198fe..15fba8b 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -50,8 +50,8 @@
* limit (e.g. 1023 characters max).
*
* 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.
+ * 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:
*
@@ -77,15 +77,15 @@
* Android log priority values, in ascending priority order.
*/
typedef enum android_LogPriority {
- ANDROID_LOG_UNKNOWN = 0,
- ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
- ANDROID_LOG_VERBOSE,
- ANDROID_LOG_DEBUG,
- ANDROID_LOG_INFO,
- ANDROID_LOG_WARN,
- ANDROID_LOG_ERROR,
- ANDROID_LOG_FATAL,
- ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
+ ANDROID_LOG_UNKNOWN = 0,
+ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ ANDROID_LOG_VERBOSE,
+ ANDROID_LOG_DEBUG,
+ ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN,
+ ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL,
+ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
/*
@@ -96,16 +96,16 @@
/*
* Send a formatted string to the log, used like printf(fmt,...)
*/
-int __android_log_print(int prio, const char* tag, const char* fmt, ...)
+int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#if defined(__GNUC__)
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
- __attribute__ ((__format__(gnu_printf, 3, 4)))
+ __attribute__((__format__(gnu_printf, 3, 4)))
#else
- __attribute__ ((__format__(printf, 3, 4)))
+ __attribute__((__format__(printf, 3, 4)))
#endif
#else
- __attribute__ ((__format__(printf, 3, 4)))
+ __attribute__((__format__(printf, 3, 4)))
#endif
#endif
;
@@ -114,17 +114,16 @@
* A variant of __android_log_print() that takes a va_list to list
* additional parameters.
*/
-int __android_log_vprint(int prio, const char* tag,
- const char* fmt, va_list ap)
+int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
#if defined(__GNUC__)
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
- __attribute__ ((__format__(gnu_printf, 3, 0)))
+ __attribute__((__format__(gnu_printf, 3, 0)))
#else
- __attribute__ ((__format__(printf, 3, 0)))
+ __attribute__((__format__(printf, 3, 0)))
#endif
#else
- __attribute__ ((__format__(printf, 3, 0)))
+ __attribute__((__format__(printf, 3, 0)))
#endif
#endif
;
@@ -133,18 +132,18 @@
* 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.
*/
-void __android_log_assert(const char* cond, const char* tag,
- const char* fmt, ...)
+void __android_log_assert(const char* cond, const char* tag, const char* fmt,
+ ...)
#if defined(__GNUC__)
- __attribute__ ((__noreturn__))
+ __attribute__((__noreturn__))
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
- __attribute__ ((__format__(gnu_printf, 3, 4)))
+ __attribute__((__format__(gnu_printf, 3, 4)))
#else
- __attribute__ ((__format__(printf, 3, 4)))
+ __attribute__((__format__(printf, 3, 4)))
#endif
#else
- __attribute__ ((__format__(printf, 3, 4)))
+ __attribute__((__format__(printf, 3, 4)))
#endif
#endif
;
diff --git a/liblog/include/log/event_tag_map.h b/liblog/include/log/event_tag_map.h
index e57e47b..8dd9157 100644
--- a/liblog/include/log/event_tag_map.h
+++ b/liblog/include/log/event_tag_map.h
@@ -21,7 +21,7 @@
extern "C" {
#endif
-#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
+#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
struct EventTagMap;
typedef struct EventTagMap EventTagMap;
@@ -42,21 +42,23 @@
* Look up a tag by index. Returns the tag string, or NULL if not found.
*/
const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag)
- __attribute__((deprecated("use android_lookupEventTag_len() instead to minimize MAP_PRIVATE copy-on-write memory impact")));
+ __attribute__((
+ deprecated("use android_lookupEventTag_len() instead to minimize "
+ "MAP_PRIVATE copy-on-write memory impact")));
/*
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
-const char* android_lookupEventTag_len(const EventTagMap* map,
- size_t* len, unsigned int tag);
+const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len,
+ unsigned int tag);
/*
* Look up a format by index. Returns the format string & string length,
* or NULL if not found. Returned string is not guaranteed to be nul terminated.
*/
-const char* android_lookupEventFormat_len(const EventTagMap* map,
- size_t* len, unsigned int tag);
+const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len,
+ unsigned int tag);
/*
* Look up tagname, generate one if necessary, and return a tag
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index db22211..6758c84 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -21,7 +21,7 @@
#if !defined(_WIN32)
#include <pthread.h>
#endif
-#include <stdint.h> /* uint16_t, int32_t */
+#include <stdint.h> /* uint16_t, int32_t */
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
@@ -95,9 +95,9 @@
int __android_log_bswrite(int32_t tag, const char* payload);
#define android_bWriteLog(tag, payload, len) \
- __android_log_bwrite(tag, payload, len)
+ __android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
- __android_log_btwrite(tag, type, payload, len)
+ __android_log_btwrite(tag, type, payload, len)
/*
* Event log entry types.
@@ -105,45 +105,46 @@
#ifndef __AndroidEventLogType_defined
#define __AndroidEventLogType_defined
typedef enum {
- /* Special markers for android_log_list_element type */
- EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
- EVENT_TYPE_UNKNOWN = '?', /* protocol error */
+ /* Special markers for android_log_list_element type */
+ EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
+ EVENT_TYPE_UNKNOWN = '?', /* protocol error */
- /* must match with declaration in java/android/android/util/EventLog.java */
- EVENT_TYPE_INT = 0, /* int32_t */
- EVENT_TYPE_LONG = 1, /* int64_t */
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
+ /* must match with declaration in java/android/android/util/EventLog.java */
+ EVENT_TYPE_INT = 0, /* int32_t */
+ EVENT_TYPE_LONG = 1, /* int64_t */
+ EVENT_TYPE_STRING = 2,
+ EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
} AndroidEventLogType;
#endif
#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
#define typeof_AndroidEventLogType unsigned char
#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) { \
- int intBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
- sizeof(intBuf)); \
- }
+#define LOG_EVENT_INT(_tag, _value) \
+ { \
+ int intBuf = _value; \
+ (void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
+ }
#endif
#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) { \
- long long longBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
- sizeof(longBuf)); \
- }
+#define LOG_EVENT_LONG(_tag, _value) \
+ { \
+ long long longBuf = _value; \
+ (void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
+ }
#endif
#ifndef LOG_EVENT_FLOAT
-#define LOG_EVENT_FLOAT(_tag, _value) { \
- float floatBuf = _value; \
- (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
- sizeof(floatBuf)); \
- }
+#define LOG_EVENT_FLOAT(_tag, _value) \
+ { \
+ float floatBuf = _value; \
+ (void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
+ sizeof(floatBuf)); \
+ }
#endif
#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value) \
- (void) __android_log_bswrite(_tag, _value);
+#define LOG_EVENT_STRING(_tag, _value) \
+ (void)__android_log_bswrite(_tag, _value);
#endif
#ifdef __linux__
@@ -179,10 +180,10 @@
#if __ANDROID_USE_LIBLOG_SAFETYNET_INTERFACE
#define android_errorWriteLog(tag, subTag) \
- __android_log_error_write(tag, subTag, -1, NULL, 0)
+ __android_log_error_write(tag, subTag, -1, NULL, 0)
#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
- __android_log_error_write(tag, subTag, uid, data, dataLen)
+ __android_log_error_write(tag, subTag, uid, data, dataLen)
int __android_log_error_write(int tag, const char* subTag, int32_t uid,
const char* data, uint32_t dataLen);
@@ -246,10 +247,9 @@
* }
*/
-#define IF_ALOG_RATELIMIT() \
- if (__android_log_ratelimit(0, NULL) > 0)
+#define IF_ALOG_RATELIMIT() if (__android_log_ratelimit(0, NULL) > 0)
#define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \
- if (__android_log_ratelimit(seconds, state) > 0)
+ if (__android_log_ratelimit(seconds, state) > 0)
#else
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index 31d49b2..55953fc 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -61,15 +61,15 @@
#ifndef __android_log_list_element_defined
#define __android_log_list_element_defined
typedef struct {
- AndroidEventLogType type;
- uint16_t complete;
- uint16_t len;
- union {
- int32_t int32;
- int64_t int64;
- char* string;
- float float32;
- } data;
+ AndroidEventLogType type;
+ uint16_t complete;
+ uint16_t len;
+ union {
+ int32_t int32;
+ int64_t int64;
+ char* string;
+ float float32;
+ } data;
} android_log_list_element;
#endif
@@ -91,8 +91,8 @@
int android_log_write_int32(android_log_context ctx, int32_t value);
int android_log_write_int64(android_log_context ctx, int64_t value);
int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx,
- const char* value, size_t maxlen);
+int android_log_write_string8_len(android_log_context ctx, const char* value,
+ size_t maxlen);
int android_log_write_float32(android_log_context ctx, float value);
/* Submit the composed list context to the specified logger id */
@@ -116,173 +116,182 @@
/* android_log_list C++ helpers */
extern "C++" {
class android_log_event_list {
-friend class __android_log_event_list;
+ friend class __android_log_event_list;
-private:
- android_log_context ctx;
- int ret;
+ private:
+ android_log_context ctx;
+ int ret;
- android_log_event_list(const android_log_event_list&) = delete;
- void operator =(const android_log_event_list&) = delete;
+ android_log_event_list(const android_log_event_list&) = delete;
+ void operator=(const android_log_event_list&) = delete;
-public:
- explicit android_log_event_list(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- explicit android_log_event_list(log_msg& log_msg) : ret(0) {
- ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- }
- ~android_log_event_list() { android_log_destroy(&ctx); }
+ public:
+ explicit android_log_event_list(int tag) : ret(0) {
+ ctx = create_android_logger(static_cast<uint32_t>(tag));
+ }
+ explicit android_log_event_list(log_msg& log_msg) : ret(0) {
+ ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
+ log_msg.entry.len - sizeof(uint32_t));
+ }
+ ~android_log_event_list() {
+ android_log_destroy(&ctx);
+ }
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) ret = retval;
- return retval;
- }
+ int close() {
+ int retval = android_log_destroy(&ctx);
+ if (retval < 0) ret = retval;
+ return retval;
+ }
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const { return ctx; }
+ /* To allow above C calls to use this class as parameter */
+ operator android_log_context() const {
+ return ctx;
+ }
- int status() const { return ret; }
+ int status() const {
+ return ret;
+ }
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
+ int begin() {
+ int retval = android_log_write_list_begin(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
+ int end() {
+ int retval = android_log_write_list_end(ctx);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
- android_log_event_list& operator <<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(int32_t value) {
+ int retval = android_log_write_int32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
- android_log_event_list& operator <<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(uint32_t value) {
+ int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
- android_log_event_list& operator <<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(int64_t value) {
+ int retval = android_log_write_int64(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
- android_log_event_list& operator <<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(uint64_t value) {
+ int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+ if (retval < 0) ret = retval;
+ return *this;
+ }
- android_log_event_list& operator <<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(const char* value) {
+ int retval = android_log_write_string8(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
#if defined(_USING_LIBCXX)
- android_log_event_list& operator <<(const std::string& value) {
- int retval = android_log_write_string8_len(ctx,
- value.data(),
- value.length());
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(const std::string& value) {
+ int retval =
+ android_log_write_string8_len(ctx, value.data(), value.length());
+ if (retval < 0) ret = retval;
+ return *this;
+ }
#endif
- android_log_event_list& operator <<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
+ android_log_event_list& operator<<(float value) {
+ int retval = android_log_write_float32(ctx, value);
+ if (retval < 0) ret = retval;
+ return *this;
+ }
- int write(log_id_t id = LOG_ID_EVENTS) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
- return ret;
- }
+ int write(log_id_t id = LOG_ID_EVENTS) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ return ret;
+ }
- int operator <<(log_id_t id) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
- android_log_destroy(&ctx);
- return ret;
- }
+ int operator<<(log_id_t id) {
+ int retval = android_log_write_list(ctx, id);
+ if (retval < 0) ret = retval;
+ android_log_destroy(&ctx);
+ return ret;
+ }
- /*
- * Append<Type> methods removes any integer promotion
- * confusion, and adds access to string with length.
- * Append methods are also added for all types for
- * convenience.
- */
+ /*
+ * Append<Type> methods removes any integer promotion
+ * confusion, and adds access to string with length.
+ * Append methods are also added for all types for
+ * convenience.
+ */
- bool AppendInt(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool AppendInt(int32_t value) {
+ int retval = android_log_write_int32(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
- bool AppendLong(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool AppendLong(int64_t value) {
+ int retval = android_log_write_int64(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
- bool AppendString(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool AppendString(const char* value) {
+ int retval = android_log_write_string8(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
- bool AppendString(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool AppendString(const char* value, size_t len) {
+ int retval = android_log_write_string8_len(ctx, value, len);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
#if defined(_USING_LIBCXX)
- bool AppendString(const std::string& value) {
- int retval = android_log_write_string8_len(ctx,
- value.data(),
- value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
+ bool AppendString(const std::string& value) {
+ int retval =
+ android_log_write_string8_len(ctx, value.data(), value.length());
+ if (retval < 0) ret = retval;
+ return ret;
+ }
- bool Append(const std::string& value) {
- int retval = android_log_write_string8_len(ctx,
- value.data(),
- value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
+ bool Append(const std::string& value) {
+ int retval =
+ android_log_write_string8_len(ctx, value.data(), value.length());
+ if (retval < 0) ret = retval;
+ return ret;
+ }
#endif
- bool AppendFloat(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool AppendFloat(float value) {
+ int retval = android_log_write_float32(ctx, value);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
- template <typename Tvalue>
- bool Append(Tvalue value) { *this << value; return ret >= 0; }
+ template <typename Tvalue>
+ bool Append(Tvalue value) {
+ *this << value;
+ return ret >= 0;
+ }
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
+ bool Append(const char* value, size_t len) {
+ int retval = android_log_write_string8_len(ctx, value, len);
+ if (retval < 0) ret = retval;
+ return ret >= 0;
+ }
- android_log_list_element read() { return android_log_read_next(ctx); }
- android_log_list_element peek() { return android_log_peek_next(ctx); }
-
+ android_log_list_element read() {
+ return android_log_read_next(ctx);
+ }
+ android_log_list_element peek() {
+ return android_log_peek_next(ctx);
+ }
};
}
#endif
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
index 3078e4e..7bfa277 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -24,17 +24,17 @@
#ifndef log_id_t_defined
#define log_id_t_defined
typedef enum log_id {
- LOG_ID_MIN = 0,
+ LOG_ID_MIN = 0,
- LOG_ID_MAIN = 0,
- LOG_ID_RADIO = 1,
- LOG_ID_EVENTS = 2,
- LOG_ID_SYSTEM = 3,
- LOG_ID_CRASH = 4,
- LOG_ID_SECURITY = 5,
- LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+ LOG_ID_MAIN = 0,
+ LOG_ID_RADIO = 1,
+ LOG_ID_EVENTS = 2,
+ LOG_ID_SYSTEM = 3,
+ LOG_ID_CRASH = 4,
+ LOG_ID_SECURITY = 5,
+ LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
- LOG_ID_MAX
+ LOG_ID_MAX
} log_id_t;
#endif
#define sizeof_log_id_t sizeof(typeof_log_id_t)
@@ -43,8 +43,10 @@
/*
* Send a simple string to the log.
*/
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+int __android_log_buf_write(int bufID, int prio, const char* tag,
+ const char* text);
+int __android_log_buf_print(int bufID, int prio, const char* tag,
+ const char* fmt, ...)
#if defined(__GNUC__)
__attribute__((__format__(printf, 4, 5)))
#endif
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index f45397a..da16158 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -56,21 +56,19 @@
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
-#define android_writeLog(prio, tag, text) \
- __android_log_write(prio, tag, text)
+#define android_writeLog(prio, tag, text) __android_log_write(prio, tag, text)
#define android_printLog(prio, tag, ...) \
- __android_log_print(prio, tag, __VA_ARGS__)
+ __android_log_print(prio, tag, __VA_ARGS__)
#define android_vprintLog(prio, cond, tag, ...) \
- __android_log_vprint(prio, tag, __VA_ARGS__)
+ __android_log_vprint(prio, tag, __VA_ARGS__)
/*
* Log macro that allows you to specify a number for the priority.
*/
#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
- android_printLog(priority, tag, __VA_ARGS__)
+#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
#endif
/*
@@ -78,7 +76,7 @@
*/
#ifndef LOG_PRI_VA
#define LOG_PRI_VA(priority, tag, fmt, args) \
- android_vprintLog(priority, NULL, tag, fmt, args)
+ android_vprintLog(priority, NULL, tag, fmt, args)
#endif
/* --------------------------------------------------------------------- */
@@ -91,16 +89,17 @@
/* Returns 2nd arg. Used to substitute default value if caller's vararg list
* is empty.
*/
-#define __android_second(dummy, second, ...) second
+#define __android_second(dummy, second, ...) second
/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
* returns nothing.
*/
-#define __android_rest(first, ...) , ## __VA_ARGS__
+#define __android_rest(first, ...) , ##__VA_ARGS__
-#define android_printAssert(cond, tag, ...) \
- __android_log_assert(cond, tag, \
- __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
+#define android_printAssert(cond, tag, ...) \
+ __android_log_assert(cond, tag, \
+ __android_second(0, ##__VA_ARGS__, NULL) \
+ __android_rest(__VA_ARGS__))
/*
* Log a fatal error. If the given condition fails, this stops program
@@ -109,15 +108,15 @@
* is -inverted- from the normal assert() semantics.
*/
#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
- : (void)0 )
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \
+ : (void)0)
#endif
#ifndef LOG_ALWAYS_FATAL
#define LOG_ALWAYS_FATAL(...) \
- ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+ (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
#endif
/*
@@ -137,7 +136,7 @@
#else
#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
@@ -150,7 +149,7 @@
* Stripped out of release builds. Uses the current LOG_TAG.
*/
#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
#endif
/* --------------------------------------------------------------------- */
@@ -175,7 +174,12 @@
#ifndef ALOGV
#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
-#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
+#define ALOGV(...) \
+ do { \
+ if (0) { \
+ __ALOGV(__VA_ARGS__); \
+ } \
+ } while (0)
#else
#define ALOGV(...) __ALOGV(__VA_ARGS__)
#endif
@@ -183,12 +187,11 @@
#ifndef ALOGV_IF
#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...) ((void)0)
+#define ALOGV_IF(cond, ...) ((void)0)
#else
-#define ALOGV_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define ALOGV_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
#endif
@@ -200,10 +203,9 @@
#endif
#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define ALOGD_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
@@ -214,10 +216,9 @@
#endif
#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define ALOGI_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
@@ -228,10 +229,9 @@
#endif
#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define ALOGW_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
@@ -242,10 +242,9 @@
#endif
#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define ALOGE_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/* --------------------------------------------------------------------- */
@@ -305,16 +304,14 @@
* The second argument may be NULL or "" to indicate the "global" tag.
*/
#ifndef ALOG
-#define ALOG(priority, tag, ...) \
- LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) \
- if (android_testLog(ANDROID_##priority, tag))
+#define IF_ALOG(priority, tag) if (android_testLog(ANDROID_##priority, tag))
#endif
/* --------------------------------------------------------------------- */
@@ -357,23 +354,23 @@
int default_prio);
#if LOG_NDEBUG /* Production */
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
- ANDROID_LOG_DEBUG) != 0)
+#define android_testLog(prio, tag) \
+ (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+ ANDROID_LOG_DEBUG) != 0)
#else
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
- ANDROID_LOG_VERBOSE) != 0)
+#define android_testLog(prio, tag) \
+ (__android_log_is_loggable_len(prio, tag, (tag && *tag) ? strlen(tag) : 0, \
+ ANDROID_LOG_VERBOSE) != 0)
#endif
#else
#if LOG_NDEBUG /* Production */
#define android_testLog(prio, tag) \
- (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
+ (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0)
#else
#define android_testLog(prio, tag) \
- (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
+ (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
#endif
#endif
diff --git a/liblog/include/log/log_radio.h b/liblog/include/log/log_radio.h
index 30a73f2..bd629fe 100644
--- a/liblog/include/log/log_radio.h
+++ b/liblog/include/log/log_radio.h
@@ -38,14 +38,24 @@
/* --------------------------------------------------------------------- */
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
/*
* Simplified macro to send a verbose radio log message using current LOG_TAG.
*/
#ifndef RLOGV
-#define __RLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define __RLOGV(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, \
+ __VA_ARGS__))
#if LOG_NDEBUG
-#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
+#define RLOGV(...) \
+ do { \
+ if (0) { \
+ __RLOGV(__VA_ARGS__); \
+ } \
+ } while (0)
#else
#define RLOGV(...) __RLOGV(__VA_ARGS__)
#endif
@@ -53,12 +63,13 @@
#ifndef RLOGV_IF
#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...) ((void)0)
+#define RLOGV_IF(cond, ...) ((void)0)
#else
-#define RLOGV_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define RLOGV_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
#endif
@@ -66,60 +77,68 @@
* Simplified macro to send a debug radio log message using current LOG_TAG.
*/
#ifndef RLOGD
-#define RLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#define RLOGD(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define RLOGD_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send an info radio log message using current LOG_TAG.
*/
#ifndef RLOGI
-#define RLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#define RLOGI(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define RLOGI_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send a warning radio log message using current LOG_TAG.
*/
#ifndef RLOGW
-#define RLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#define RLOGW(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define RLOGW_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send an error radio log message using current LOG_TAG.
*/
#ifndef RLOGE
-#define RLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#define RLOGE(...) \
+ ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define RLOGE_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
#endif /* _LIBS_LOG_LOG_RADIO_H */
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 5b5eebc..d118563 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -53,14 +53,14 @@
#ifndef __struct_logger_entry_defined
#define __struct_logger_entry_defined
struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t __pad; /* no matter what, we get 2 bytes of padding */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
+ uint16_t len; /* length of the payload */
+ uint16_t __pad; /* no matter what, we get 2 bytes of padding */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
#ifndef __cplusplus
- char msg[0]; /* the entry's payload */
+ char msg[0]; /* the entry's payload */
#endif
};
#endif
@@ -71,15 +71,15 @@
#ifndef __struct_logger_entry_v2_defined
#define __struct_logger_entry_v2_defined
struct logger_entry_v2 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- uint32_t euid; /* effective UID of logger */
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ uint32_t euid; /* effective UID of logger */
#ifndef __cplusplus
- char msg[0]; /* the entry's payload */
+ char msg[0]; /* the entry's payload */
#endif
} __attribute__((__packed__));
#endif
@@ -90,15 +90,15 @@
#ifndef __struct_logger_entry_v3_defined
#define __struct_logger_entry_v3_defined
struct logger_entry_v3 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload */
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ uint32_t lid; /* log id of the payload */
#ifndef __cplusplus
- char msg[0]; /* the entry's payload */
+ char msg[0]; /* the entry's payload */
#endif
} __attribute__((__packed__));
#endif
@@ -109,16 +109,16 @@
#ifndef __struct_logger_entry_v4_defined
#define __struct_logger_entry_v4_defined
struct logger_entry_v4 {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
- int32_t pid; /* generating process's pid */
- uint32_t tid; /* generating process's tid */
- uint32_t sec; /* seconds since Epoch */
- uint32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload, bottom 4 bits currently */
- uint32_t uid; /* generating process's uid */
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
+ int32_t pid; /* generating process's pid */
+ uint32_t tid; /* generating process's tid */
+ uint32_t sec; /* seconds since Epoch */
+ uint32_t nsec; /* nanoseconds */
+ uint32_t lid; /* log id of the payload, bottom 4 bits currently */
+ uint32_t uid; /* generating process's uid */
#ifndef __cplusplus
- char msg[0]; /* the entry's payload */
+ char msg[0]; /* the entry's payload */
#endif
};
#endif
@@ -135,77 +135,64 @@
* An attempt to read less than this amount may result
* in read() returning EINVAL.
*/
-#define LOGGER_ENTRY_MAX_LEN (5*1024)
+#define LOGGER_ENTRY_MAX_LEN (5 * 1024)
#ifndef __struct_log_msg_defined
#define __struct_log_msg_defined
struct log_msg {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry_v4 entry;
- struct logger_entry_v4 entry_v4;
- struct logger_entry_v3 entry_v3;
- struct logger_entry_v2 entry_v2;
- struct logger_entry entry_v1;
- } __attribute__((aligned(4)));
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+ struct logger_entry_v4 entry;
+ struct logger_entry_v4 entry_v4;
+ struct logger_entry_v3 entry_v3;
+ struct logger_entry_v2 entry_v2;
+ struct logger_entry entry_v1;
+ } __attribute__((aligned(4)));
#ifdef __cplusplus
- /* Matching log_time operators */
- bool operator== (const log_msg& T) const
- {
- return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
- }
- bool operator!= (const log_msg& T) const
- {
- return !(*this == T);
- }
- bool operator< (const log_msg& T) const
- {
- return (entry.sec < T.entry.sec)
- || ((entry.sec == T.entry.sec)
- && (entry.nsec < T.entry.nsec));
- }
- bool operator>= (const log_msg& T) const
- {
- return !(*this < T);
- }
- bool operator> (const log_msg& T) const
- {
- return (entry.sec > T.entry.sec)
- || ((entry.sec == T.entry.sec)
- && (entry.nsec > T.entry.nsec));
- }
- bool operator<= (const log_msg& T) const
- {
- return !(*this > T);
- }
- uint64_t nsec() const
- {
- return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
- }
+ /* Matching log_time operators */
+ bool operator==(const log_msg& T) const {
+ return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+ }
+ bool operator!=(const log_msg& T) const {
+ return !(*this == T);
+ }
+ bool operator<(const log_msg& T) const {
+ return (entry.sec < T.entry.sec) ||
+ ((entry.sec == T.entry.sec) && (entry.nsec < T.entry.nsec));
+ }
+ bool operator>=(const log_msg& T) const {
+ return !(*this < T);
+ }
+ bool operator>(const log_msg& T) const {
+ return (entry.sec > T.entry.sec) ||
+ ((entry.sec == T.entry.sec) && (entry.nsec > T.entry.nsec));
+ }
+ bool operator<=(const log_msg& T) const {
+ return !(*this > T);
+ }
+ uint64_t nsec() const {
+ return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+ }
- /* packet methods */
- log_id_t id()
- {
- return static_cast<log_id_t>(entry.lid);
+ /* packet methods */
+ log_id_t id() {
+ return static_cast<log_id_t>(entry.lid);
+ }
+ char* msg() {
+ unsigned short hdr_size = entry.hdr_size;
+ if (!hdr_size) {
+ hdr_size = sizeof(entry_v1);
}
- char* msg()
- {
- unsigned short hdr_size = entry.hdr_size;
- if (!hdr_size) {
- hdr_size = sizeof(entry_v1);
- }
- if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
- return NULL;
- }
- return reinterpret_cast<char*>(buf) + hdr_size;
+ if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
+ return NULL;
}
- unsigned int len()
- {
- return (entry.hdr_size ?
- entry.hdr_size :
- static_cast<uint16_t>(sizeof(entry_v1))) +
- entry.len;
- }
+ return reinterpret_cast<char*>(buf) + hdr_size;
+ }
+ unsigned int len() {
+ return (entry.hdr_size ? entry.hdr_size
+ : static_cast<uint16_t>(sizeof(entry_v1))) +
+ entry.len;
+ }
#endif
};
#endif
@@ -243,28 +230,30 @@
char* buf, size_t len);
ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
char* buf, size_t len);
-int android_logger_set_prune_list(struct logger_list* logger_list,
- char* buf, size_t len);
+int android_logger_set_prune_list(struct logger_list* logger_list, char* buf,
+ size_t len);
#endif
-#define ANDROID_LOG_RDONLY O_RDONLY
-#define ANDROID_LOG_WRONLY O_WRONLY
-#define ANDROID_LOG_RDWR O_RDWR
-#define ANDROID_LOG_ACCMODE O_ACCMODE
+#define ANDROID_LOG_RDONLY O_RDONLY
+#define ANDROID_LOG_WRONLY O_WRONLY
+#define ANDROID_LOG_RDWR O_RDWR
+#define ANDROID_LOG_ACCMODE O_ACCMODE
+#ifndef O_NONBLOCK
+#define ANDROID_LOG_NONBLOCK 0x00000800
+#else
#define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#endif
#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 2
-#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
+#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
#endif
#if __ANDROID_USE_LIBLOG_READER_INTERFACE > 1
-#define ANDROID_LOG_PSTORE 0x80000000
+#define ANDROID_LOG_PSTORE 0x80000000
#endif
-struct logger_list* android_logger_list_alloc(int mode,
- unsigned int tail,
+struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
pid_t pid);
-struct logger_list* android_logger_list_alloc_time(int mode,
- log_time start,
+struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
pid_t pid);
void android_logger_list_free(struct logger_list* logger_list);
/* In the purest sense, the following two are orthogonal interfaces */
@@ -272,14 +261,11 @@
struct log_msg* log_msg);
/* Multiple log_id_t opens */
-struct logger* android_logger_open(struct logger_list* logger_list,
- log_id_t id);
+struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
#define android_logger_close android_logger_free
/* Single log_id_t open */
-struct logger_list* android_logger_list_open(log_id_t id,
- int mode,
- unsigned int tail,
- pid_t pid);
+struct logger_list* android_logger_list_open(log_id_t id, int mode,
+ unsigned int tail, pid_t pid);
#define android_logger_list_close android_logger_list_free
#endif /* __ANDROID_USE_LIBLOG_READER_INTERFACE */
diff --git a/liblog/include/log/log_system.h b/liblog/include/log/log_system.h
index 8c1ec96..3b5ae22 100644
--- a/liblog/include/log/log_system.h
+++ b/liblog/include/log/log_system.h
@@ -36,14 +36,24 @@
#endif
#endif
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
/*
* Simplified macro to send a verbose system log message using current LOG_TAG.
*/
#ifndef SLOGV
-#define __SLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define __SLOGV(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
+ __VA_ARGS__))
#if LOG_NDEBUG
-#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
+#define SLOGV(...) \
+ do { \
+ if (0) { \
+ __SLOGV(__VA_ARGS__); \
+ } \
+ } while (0)
#else
#define SLOGV(...) __SLOGV(__VA_ARGS__)
#endif
@@ -51,12 +61,13 @@
#ifndef SLOGV_IF
#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...) ((void)0)
+#define SLOGV_IF(cond, ...) ((void)0)
#else
-#define SLOGV_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define SLOGV_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
#endif
@@ -64,60 +75,68 @@
* Simplified macro to send a debug system log message using current LOG_TAG.
*/
#ifndef SLOGD
-#define SLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#define SLOGD(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define SLOGD_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send an info system log message using current LOG_TAG.
*/
#ifndef SLOGI
-#define SLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#define SLOGI(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define SLOGI_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send a warning system log message using current LOG_TAG.
*/
#ifndef SLOGW
-#define SLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#define SLOGW(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define SLOGW_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
/*
* Simplified macro to send an error system log message using current LOG_TAG.
*/
#ifndef SLOGE
-#define SLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#define SLOGE(...) \
+ ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
+ __VA_ARGS__))
#endif
#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
- ( (__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
+#define SLOGE_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, \
+ LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
#endif
#endif /* _LIBS_LOG_LOG_SYSTEM_H */
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h
index 900dc1b..5f70f7d 100644
--- a/liblog/include/log/log_time.h
+++ b/liblog/include/log/log_time.h
@@ -34,159 +34,135 @@
* efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
*/
struct log_time {
-public:
- uint32_t tv_sec; /* good to Feb 5 2106 */
- uint32_t tv_nsec;
+ public:
+ uint32_t tv_sec; /* good to Feb 5 2106 */
+ uint32_t tv_nsec;
- static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
- static const uint32_t tv_nsec_max = 999999999UL;
+ static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+ static const uint32_t tv_nsec_max = 999999999UL;
- log_time(const timespec& T)
- {
- tv_sec = static_cast<uint32_t>(T.tv_sec);
- tv_nsec = static_cast<uint32_t>(T.tv_nsec);
- }
- log_time(uint32_t sec, uint32_t nsec)
- {
- tv_sec = sec;
- tv_nsec = nsec;
- }
+ log_time(const timespec& T) {
+ tv_sec = static_cast<uint32_t>(T.tv_sec);
+ tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+ }
+ log_time(uint32_t sec, uint32_t nsec) {
+ tv_sec = sec;
+ tv_nsec = nsec;
+ }
#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
#define __struct_log_time_private_defined
- static const timespec EPOCH;
+ static const timespec EPOCH;
#endif
- log_time()
- {
- }
+ log_time() {
+ }
#ifdef __linux__
- log_time(clockid_t id)
- {
- timespec T;
- clock_gettime(id, &T);
- tv_sec = static_cast<uint32_t>(T.tv_sec);
- tv_nsec = static_cast<uint32_t>(T.tv_nsec);
- }
+ log_time(clockid_t id) {
+ timespec T;
+ clock_gettime(id, &T);
+ tv_sec = static_cast<uint32_t>(T.tv_sec);
+ tv_nsec = static_cast<uint32_t>(T.tv_nsec);
+ }
#endif
- log_time(const char* T)
- {
- const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
- tv_sec = c[0] |
- (static_cast<uint32_t>(c[1]) << 8) |
- (static_cast<uint32_t>(c[2]) << 16) |
- (static_cast<uint32_t>(c[3]) << 24);
- tv_nsec = c[4] |
- (static_cast<uint32_t>(c[5]) << 8) |
- (static_cast<uint32_t>(c[6]) << 16) |
- (static_cast<uint32_t>(c[7]) << 24);
- }
+ log_time(const char* T) {
+ const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
+ tv_sec = c[0] | (static_cast<uint32_t>(c[1]) << 8) |
+ (static_cast<uint32_t>(c[2]) << 16) |
+ (static_cast<uint32_t>(c[3]) << 24);
+ tv_nsec = c[4] | (static_cast<uint32_t>(c[5]) << 8) |
+ (static_cast<uint32_t>(c[6]) << 16) |
+ (static_cast<uint32_t>(c[7]) << 24);
+ }
- /* timespec */
- bool operator== (const timespec& T) const
- {
- return (tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
- }
- bool operator!= (const timespec& T) const
- {
- return !(*this == T);
- }
- bool operator< (const timespec& T) const
- {
- return (tv_sec < static_cast<uint32_t>(T.tv_sec))
- || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator>= (const timespec& T) const
- {
- return !(*this < T);
- }
- bool operator> (const timespec& T) const
- {
- return (tv_sec > static_cast<uint32_t>(T.tv_sec))
- || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
- && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator<= (const timespec& T) const
- {
- return !(*this > T);
- }
+ /* timespec */
+ bool operator==(const timespec& T) const {
+ return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
+ (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
+ }
+ bool operator!=(const timespec& T) const {
+ return !(*this == T);
+ }
+ bool operator<(const timespec& T) const {
+ return (tv_sec < static_cast<uint32_t>(T.tv_sec)) ||
+ ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
+ (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
+ }
+ bool operator>=(const timespec& T) const {
+ return !(*this < T);
+ }
+ bool operator>(const timespec& T) const {
+ return (tv_sec > static_cast<uint32_t>(T.tv_sec)) ||
+ ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
+ (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
+ }
+ bool operator<=(const timespec& T) const {
+ return !(*this > T);
+ }
#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
- log_time operator-= (const timespec& T);
- log_time operator- (const timespec& T) const
- {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+= (const timespec& T);
- log_time operator+ (const timespec& T) const
- {
- log_time local(*this);
- return local += T;
- }
+ log_time operator-=(const timespec& T);
+ log_time operator-(const timespec& T) const {
+ log_time local(*this);
+ return local -= T;
+ }
+ log_time operator+=(const timespec& T);
+ log_time operator+(const timespec& T) const {
+ log_time local(*this);
+ return local += T;
+ }
#endif
- /* log_time */
- bool operator== (const log_time& T) const
- {
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
- }
- bool operator!= (const log_time& T) const
- {
- return !(*this == T);
- }
- bool operator< (const log_time& T) const
- {
- return (tv_sec < T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
- }
- bool operator>= (const log_time& T) const
- {
- return !(*this < T);
- }
- bool operator> (const log_time& T) const
- {
- return (tv_sec > T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
- }
- bool operator<= (const log_time& T) const
- {
- return !(*this > T);
- }
+ /* log_time */
+ bool operator==(const log_time& T) const {
+ return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+ }
+ bool operator!=(const log_time& T) const {
+ return !(*this == T);
+ }
+ bool operator<(const log_time& T) const {
+ return (tv_sec < T.tv_sec) ||
+ ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+ }
+ bool operator>=(const log_time& T) const {
+ return !(*this < T);
+ }
+ bool operator>(const log_time& T) const {
+ return (tv_sec > T.tv_sec) ||
+ ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+ }
+ bool operator<=(const log_time& T) const {
+ return !(*this > T);
+ }
#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
- log_time operator-= (const log_time& T);
- log_time operator- (const log_time& T) const
- {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+= (const log_time& T);
- log_time operator+ (const log_time& T) const
- {
- log_time local(*this);
- return local += T;
- }
+ log_time operator-=(const log_time& T);
+ log_time operator-(const log_time& T) const {
+ log_time local(*this);
+ return local -= T;
+ }
+ log_time operator+=(const log_time& T);
+ log_time operator+(const log_time& T) const {
+ log_time local(*this);
+ return local += T;
+ }
#endif
- uint64_t nsec() const
- {
- return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
- }
+ uint64_t nsec() const {
+ return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
+ }
#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
- static const char default_format[];
+ static const char default_format[];
- /* Add %#q for the fraction of a second to the standard library functions */
- char* strptime(const char* s, const char* format = default_format);
+ /* Add %#q for the fraction of a second to the standard library functions */
+ char* strptime(const char* s, const char* format = default_format);
#endif
} __attribute__((__packed__));
#else
typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
+ uint32_t tv_sec;
+ uint32_t tv_nsec;
} __attribute__((__packed__)) log_time;
#endif
diff --git a/liblog/include/log/log_transport.h b/liblog/include/log/log_transport.h
new file mode 100644
index 0000000..80b30db
--- /dev/null
+++ b/liblog/include/log/log_transport.h
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** This file is dual licensed. It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _LIBS_LOG_TRANSPORT_H
+#define _LIBS_LOG_TRANSPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Logging transports, bit mask to select features. Function returns selection.
+ */
+/* clang-format off */
+#define LOGGER_DEFAULT 0x00
+#define LOGGER_LOGD 0x01
+#define LOGGER_KERNEL 0x02 /* Reserved/Deprecated */
+#define LOGGER_NULL 0x04 /* Does not release resources of other selections */
+#define LOGGER_LOCAL 0x08 /* logs sent to local memory */
+#define LOGGER_STDERR 0x10 /* logs sent to stderr */
+/* clang-format on */
+
+/* Both return the selected transport flag mask, or negative errno */
+int android_set_log_transport(int transport_flag);
+int android_get_log_transport();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_TRANSPORT_H */
diff --git a/liblog/include/log/logprint.h b/liblog/include/log/logprint.h
index 5b99c3c..ca58bc7 100644
--- a/liblog/include/log/logprint.h
+++ b/liblog/include/log/logprint.h
@@ -27,43 +27,43 @@
#endif
typedef enum {
- /* Verbs */
- FORMAT_OFF = 0,
- FORMAT_BRIEF,
- FORMAT_PROCESS,
- FORMAT_TAG,
- FORMAT_THREAD,
- FORMAT_RAW,
- FORMAT_TIME,
- FORMAT_THREADTIME,
- FORMAT_LONG,
- /* Adverbs. The following are modifiers to above format verbs */
- FORMAT_MODIFIER_COLOR, /* converts priority to color */
- FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
- FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
- FORMAT_MODIFIER_YEAR, /* Adds year to date */
- FORMAT_MODIFIER_ZONE, /* Adds zone to date, + UTC */
- FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
- FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
- FORMAT_MODIFIER_UID, /* Adds uid */
- FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
- /* private, undocumented */
- FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
+ /* Verbs */
+ FORMAT_OFF = 0,
+ FORMAT_BRIEF,
+ FORMAT_PROCESS,
+ FORMAT_TAG,
+ FORMAT_THREAD,
+ FORMAT_RAW,
+ FORMAT_TIME,
+ FORMAT_THREADTIME,
+ FORMAT_LONG,
+ /* Adverbs. The following are modifiers to above format verbs */
+ FORMAT_MODIFIER_COLOR, /* converts priority to color */
+ FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
+ FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
+ FORMAT_MODIFIER_YEAR, /* Adds year to date */
+ FORMAT_MODIFIER_ZONE, /* Adds zone to date, + UTC */
+ FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
+ FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
+ FORMAT_MODIFIER_UID, /* Adds uid */
+ FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
+ /* private, undocumented */
+ FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
typedef struct AndroidLogEntry_t {
- time_t tv_sec;
- long tv_nsec;
- android_LogPriority priority;
- int32_t uid;
- int32_t pid;
- int32_t tid;
- const char* tag;
- size_t tagLen;
- size_t messageLen;
- const char* message;
+ time_t tv_sec;
+ long tv_nsec;
+ android_LogPriority priority;
+ int32_t uid;
+ int32_t pid;
+ int32_t tid;
+ const char* tag;
+ size_t tagLen;
+ size_t messageLen;
+ const char* message;
} AndroidLogEntry;
AndroidLogFormat* android_log_format_new();
@@ -72,7 +72,7 @@
/* currently returns 0 if format is a modifier, 1 if not */
int android_log_setPrintFormat(AndroidLogFormat* p_format,
- AndroidLogPrintFormat format);
+ AndroidLogPrintFormat format);
/**
* Returns FORMAT_OFF on invalid string
@@ -90,7 +90,7 @@
*/
int android_log_addFilterRule(AndroidLogFormat* p_format,
- const char* filterExpression);
+ const char* filterExpression);
/**
* filterString: a whitespace-separated set of filter expressions
@@ -103,14 +103,14 @@
*/
int android_log_addFilterString(AndroidLogFormat* p_format,
- const char* filterString);
+ const char* filterString);
/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
-int android_log_shouldPrintLine (
- AndroidLogFormat* p_format, const char* tag, android_LogPriority pri);
+int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
+ android_LogPriority pri);
/**
* Splits a wire-format buffer into an AndroidLogEntry
@@ -129,8 +129,9 @@
* into a string.
*/
int android_log_processBinaryLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry, const EventTagMap* map, char* messageBuf,
- int messageBufLen);
+ AndroidLogEntry* entry,
+ const EventTagMap* map, char* messageBuf,
+ int messageBufLen);
/**
* Formats a log message into a buffer
@@ -140,12 +141,10 @@
* Returns NULL on malloc error
*/
-char* android_log_formatLogLine (
- AndroidLogFormat* p_format,
- char* defaultBuffer,
- size_t defaultBufferSize,
- const AndroidLogEntry* p_line,
- size_t* p_outLength);
+char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
+ size_t defaultBufferSize,
+ const AndroidLogEntry* p_line,
+ size_t* p_outLength);
/**
* Either print or do not print log line, based on filter
@@ -153,10 +152,8 @@
* Assumes single threaded execution
*
*/
-int android_log_printLogLine(
- AndroidLogFormat* p_format,
- int fd,
- const AndroidLogEntry* entry);
+int android_log_printLogLine(AndroidLogFormat* p_format, int fd,
+ const AndroidLogEntry* entry);
#ifdef __cplusplus
}
diff --git a/liblog/include/log/uio.h b/liblog/include/log/uio.h
index 7059da5..a492bae 100644
--- a/liblog/include/log/uio.h
+++ b/liblog/include/log/uio.h
@@ -34,12 +34,12 @@
#include <stddef.h>
struct iovec {
- void* iov_base;
- size_t iov_len;
+ void* iov_base;
+ size_t iov_len;
};
-extern int readv( int fd, struct iovec* vecs, int count );
-extern int writev( int fd, const struct iovec* vecs, int count );
+extern int readv(int fd, struct iovec* vecs, int count);
+extern int writev(int fd, const struct iovec* vecs, int count);
#ifdef __cplusplus
}
@@ -48,4 +48,3 @@
#endif
#endif /* _LIBS_UTILS_UIO_H */
-
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
index 9f81b1f..e3ccfcf 100644
--- a/liblog/include/private/android_logger.h
+++ b/liblog/include/private/android_logger.h
@@ -31,8 +31,8 @@
}
#endif
-#include <log/log_event_list.h>
#include <log/log.h>
+#include <log/log_event_list.h>
#define LOGGER_MAGIC 'l'
@@ -42,46 +42,46 @@
/* Header Structure to pstore */
typedef struct __attribute__((__packed__)) {
- uint8_t magic;
- uint16_t len;
- uint16_t uid;
- uint16_t pid;
+ uint8_t magic;
+ uint16_t len;
+ uint16_t uid;
+ uint16_t pid;
} android_pmsg_log_header_t;
/* Header Structure to logd, and second header for pstore */
typedef struct __attribute__((__packed__)) {
- typeof_log_id_t id;
- uint16_t tid;
- log_time realtime;
+ typeof_log_id_t id;
+ uint16_t tid;
+ log_time realtime;
} android_log_header_t;
/* Event Header Structure to logd */
typedef struct __attribute__((__packed__)) {
- int32_t tag; // Little Endian Order
+ int32_t tag; // Little Endian Order
} android_event_header_t;
/* Event payload EVENT_TYPE_INT */
typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_INT
- int32_t data; // Little Endian Order
+ int8_t type; // EVENT_TYPE_INT
+ int32_t data; // Little Endian Order
} android_event_int_t;
/* Event with single EVENT_TYPE_INT */
typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_int_t payload;
+ android_event_header_t header;
+ android_event_int_t payload;
} android_log_event_int_t;
/* Event payload EVENT_TYPE_LONG */
typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_LONG
- int64_t data; // Little Endian Order
+ int8_t type; // EVENT_TYPE_LONG
+ int64_t data; // Little Endian Order
} android_event_long_t;
/* Event with single EVENT_TYPE_LONG */
typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_long_t payload;
+ android_event_header_t header;
+ android_event_long_t payload;
} android_log_event_long_t;
/*
@@ -97,41 +97,39 @@
*/
typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
+ int8_t type; // EVENT_TYPE_STRING;
+ int32_t length; // Little Endian Order
+ char data[];
} android_event_string_t;
/* Event with single EVENT_TYPE_STRING */
typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
+ android_event_header_t header;
+ int8_t type; // EVENT_TYPE_STRING;
+ int32_t length; // Little Endian Order
+ char data[];
} android_log_event_string_t;
#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
-#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
+#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
-ssize_t __android_log_pmsg_file_write(
- log_id_t logId,
- char prio,
- const char* filename,
- const char* buf, size_t len);
+ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio,
+ const char* filename, const char* buf,
+ size_t len);
-#define LOG_ID_ANY ((log_id_t)-1)
+#define LOG_ID_ANY ((log_id_t)-1)
#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
-typedef ssize_t (*__android_log_pmsg_file_read_fn)(
- log_id_t logId,
- char prio,
- const char* filename,
- const char* buf, size_t len, void* arg);
+typedef ssize_t (*__android_log_pmsg_file_read_fn)(log_id_t logId, char prio,
+ const char* filename,
+ const char* buf, size_t len,
+ void* arg);
-ssize_t __android_log_pmsg_file_read(
- log_id_t logId, char prio, const char* prefix,
- __android_log_pmsg_file_read_fn fn, void* arg);
+ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio,
+ const char* prefix,
+ __android_log_pmsg_file_read_fn fn,
+ void* arg);
int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
int __android_log_security_bswrite(int32_t tag, const char* payload);
@@ -140,14 +138,15 @@
int __android_log_is_debuggable();
#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
-#define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */
-#define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */
-#define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */
-#define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */
-#define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */
+#define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */
+#define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */
+#define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */
+#define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */
+#define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */
bool __android_logger_property_get_bool(const char* key, int flag);
-#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform */
+#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform \
+ */
#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
unsigned long __android_logger_get_buffer_size(log_id_t logId);
@@ -163,24 +162,26 @@
/* android_log_context C++ helpers */
extern "C++" {
class __android_log_event_list : public android_log_event_list {
- __android_log_event_list(const android_log_event_list&) = delete;
- void operator =(const __android_log_event_list&) = delete;
+ __android_log_event_list(const android_log_event_list&) = delete;
+ void operator=(const __android_log_event_list&) = delete;
-public:
- explicit __android_log_event_list(int tag) : android_log_event_list(tag) { }
- explicit __android_log_event_list(log_msg& log_msg) : android_log_event_list(log_msg) { }
+ public:
+ explicit __android_log_event_list(int tag) : android_log_event_list(tag) {
+ }
+ explicit __android_log_event_list(log_msg& log_msg)
+ : android_log_event_list(log_msg) {
+ }
#if defined(_USING_LIBCXX)
- operator std::string() {
- if (ret) return std::string("");
- const char* cp = NULL;
- ssize_t len = android_log_write_list_buffer(ctx, &cp);
- if (len < 0) ret = len;
- if (!cp || (len <= 0)) return std::string("");
- return std::string(cp, len);
- }
+ operator std::string() {
+ if (ret) return std::string("");
+ const char* cp = NULL;
+ ssize_t len = android_log_write_list_buffer(ctx, &cp);
+ if (len < 0) ret = len;
+ if (!cp || (len <= 0)) return std::string("");
+ return std::string(cp, len);
+ }
#endif
-
};
}
#endif
diff --git a/liblog/local_logger.c b/liblog/local_logger.c
new file mode 100644
index 0000000..522867d
--- /dev/null
+++ b/liblog/local_logger.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#if !defined(__MINGW32__)
+#include <pwd.h>
+#endif
+#include <log/uio.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/list.h> /* template, no library dependency */
+#include <log/log_transport.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+#include <system/thread_defs.h>
+
+#include "config_read.h"
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static const char baseServiceName[] = "android.logd";
+
+static int writeToLocalInit();
+static int writeToLocalAvailable(log_id_t logId);
+static void writeToLocalReset();
+static int writeToLocalWrite(log_id_t logId, struct timespec* ts,
+ struct iovec* vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write localLoggerWrite = {
+ .node = { &localLoggerWrite.node, &localLoggerWrite.node },
+ .context.priv = NULL,
+ .name = "local",
+ .available = writeToLocalAvailable,
+ .open = writeToLocalInit,
+ .close = writeToLocalReset,
+ .write = writeToLocalWrite,
+};
+
+static int writeToLocalVersion(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static int writeToLocalRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg);
+static int writeToLocalPoll(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
+static void writeToLocalClose(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
+static int writeToLocalClear(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static ssize_t writeToLocalGetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static ssize_t writeToLocalSetSize(
+ struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused, size_t size);
+static ssize_t writeToLocalGetReadbleSize(
+ struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+
+struct android_log_transport_read localLoggerRead = {
+ .node = { &localLoggerRead.node, &localLoggerRead.node },
+ .name = "local",
+ .available = writeToLocalAvailable,
+ .version = writeToLocalVersion,
+ .read = writeToLocalRead,
+ .poll = writeToLocalPoll,
+ .close = writeToLocalClose,
+ .clear = writeToLocalClear,
+ .getSize = writeToLocalGetSize,
+ .setSize = writeToLocalSetSize,
+ .getReadableSize = writeToLocalGetReadbleSize,
+ .getPrune = NULL,
+ .setPrune = NULL,
+ .getStats = NULL,
+};
+
+struct LogBufferElement {
+ struct listnode node;
+ log_id_t logId;
+ pid_t tid;
+ log_time timestamp;
+ unsigned short len;
+ char msg[];
+};
+
+static const size_t MAX_SIZE_DEFAULT = 32768;
+
+/*
+ * Number of log buffers we support with the following assumption:
+ * . . .
+ * LOG_ID_SECURITY = 5, // security logs go to the system logs only
+ * LOG_ID_KERNEL = 6, // place last, third-parties can not use it
+ * LOG_ID_MAX
+ * } log_id_t;
+ *
+ * Confirm the following should <log/log_id.h> be adjusted in the future.
+ */
+#define NUMBER_OF_LOG_BUFFERS \
+ ((LOG_ID_SECURITY == (LOG_ID_MAX - 2)) ? LOG_ID_SECURITY : LOG_ID_KERNEL)
+#define BLOCK_LOG_BUFFERS(id) \
+ (((id) == LOG_ID_SECURITY) || ((id) == LOG_ID_KERNEL))
+
+static struct LogBuffer {
+ struct listnode head;
+ pthread_rwlock_t listLock;
+ char* serviceName; /* Also indicates ready by having a value */
+ /* Order and proximity important for memset */
+ size_t number[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
+ size_t size[NUMBER_OF_LOG_BUFFERS]; /* clear memset */
+ size_t totalSize[NUMBER_OF_LOG_BUFFERS]; /* init memset */
+ size_t maxSize[NUMBER_OF_LOG_BUFFERS]; /* init MAX_SIZE_DEFAULT */
+ struct listnode* last[NUMBER_OF_LOG_BUFFERS]; /* init &head */
+} logbuf = {
+ .head = { &logbuf.head, &logbuf.head }, .listLock = PTHREAD_RWLOCK_INITIALIZER,
+};
+
+static void LogBufferInit(struct LogBuffer* log) {
+ size_t i;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ list_init(&log->head);
+ memset(log->number, 0,
+ sizeof(log->number) + sizeof(log->size) + sizeof(log->totalSize));
+ for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+ log->maxSize[i] = MAX_SIZE_DEFAULT;
+ log->last[i] = &log->head;
+ }
+#ifdef __BIONIC__
+ asprintf(&log->serviceName, "%s@%d:%d", baseServiceName, __android_log_uid(),
+ getpid());
+#else
+ char buffer[sizeof(baseServiceName) + 1 + 5 + 1 + 5 + 8];
+ snprintf(buffer, sizeof(buffer), "%s@%d:%d", baseServiceName,
+ __android_log_uid(), getpid());
+ log->serviceName = strdup(buffer);
+#endif
+ pthread_rwlock_unlock(&log->listLock);
+}
+
+static void LogBufferClear(struct LogBuffer* log) {
+ size_t i;
+ struct listnode* node;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ memset(log->number, 0, sizeof(log->number) + sizeof(log->size));
+ for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+ log->last[i] = &log->head;
+ }
+ while ((node = list_head(&log->head)) != &log->head) {
+ struct LogBufferElement* element;
+
+ element = node_to_item(node, struct LogBufferElement, node);
+ list_remove(node);
+ free(element);
+ }
+ pthread_rwlock_unlock(&log->listLock);
+}
+
+static inline void LogBufferFree(struct LogBuffer* log) {
+ pthread_rwlock_wrlock(&log->listLock);
+ free(log->serviceName);
+ log->serviceName = NULL;
+ pthread_rwlock_unlock(&log->listLock);
+ LogBufferClear(log);
+}
+
+static int LogBufferLog(struct LogBuffer* log,
+ struct LogBufferElement* element) {
+ log_id_t logId = element->logId;
+
+ pthread_rwlock_wrlock(&log->listLock);
+ log->number[logId]++;
+ log->size[logId] += element->len;
+ log->totalSize[logId] += element->len;
+ /* prune entry(s) until enough space is available */
+ if (log->last[logId] == &log->head) {
+ log->last[logId] = list_tail(&log->head);
+ }
+ while (log->size[logId] > log->maxSize[logId]) {
+ struct listnode* node = log->last[logId];
+ struct LogBufferElement* e;
+ struct android_log_logger_list* logger_list;
+
+ e = node_to_item(node, struct LogBufferElement, node);
+ log->number[logId]--;
+ log->size[logId] -= e->len;
+ logger_list_rdlock();
+ logger_list_for_each(logger_list) {
+ struct android_log_transport_context* transp;
+
+ transport_context_for_each(transp, logger_list) {
+ if ((transp->transport == &localLoggerRead) &&
+ (transp->context.node == node)) {
+ if (node == &log->head) {
+ transp->context.node = &log->head;
+ } else {
+ transp->context.node = node->next;
+ }
+ }
+ }
+ }
+ logger_list_unlock();
+ if (node != &log->head) {
+ log->last[logId] = node->prev;
+ }
+ list_remove(node);
+ free(e);
+ }
+ /* add entry to list */
+ list_add_head(&log->head, &element->node);
+ /* ToDo: wake up all readers */
+ pthread_rwlock_unlock(&log->listLock);
+
+ return element->len;
+}
+
+/*
+ * return zero if permitted to log directly to logd,
+ * return 1 if binder server started and
+ * return negative error number if failed to start binder server.
+ */
+static int writeToLocalInit() {
+ pthread_attr_t attr;
+ struct LogBuffer* log;
+
+ if (writeToLocalAvailable(LOG_ID_MAIN) < 0) {
+ return -EPERM;
+ }
+
+ log = &logbuf;
+ if (!log->serviceName) {
+ LogBufferInit(log);
+ }
+
+ if (!log->serviceName) {
+ LogBufferFree(log);
+ return -ENOMEM;
+ }
+
+ return EPERM; /* successful local-only logging */
+}
+
+static void writeToLocalReset() {
+ LogBufferFree(&logbuf);
+}
+
+static int writeToLocalAvailable(log_id_t logId) {
+#if !defined(__MINGW32__)
+ uid_t uid;
+#endif
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+/* Android hard coded permitted, system goes to logd */
+#if !defined(__MINGW32__)
+ if (__android_log_transport == LOGGER_DEFAULT) {
+ uid = __android_log_uid();
+ if ((uid < AID_APP) && (getpwuid(uid) != NULL)) {
+ return -EPERM;
+ }
+ }
+#endif
+
+ /* ToDo: Ask package manager for LOGD permissions */
+ /* Assume we do _not_ have permissions to go to LOGD, so must go local */
+ return 0;
+}
+
+static int writeToLocalWrite(log_id_t logId, struct timespec* ts,
+ struct iovec* vec, size_t nr) {
+ size_t len, i;
+ struct LogBufferElement* element;
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+ len = 0;
+ for (i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+
+ if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ len = LOGGER_ENTRY_MAX_PAYLOAD;
+ }
+ element = (struct LogBufferElement*)calloc(
+ 1, sizeof(struct LogBufferElement) + len + 1);
+ if (!element) {
+ return errno ? -errno : -ENOMEM;
+ }
+ element->timestamp.tv_sec = ts->tv_sec;
+ element->timestamp.tv_nsec = ts->tv_nsec;
+#ifdef __BIONIC__
+ element->tid = gettid();
+#else
+ element->tid = getpid();
+#endif
+ element->logId = logId;
+ element->len = len;
+
+ char* cp = element->msg;
+ for (i = 0; i < nr; ++i) {
+ size_t iov_len = vec[i].iov_len;
+ if (iov_len > len) {
+ iov_len = len;
+ }
+ memcpy(cp, vec[i].iov_base, iov_len);
+ len -= iov_len;
+ if (len == 0) {
+ break;
+ }
+ cp += iov_len;
+ }
+
+ return LogBufferLog(&logbuf, element);
+}
+
+static int writeToLocalVersion(struct android_log_logger* logger __unused,
+ struct android_log_transport_context* transp
+ __unused) {
+ return 3;
+}
+
+/* within reader lock, serviceName already validated */
+static struct listnode* writeToLocalNode(
+ struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp) {
+ struct listnode* node;
+ unsigned logMask;
+ unsigned int tail;
+
+ node = transp->context.node;
+ if (node) {
+ return node;
+ }
+
+ if (!logger_list->tail) {
+ return transp->context.node = &logbuf.head;
+ }
+
+ logMask = transp->logMask;
+ tail = logger_list->tail;
+
+ for (node = list_head(&logbuf.head); node != &logbuf.head; node = node->next) {
+ struct LogBufferElement* element;
+ log_id_t logId;
+
+ element = node_to_item(node, struct LogBufferElement, node);
+ logId = element->logId;
+
+ if ((logMask & (1 << logId)) && !--tail) {
+ node = node->next;
+ break;
+ }
+ }
+ return transp->context.node = node;
+}
+
+static int writeToLocalRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg) {
+ int ret;
+ struct listnode* node;
+ unsigned logMask;
+
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ if (!logbuf.serviceName) {
+ pthread_rwlock_unlock(&logbuf.listLock);
+ return (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+ }
+
+ logMask = transp->logMask;
+
+ node = writeToLocalNode(logger_list, transp);
+
+ ret = 0;
+
+ while (node != list_head(&logbuf.head)) {
+ struct LogBufferElement* element;
+ log_id_t logId;
+
+ node = node->prev;
+ element = node_to_item(node, struct LogBufferElement, node);
+ logId = element->logId;
+
+ if (logMask & (1 << logId)) {
+ ret = log_msg->entry_v3.len = element->len;
+ log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+ log_msg->entry_v3.pid = getpid();
+ log_msg->entry_v3.tid = element->tid;
+ log_msg->entry_v3.sec = element->timestamp.tv_sec;
+ log_msg->entry_v3.nsec = element->timestamp.tv_nsec;
+ log_msg->entry_v3.lid = logId;
+ memcpy(log_msg->entry_v3.msg, element->msg, ret);
+ ret += log_msg->entry_v3.hdr_size;
+ break;
+ }
+ }
+
+ transp->context.node = node;
+
+ /* ToDo: if blocking, and no entry, put reader to sleep */
+ pthread_rwlock_unlock(&logbuf.listLock);
+ return ret;
+}
+
+static int writeToLocalPoll(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp) {
+ int ret = (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+
+ pthread_rwlock_rdlock(&logbuf.listLock);
+
+ if (logbuf.serviceName) {
+ unsigned logMask = transp->logMask;
+ struct listnode* node = writeToLocalNode(logger_list, transp);
+
+ ret = (node != list_head(&logbuf.head));
+ if (ret) {
+ do {
+ ret = !!(logMask &
+ (1 << (node_to_item(node->prev, struct LogBufferElement, node))
+ ->logId));
+ } while (!ret && ((node = node->prev) != list_head(&logbuf.head)));
+ }
+
+ transp->context.node = node;
+ }
+
+ pthread_rwlock_unlock(&logbuf.listLock);
+
+ return ret;
+}
+
+static void writeToLocalClose(struct android_log_logger_list* logger_list
+ __unused,
+ struct android_log_transport_context* transp) {
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ transp->context.node = list_head(&logbuf.head);
+ pthread_rwlock_unlock(&logbuf.listLock);
+}
+
+static int writeToLocalClear(struct android_log_logger* logger,
+ struct android_log_transport_context* unused
+ __unused) {
+ log_id_t logId = logger->logId;
+ struct listnode *node, *n;
+
+ if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+ return -EINVAL;
+ }
+
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ logbuf.number[logId] = 0;
+ logbuf.last[logId] = &logbuf.head;
+ list_for_each_safe(node, n, &logbuf.head) {
+ struct LogBufferElement* element;
+ element = node_to_item(node, struct LogBufferElement, node);
+
+ if (logId == element->logId) {
+ struct android_log_logger_list* logger_list;
+
+ logger_list_rdlock();
+ logger_list_for_each(logger_list) {
+ struct android_log_transport_context* transp;
+
+ transport_context_for_each(transp, logger_list) {
+ if ((transp->transport == &localLoggerRead) &&
+ (transp->context.node == node)) {
+ transp->context.node = node->next;
+ }
+ }
+ }
+ logger_list_unlock();
+ list_remove(node);
+ free(element);
+ }
+ }
+
+ pthread_rwlock_unlock(&logbuf.listLock);
+
+ return 0;
+}
+
+static ssize_t writeToLocalGetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp
+ __unused) {
+ ssize_t ret = -EINVAL;
+ log_id_t logId = logger->logId;
+
+ if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ ret = logbuf.maxSize[logId];
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+
+ return ret;
+}
+
+static ssize_t writeToLocalSetSize(
+ struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused, size_t size) {
+ ssize_t ret = -EINVAL;
+
+ if ((size > LOGGER_ENTRY_MAX_LEN) || (size < (4 * 1024 * 1024))) {
+ log_id_t logId = logger->logId;
+ if ((logId < NUMBER_OF_LOG_BUFFERS) || !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_wrlock(&logbuf.listLock);
+ ret = logbuf.maxSize[logId] = size;
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t writeToLocalGetReadbleSize(
+ struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused) {
+ ssize_t ret = -EINVAL;
+ log_id_t logId = logger->logId;
+
+ if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+ pthread_rwlock_rdlock(&logbuf.listLock);
+ ret = logbuf.serviceName ? (ssize_t)logbuf.size[logId] : -EBADF;
+ pthread_rwlock_unlock(&logbuf.listLock);
+ }
+
+ return ret;
+}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index 9ac1d30..59ea5ef 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -30,270 +30,266 @@
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
typedef struct {
- uint32_t tag;
- unsigned pos; /* Read/write position into buffer */
- unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
- unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
- unsigned list_nest_depth;
- unsigned len; /* Length or raw buffer. */
- bool overflow;
- bool list_stop; /* next call decrement list_nest_depth and issue a stop */
- enum {
- kAndroidLoggerRead = 1,
- kAndroidLoggerWrite = 2,
- } read_write_flag;
- uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
+ uint32_t tag;
+ unsigned pos; /* Read/write position into buffer */
+ unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
+ unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
+ unsigned list_nest_depth;
+ unsigned len; /* Length or raw buffer. */
+ bool overflow;
+ bool list_stop; /* next call decrement list_nest_depth and issue a stop */
+ enum {
+ kAndroidLoggerRead = 1,
+ kAndroidLoggerWrite = 2,
+ } read_write_flag;
+ uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
} android_log_context_internal;
LIBLOG_ABI_PUBLIC android_log_context create_android_logger(uint32_t tag) {
- size_t needed, i;
- android_log_context_internal *context;
+ size_t needed, i;
+ android_log_context_internal* context;
- context = calloc(1, sizeof(android_log_context_internal));
- if (!context) {
- return NULL;
- }
- context->tag = tag;
- context->read_write_flag = kAndroidLoggerWrite;
- needed = sizeof(uint8_t) + sizeof(uint8_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- }
- /* Everything is a list */
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->list[0] = context->pos + 1;
- context->pos += needed;
+ context = calloc(1, sizeof(android_log_context_internal));
+ if (!context) {
+ return NULL;
+ }
+ context->tag = tag;
+ context->read_write_flag = kAndroidLoggerWrite;
+ needed = sizeof(uint8_t) + sizeof(uint8_t);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ }
+ /* Everything is a list */
+ context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+ context->list[0] = context->pos + 1;
+ context->pos += needed;
- return (android_log_context)context;
+ return (android_log_context)context;
}
-LIBLOG_ABI_PUBLIC android_log_context create_android_log_parser(
- const char *msg,
- size_t len) {
- android_log_context_internal *context;
- size_t i;
+LIBLOG_ABI_PUBLIC android_log_context create_android_log_parser(const char* msg,
+ size_t len) {
+ android_log_context_internal* context;
+ size_t i;
- context = calloc(1, sizeof(android_log_context_internal));
- if (!context) {
- return NULL;
- }
- len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
- context->len = len;
- memcpy(context->storage, msg, len);
- context->read_write_flag = kAndroidLoggerRead;
+ context = calloc(1, sizeof(android_log_context_internal));
+ if (!context) {
+ return NULL;
+ }
+ len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
+ context->len = len;
+ memcpy(context->storage, msg, len);
+ context->read_write_flag = kAndroidLoggerRead;
- return (android_log_context)context;
+ return (android_log_context)context;
}
-LIBLOG_ABI_PUBLIC int android_log_destroy(android_log_context *ctx) {
- android_log_context_internal *context;
+LIBLOG_ABI_PUBLIC int android_log_destroy(android_log_context* ctx) {
+ android_log_context_internal* context;
- context = (android_log_context_internal *)*ctx;
- if (!context) {
- return -EBADF;
- }
- memset(context, 0, sizeof(*context));
- free(context);
- *ctx = NULL;
- return 0;
+ context = (android_log_context_internal*)*ctx;
+ if (!context) {
+ return -EBADF;
+ }
+ memset(context, 0, sizeof(*context));
+ free(context);
+ *ctx = NULL;
+ return 0;
}
LIBLOG_ABI_PUBLIC int android_log_write_list_begin(android_log_context ctx) {
- size_t needed;
- android_log_context_internal *context;
+ size_t needed;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context ||
- (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- needed = sizeof(uint8_t) + sizeof(uint8_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- context->list_nest_depth++;
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->overflow) {
- return -EIO;
- }
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->storage[context->pos + 1] = 0;
- context->list[context->list_nest_depth] = context->pos + 1;
- context->count[context->list_nest_depth] = 0;
- context->pos += needed;
- return 0;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ needed = sizeof(uint8_t) + sizeof(uint8_t);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->list_nest_depth++;
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+ context->storage[context->pos + 1] = 0;
+ context->list[context->list_nest_depth] = context->pos + 1;
+ context->count[context->list_nest_depth] = 0;
+ context->pos += needed;
+ return 0;
}
-static inline void copy4LE(uint8_t *buf, uint32_t val)
-{
- buf[0] = val & 0xFF;
- buf[1] = (val >> 8) & 0xFF;
- buf[2] = (val >> 16) & 0xFF;
- buf[3] = (val >> 24) & 0xFF;
+static inline void copy4LE(uint8_t* buf, uint32_t val) {
+ buf[0] = val & 0xFF;
+ buf[1] = (val >> 8) & 0xFF;
+ buf[2] = (val >> 16) & 0xFF;
+ buf[3] = (val >> 24) & 0xFF;
}
LIBLOG_ABI_PUBLIC int android_log_write_int32(android_log_context ctx,
int32_t value) {
- size_t needed;
- android_log_context_internal *context;
+ size_t needed;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- needed = sizeof(uint8_t) + sizeof(value);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- context->storage[context->pos + 0] = EVENT_TYPE_INT;
- copy4LE(&context->storage[context->pos + 1], value);
- context->pos += needed;
- return 0;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(value);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_INT;
+ copy4LE(&context->storage[context->pos + 1], value);
+ context->pos += needed;
+ return 0;
}
-static inline void copy8LE(uint8_t *buf, uint64_t val)
-{
- buf[0] = val & 0xFF;
- buf[1] = (val >> 8) & 0xFF;
- buf[2] = (val >> 16) & 0xFF;
- buf[3] = (val >> 24) & 0xFF;
- buf[4] = (val >> 32) & 0xFF;
- buf[5] = (val >> 40) & 0xFF;
- buf[6] = (val >> 48) & 0xFF;
- buf[7] = (val >> 56) & 0xFF;
+static inline void copy8LE(uint8_t* buf, uint64_t val) {
+ buf[0] = val & 0xFF;
+ buf[1] = (val >> 8) & 0xFF;
+ buf[2] = (val >> 16) & 0xFF;
+ buf[3] = (val >> 24) & 0xFF;
+ buf[4] = (val >> 32) & 0xFF;
+ buf[5] = (val >> 40) & 0xFF;
+ buf[6] = (val >> 48) & 0xFF;
+ buf[7] = (val >> 56) & 0xFF;
}
LIBLOG_ABI_PUBLIC int android_log_write_int64(android_log_context ctx,
int64_t value) {
- size_t needed;
- android_log_context_internal *context;
+ size_t needed;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- needed = sizeof(uint8_t) + sizeof(value);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- context->storage[context->pos + 0] = EVENT_TYPE_LONG;
- copy8LE(&context->storage[context->pos + 1], value);
- context->pos += needed;
- return 0;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(value);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_LONG;
+ copy8LE(&context->storage[context->pos + 1], value);
+ context->pos += needed;
+ return 0;
}
LIBLOG_ABI_PUBLIC int android_log_write_string8_len(android_log_context ctx,
- const char *value,
+ const char* value,
size_t maxlen) {
- size_t needed;
- ssize_t len;
- android_log_context_internal *context;
+ size_t needed;
+ ssize_t len;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ if (!value) {
+ value = "";
+ }
+ len = strnlen(value, maxlen);
+ needed = sizeof(uint8_t) + sizeof(int32_t) + len;
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ /* Truncate string for delivery */
+ len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
+ if (len <= 0) {
+ context->overflow = true;
+ return -EIO;
}
- if (context->overflow) {
- return -EIO;
- }
- if (!value) {
- value = "";
- }
- len = strnlen(value, maxlen);
- needed = sizeof(uint8_t) + sizeof(int32_t) + len;
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- /* Truncate string for delivery */
- len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
- if (len <= 0) {
- context->overflow = true;
- return -EIO;
- }
- }
- context->count[context->list_nest_depth]++;
- context->storage[context->pos + 0] = EVENT_TYPE_STRING;
- copy4LE(&context->storage[context->pos + 1], len);
- if (len) {
- memcpy(&context->storage[context->pos + 5], value, len);
- }
- context->pos += needed;
- return len;
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_STRING;
+ copy4LE(&context->storage[context->pos + 1], len);
+ if (len) {
+ memcpy(&context->storage[context->pos + 5], value, len);
+ }
+ context->pos += needed;
+ return len;
}
LIBLOG_ABI_PUBLIC int android_log_write_string8(android_log_context ctx,
- const char *value) {
- return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
+ const char* value) {
+ return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
}
LIBLOG_ABI_PUBLIC int android_log_write_float32(android_log_context ctx,
float value) {
- size_t needed;
- uint32_t ivalue;
- android_log_context_internal *context;
+ size_t needed;
+ uint32_t ivalue;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- needed = sizeof(uint8_t) + sizeof(ivalue);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- ivalue = *(uint32_t *)&value;
- context->count[context->list_nest_depth]++;
- context->storage[context->pos + 0] = EVENT_TYPE_FLOAT;
- copy4LE(&context->storage[context->pos + 1], ivalue);
- context->pos += needed;
- return 0;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(ivalue);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ ivalue = *(uint32_t*)&value;
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_FLOAT;
+ copy4LE(&context->storage[context->pos + 1], ivalue);
+ context->pos += needed;
+ return 0;
}
LIBLOG_ABI_PUBLIC int android_log_write_list_end(android_log_context ctx) {
- android_log_context_internal *context;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- context->list_nest_depth--;
- return -EOVERFLOW;
- }
- if (!context->list_nest_depth) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->list[context->list_nest_depth] <= 0) {
- context->list_nest_depth--;
- context->overflow = true;
- return -EOVERFLOW;
- }
- context->storage[context->list[context->list_nest_depth]] =
- context->count[context->list_nest_depth];
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
context->list_nest_depth--;
- return 0;
+ return -EOVERFLOW;
+ }
+ if (!context->list_nest_depth) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ if (context->list[context->list_nest_depth] <= 0) {
+ context->list_nest_depth--;
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ context->storage[context->list[context->list_nest_depth]] =
+ context->count[context->list_nest_depth];
+ context->list_nest_depth--;
+ return 0;
}
/*
@@ -301,86 +297,84 @@
*/
LIBLOG_ABI_PUBLIC int android_log_write_list(android_log_context ctx,
log_id_t id) {
- android_log_context_internal *context;
- const char *msg;
- ssize_t len;
+ android_log_context_internal* context;
+ const char* msg;
+ ssize_t len;
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
- return -EINVAL;
- }
+ if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
+ return -EINVAL;
+ }
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth) {
+ return -EIO;
+ }
+ /* NB: if there was overflow, then log is truncated. Nothing reported */
+ context->storage[1] = context->count[0];
+ len = context->len = context->pos;
+ msg = (const char*)context->storage;
+ /* it's not a list */
+ if (context->count[0] <= 1) {
+ len -= sizeof(uint8_t) + sizeof(uint8_t);
+ if (len < 0) {
+ len = 0;
}
- if (context->list_nest_depth) {
- return -EIO;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char *)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- return (id == LOG_ID_EVENTS) ?
- __android_log_bwrite(context->tag, msg, len) :
- __android_log_security_bwrite(context->tag, msg, len);
+ msg += sizeof(uint8_t) + sizeof(uint8_t);
+ }
+ return (id == LOG_ID_EVENTS)
+ ? __android_log_bwrite(context->tag, msg, len)
+ : __android_log_security_bwrite(context->tag, msg, len);
}
LIBLOG_ABI_PRIVATE int android_log_write_list_buffer(android_log_context ctx,
- const char **buffer) {
- android_log_context_internal *context;
- const char *msg;
- ssize_t len;
+ const char** buffer) {
+ android_log_context_internal* context;
+ const char* msg;
+ ssize_t len;
- context = (android_log_context_internal *)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
+ context = (android_log_context_internal*)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth) {
+ return -EIO;
+ }
+ if (buffer == NULL) {
+ return -EFAULT;
+ }
+ /* NB: if there was overflow, then log is truncated. Nothing reported */
+ context->storage[1] = context->count[0];
+ len = context->len = context->pos;
+ msg = (const char*)context->storage;
+ /* it's not a list */
+ if (context->count[0] <= 1) {
+ len -= sizeof(uint8_t) + sizeof(uint8_t);
+ if (len < 0) {
+ len = 0;
}
- if (context->list_nest_depth) {
- return -EIO;
- }
- if (buffer == NULL) {
- return -EFAULT;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char *)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- *buffer = msg;
- return len;
+ msg += sizeof(uint8_t) + sizeof(uint8_t);
+ }
+ *buffer = msg;
+ return len;
}
/*
* Extract a 4-byte value from a byte stream.
*/
-static inline uint32_t get4LE(const uint8_t* src)
-{
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+static inline uint32_t get4LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
/*
* Extract an 8-byte value from a byte stream.
*/
-static inline uint64_t get8LE(const uint8_t* src)
-{
- uint32_t low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
- uint32_t high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
- return ((uint64_t) high << 32) | (uint64_t) low;
+static inline uint64_t get8LE(const uint8_t* src) {
+ uint32_t low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ uint32_t high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+ return ((uint64_t)high << 32) | (uint64_t)low;
}
/*
@@ -391,181 +385,181 @@
* (although it won't crash).
*/
static android_log_list_element android_log_read_next_internal(
- android_log_context ctx, int peek) {
- android_log_list_element elem;
- unsigned pos;
- android_log_context_internal *context;
+ android_log_context ctx, int peek) {
+ android_log_list_element elem;
+ unsigned pos;
+ android_log_context_internal* context;
- context = (android_log_context_internal *)ctx;
+ context = (android_log_context_internal*)ctx;
- memset(&elem, 0, sizeof(elem));
+ memset(&elem, 0, sizeof(elem));
- /* Nothing to parse from this context, so return complete. */
- if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
- (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
- (context->count[context->list_nest_depth] >=
- (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
- elem.type = EVENT_TYPE_UNKNOWN;
- if (context &&
- (context->list_stop ||
- ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
- !context->count[context->list_nest_depth]))) {
- elem.type = EVENT_TYPE_LIST_STOP;
+ /* Nothing to parse from this context, so return complete. */
+ if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
+ (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
+ (context->count[context->list_nest_depth] >=
+ (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ if (context && (context->list_stop ||
+ ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
+ !context->count[context->list_nest_depth]))) {
+ elem.type = EVENT_TYPE_LIST_STOP;
+ }
+ elem.complete = true;
+ return elem;
+ }
+
+ /*
+ * Use a different variable to update the position in case this
+ * operation is a "peek".
+ */
+ pos = context->pos;
+ if (context->list_stop) {
+ elem.type = EVENT_TYPE_LIST_STOP;
+ elem.complete = !context->count[0] &&
+ (!context->list_nest_depth ||
+ ((context->list_nest_depth == 1) && !context->count[1]));
+ if (!peek) {
+ /* Suck in superfluous stop */
+ if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
+ context->pos = pos + 1;
+ }
+ if (context->list_nest_depth) {
+ --context->list_nest_depth;
+ if (context->count[context->list_nest_depth]) {
+ context->list_stop = false;
}
- elem.complete = true;
- return elem;
+ } else {
+ context->list_stop = false;
+ }
}
+ return elem;
+ }
+ if ((pos + 1) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
+ return elem;
+ }
- /*
- * Use a different variable to update the position in case this
- * operation is a "peek".
- */
- pos = context->pos;
- if (context->list_stop) {
- elem.type = EVENT_TYPE_LIST_STOP;
- elem.complete = !context->count[0] && (!context->list_nest_depth ||
- ((context->list_nest_depth == 1) && !context->count[1]));
- if (!peek) {
- /* Suck in superfluous stop */
- if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
- context->pos = pos + 1;
- }
- if (context->list_nest_depth) {
- --context->list_nest_depth;
- if (context->count[context->list_nest_depth]) {
- context->list_stop = false;
- }
- } else {
- context->list_stop = false;
- }
- }
- return elem;
- }
- if ((pos + 1) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
-
- elem.type = context->storage[pos++];
- switch ((int)elem.type) {
+ elem.type = context->storage[pos++];
+ switch ((int)elem.type) {
case EVENT_TYPE_FLOAT:
- /* Rely on union to translate elem.data.int32 into elem.data.float32 */
- /* FALLTHRU */
+ /* Rely on union to translate elem.data.int32 into elem.data.float32 */
+ /* FALLTHRU */
case EVENT_TYPE_INT:
- elem.len = sizeof(int32_t);
- if ((pos + elem.len) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- elem.data.int32 = get4LE(&context->storage[pos]);
- /* common tangeable object suffix */
- pos += elem.len;
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
+ elem.len = sizeof(int32_t);
+ if ((pos + elem.len) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
return elem;
+ }
+ elem.data.int32 = get4LE(&context->storage[pos]);
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
case EVENT_TYPE_LONG:
- elem.len = sizeof(int64_t);
- if ((pos + elem.len) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- elem.data.int64 = get8LE(&context->storage[pos]);
- /* common tangeable object suffix */
- pos += elem.len;
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
+ elem.len = sizeof(int64_t);
+ if ((pos + elem.len) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
return elem;
+ }
+ elem.data.int64 = get8LE(&context->storage[pos]);
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
case EVENT_TYPE_STRING:
- if ((pos + sizeof(int32_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- elem.len = get4LE(&context->storage[pos]);
- pos += sizeof(int32_t);
- if ((pos + elem.len) > context->len) {
- elem.len = context->len - pos; /* truncate string */
- elem.complete = true;
- if (!elem.len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- }
- elem.data.string = (char *)&context->storage[pos];
- /* common tangeable object suffix */
- pos += elem.len;
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
+ if ((pos + sizeof(int32_t)) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
return elem;
+ }
+ elem.len = get4LE(&context->storage[pos]);
+ pos += sizeof(int32_t);
+ if ((pos + elem.len) > context->len) {
+ elem.len = context->len - pos; /* truncate string */
+ elem.complete = true;
+ if (!elem.len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
+ }
+ elem.data.string = (char*)&context->storage[pos];
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
case EVENT_TYPE_LIST:
- if ((pos + sizeof(uint8_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
- if (peek) {
- return elem;
- }
- if (context->count[context->list_nest_depth]) {
- context->count[context->list_nest_depth]--;
- }
- context->list_stop = !context->storage[pos];
- context->list_nest_depth++;
- if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
- context->count[context->list_nest_depth] = context->storage[pos];
- }
- context->pos = pos + sizeof(uint8_t);
+ if ((pos + sizeof(uint8_t)) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
return elem;
+ }
+ elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
+ if (peek) {
+ return elem;
+ }
+ if (context->count[context->list_nest_depth]) {
+ context->count[context->list_nest_depth]--;
+ }
+ context->list_stop = !context->storage[pos];
+ context->list_nest_depth++;
+ if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->count[context->list_nest_depth] = context->storage[pos];
+ }
+ context->pos = pos + sizeof(uint8_t);
+ return elem;
case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
+ if (!peek) {
+ context->pos = pos;
+ }
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = !context->list_nest_depth;
+ if (context->list_nest_depth > 0) {
+ elem.type = EVENT_TYPE_LIST_STOP;
if (!peek) {
- context->pos = pos;
+ context->list_nest_depth--;
}
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = !context->list_nest_depth;
- if (context->list_nest_depth > 0) {
- elem.type = EVENT_TYPE_LIST_STOP;
- if (!peek) {
- context->list_nest_depth--;
- }
- }
- return elem;
+ }
+ return elem;
default:
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
}
-LIBLOG_ABI_PUBLIC android_log_list_element android_log_read_next(
- android_log_context ctx) {
- return android_log_read_next_internal(ctx, 0);
+LIBLOG_ABI_PUBLIC android_log_list_element
+android_log_read_next(android_log_context ctx) {
+ return android_log_read_next_internal(ctx, 0);
}
-LIBLOG_ABI_PUBLIC android_log_list_element android_log_peek_next(
- android_log_context ctx) {
- return android_log_read_next_internal(ctx, 1);
+LIBLOG_ABI_PUBLIC android_log_list_element
+android_log_peek_next(android_log_context ctx) {
+ return android_log_read_next_internal(ctx, 1);
}
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 14d6482..45a6f37 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -24,31 +24,28 @@
#define MAX_SUBTAG_LEN 32
-LIBLOG_ABI_PUBLIC int __android_log_error_write(
- int tag,
- const char *subTag,
- int32_t uid,
- const char *data, uint32_t dataLen)
-{
- int ret = -EINVAL;
+LIBLOG_ABI_PUBLIC int __android_log_error_write(int tag, const char* subTag,
+ int32_t uid, const char* data,
+ uint32_t dataLen) {
+ int ret = -EINVAL;
- if (subTag && (data || !dataLen)) {
- android_log_context ctx = create_android_logger(tag);
+ if (subTag && (data || !dataLen)) {
+ android_log_context ctx = create_android_logger(tag);
- ret = -ENOMEM;
- if (ctx) {
- ret = android_log_write_string8_len(ctx, subTag, MAX_SUBTAG_LEN);
- if (ret >= 0) {
- ret = android_log_write_int32(ctx, uid);
- if (ret >= 0) {
- ret = android_log_write_string8_len(ctx, data, dataLen);
- if (ret >= 0) {
- ret = android_log_write_list(ctx, LOG_ID_EVENTS);
- }
- }
- }
- android_log_destroy(&ctx);
+ ret = -ENOMEM;
+ if (ctx) {
+ ret = android_log_write_string8_len(ctx, subTag, MAX_SUBTAG_LEN);
+ if (ret >= 0) {
+ ret = android_log_write_int32(ctx, uid);
+ if (ret >= 0) {
+ ret = android_log_write_string8_len(ctx, data, dataLen);
+ if (ret >= 0) {
+ ret = android_log_write_list(ctx, LOG_ID_EVENTS);
+ }
}
+ }
+ android_log_destroy(&ctx);
}
- return ret;
+ }
+ return ret;
}
diff --git a/liblog/log_portability.h b/liblog/log_portability.h
index 3ad2060..88805c7 100644
--- a/liblog/log_portability.h
+++ b/liblog/log_portability.h
@@ -46,7 +46,7 @@
#if defined(_WIN32)
#define LIBLOG_WEAK static /* Accept that it is totally private */
#else
-#define LIBLOG_WEAK __attribute__((weak,visibility("default")))
+#define LIBLOG_WEAK __attribute__((weak, visibility("default")))
#endif
/* possible missing definitions in sys/cdefs.h */
@@ -54,8 +54,8 @@
/* DECLS */
#ifndef __BEGIN_DECLS
#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS }
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
#else
#define __BEGIN_DECLS
#define __END_DECLS
@@ -64,19 +64,21 @@
/* Unused argument. For C code only, remove symbol name for C++ */
#ifndef __unused
-#define __unused __attribute__((__unused__))
+#define __unused __attribute__((__unused__))
#endif
/* possible missing definitions in unistd.h */
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({ \
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
__typeof__(exp) _rc; \
do { \
- _rc = (exp); \
+ _rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
- _rc; })
+ _rc; \
+ })
#endif
#endif /* _LIBLOG_PORTABILITY_H__ */
diff --git a/liblog/log_ratelimit.cpp b/liblog/log_ratelimit.cpp
index dfd4b8f..33770dd 100644
--- a/liblog/log_ratelimit.cpp
+++ b/liblog/log_ratelimit.cpp
@@ -31,8 +31,8 @@
// of varying the 'seconds' argument to their pleasure.
static time_t g_last_seconds;
static const time_t last_seconds_default = 10;
-static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day
-static const time_t last_seconds_min = 2; // granularity
+static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day
+static const time_t last_seconds_min = 2; // granularity
// Lock to protect last_clock and last_seconds, but also 'last'
// argument (not NULL) as supplied to __android_log_ratelimit.
static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER;
@@ -43,44 +43,44 @@
// can not acquire a lock, 0 if we are not to log a message, and 1
// if we are ok to log a message. Caller should check > 0 for true.
LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) {
- int save_errno = errno;
+ int save_errno = errno;
- // Two reasons for trylock failure:
- // 1. In a signal handler. Must prevent deadlock
- // 2. Too many threads calling __android_log_ratelimit.
- // Bonus to not print if they race here because that
- // dovetails the goal of ratelimiting. One may print
- // and the others will wait their turn ...
- if (pthread_mutex_trylock(&lock_ratelimit)) {
- if (save_errno) errno = save_errno;
- return -1;
- }
+ // Two reasons for trylock failure:
+ // 1. In a signal handler. Must prevent deadlock
+ // 2. Too many threads calling __android_log_ratelimit.
+ // Bonus to not print if they race here because that
+ // dovetails the goal of ratelimiting. One may print
+ // and the others will wait their turn ...
+ if (pthread_mutex_trylock(&lock_ratelimit)) {
+ if (save_errno) errno = save_errno;
+ return -1;
+ }
- if (seconds == 0) {
- seconds = last_seconds_default;
- } else if (seconds < last_seconds_min) {
- seconds = last_seconds_min;
- } else if (seconds > last_seconds_max) {
- seconds = last_seconds_max;
- }
+ if (seconds == 0) {
+ seconds = last_seconds_default;
+ } else if (seconds < last_seconds_min) {
+ seconds = last_seconds_min;
+ } else if (seconds > last_seconds_max) {
+ seconds = last_seconds_max;
+ }
- if (!last) {
- if (g_last_seconds > seconds) {
- seconds = g_last_seconds;
- } else if (g_last_seconds < seconds) {
- g_last_seconds = seconds;
- }
- last = &g_last_clock;
+ if (!last) {
+ if (g_last_seconds > seconds) {
+ seconds = g_last_seconds;
+ } else if (g_last_seconds < seconds) {
+ g_last_seconds = seconds;
}
+ last = &g_last_clock;
+ }
- time_t now = time(NULL);
- if ((now == (time_t)-1) || ((*last + seconds) > now)) {
- pthread_mutex_unlock(&lock_ratelimit);
- if (save_errno) errno = save_errno;
- return 0;
- }
- *last = now;
+ time_t now = time(NULL);
+ if ((now == (time_t)-1) || ((*last + seconds) > now)) {
pthread_mutex_unlock(&lock_ratelimit);
if (save_errno) errno = save_errno;
- return 1;
+ return 0;
+ }
+ *last = now;
+ pthread_mutex_unlock(&lock_ratelimit);
+ if (save_errno) errno = save_errno;
+ return 1;
}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index dfd2d44..ae376be 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -28,164 +28,164 @@
// Add %#q for fractional seconds to standard strptime function
-LIBLOG_ABI_PRIVATE char *log_time::strptime(const char *s, const char *format) {
- time_t now;
+LIBLOG_ABI_PRIVATE char* log_time::strptime(const char* s, const char* format) {
+ time_t now;
#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
- now = tv_sec;
+ *this = log_time(CLOCK_REALTIME);
+ now = tv_sec;
#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
+ time(&now);
+ tv_sec = now;
+ tv_nsec = 0;
#endif
- struct tm *ptm;
+ struct tm* ptm;
#if !defined(_WIN32)
- struct tm tmBuf;
- ptm = localtime_r(&now, &tmBuf);
+ struct tm tmBuf;
+ ptm = localtime_r(&now, &tmBuf);
#else
- ptm = localtime(&now);
+ ptm = localtime(&now);
#endif
- char fmt[strlen(format) + 1];
- strcpy(fmt, format);
+ char fmt[strlen(format) + 1];
+ strcpy(fmt, format);
- char *ret = const_cast<char *> (s);
- char *cp;
- for (char *f = cp = fmt; ; ++cp) {
- if (!*cp) {
- if (f != cp) {
- ret = ::strptime(ret, f, ptm);
- }
- break;
- }
- if (*cp != '%') {
- continue;
- }
- char *e = cp;
- ++e;
+ char* ret = const_cast<char*>(s);
+ char* cp;
+ for (char* f = cp = fmt;; ++cp) {
+ if (!*cp) {
+ if (f != cp) {
+ ret = ::strptime(ret, f, ptm);
+ }
+ break;
+ }
+ if (*cp != '%') {
+ continue;
+ }
+ char* e = cp;
+ ++e;
#if (defined(__BIONIC__))
- if (*e == 's') {
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- tv_sec = 0;
- while (isdigit(*ret)) {
- tv_sec = tv_sec * 10 + *ret - '0';
- ++ret;
- }
- now = tv_sec;
-#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
- } else
-#endif
- {
- unsigned num = 0;
- while (isdigit(*e)) {
- num = num * 10 + *e - '0';
- ++e;
- }
- if (*e != 'q') {
- continue;
- }
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- unsigned long mul = NS_PER_SEC;
- if (num == 0) {
- num = INT_MAX;
- }
- tv_nsec = 0;
- while (isdigit(*ret) && num && (mul > 1)) {
- --num;
- mul /= 10;
- tv_nsec = tv_nsec + (*ret - '0') * mul;
- ++ret;
- }
+ if (*e == 's') {
+ *cp = '\0';
+ if (*f) {
+ ret = ::strptime(ret, f, ptm);
+ if (!ret) {
+ break;
}
- f = cp = e;
- ++f;
- }
-
- if (ret) {
- tv_sec = mktime(ptm);
- return ret;
- }
-
- // Upon error, place a known value into the class, the current time.
-#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
+ }
+ tv_sec = 0;
+ while (isdigit(*ret)) {
+ tv_sec = tv_sec * 10 + *ret - '0';
+ ++ret;
+ }
+ now = tv_sec;
+#if !defined(_WIN32)
+ ptm = localtime_r(&now, &tmBuf);
#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
+ ptm = localtime(&now);
#endif
+ } else
+#endif
+ {
+ unsigned num = 0;
+ while (isdigit(*e)) {
+ num = num * 10 + *e - '0';
+ ++e;
+ }
+ if (*e != 'q') {
+ continue;
+ }
+ *cp = '\0';
+ if (*f) {
+ ret = ::strptime(ret, f, ptm);
+ if (!ret) {
+ break;
+ }
+ }
+ unsigned long mul = NS_PER_SEC;
+ if (num == 0) {
+ num = INT_MAX;
+ }
+ tv_nsec = 0;
+ while (isdigit(*ret) && num && (mul > 1)) {
+ --num;
+ mul /= 10;
+ tv_nsec = tv_nsec + (*ret - '0') * mul;
+ ++ret;
+ }
+ }
+ f = cp = e;
+ ++f;
+ }
+
+ if (ret) {
+ tv_sec = mktime(ptm);
return ret;
+ }
+
+// Upon error, place a known value into the class, the current time.
+#ifdef __linux__
+ *this = log_time(CLOCK_REALTIME);
+#else
+ time(&now);
+ tv_sec = now;
+ tv_nsec = 0;
+#endif
+ return ret;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator-= (const timespec &T) {
- // No concept of negative time, clamp to EPOCH
- if (*this <= T) {
- return *this = EPOCH;
- }
+LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const timespec& T) {
+ // No concept of negative time, clamp to EPOCH
+ if (*this <= T) {
+ return *this = EPOCH;
+ }
- if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
- --this->tv_sec;
- this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
- } else {
- this->tv_nsec -= T.tv_nsec;
- }
- this->tv_sec -= T.tv_sec;
+ if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
+ --this->tv_sec;
+ this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+ } else {
+ this->tv_nsec -= T.tv_nsec;
+ }
+ this->tv_sec -= T.tv_sec;
- return *this;
+ return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator+= (const timespec &T) {
- this->tv_nsec += (unsigned long int)T.tv_nsec;
- if (this->tv_nsec >= NS_PER_SEC) {
- this->tv_nsec -= NS_PER_SEC;
- ++this->tv_sec;
- }
- this->tv_sec += T.tv_sec;
+LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const timespec& T) {
+ this->tv_nsec += (unsigned long int)T.tv_nsec;
+ if (this->tv_nsec >= NS_PER_SEC) {
+ this->tv_nsec -= NS_PER_SEC;
+ ++this->tv_sec;
+ }
+ this->tv_sec += T.tv_sec;
- return *this;
+ return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator-= (const log_time &T) {
- // No concept of negative time, clamp to EPOCH
- if (*this <= T) {
- return *this = EPOCH;
- }
+LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const log_time& T) {
+ // No concept of negative time, clamp to EPOCH
+ if (*this <= T) {
+ return *this = EPOCH;
+ }
- if (this->tv_nsec < T.tv_nsec) {
- --this->tv_sec;
- this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
- } else {
- this->tv_nsec -= T.tv_nsec;
- }
- this->tv_sec -= T.tv_sec;
+ if (this->tv_nsec < T.tv_nsec) {
+ --this->tv_sec;
+ this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+ } else {
+ this->tv_nsec -= T.tv_nsec;
+ }
+ this->tv_sec -= T.tv_sec;
- return *this;
+ return *this;
}
-LIBLOG_ABI_PRIVATE log_time log_time::operator+= (const log_time &T) {
- this->tv_nsec += T.tv_nsec;
- if (this->tv_nsec >= NS_PER_SEC) {
- this->tv_nsec -= NS_PER_SEC;
- ++this->tv_sec;
- }
- this->tv_sec += T.tv_sec;
+LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const log_time& T) {
+ this->tv_nsec += T.tv_nsec;
+ if (this->tv_nsec >= NS_PER_SEC) {
+ this->tv_nsec -= NS_PER_SEC;
+ ++this->tv_sec;
+ }
+ this->tv_sec += T.tv_sec;
- return *this;
+ return *this;
}
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index ccc7da8..600f4bb 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -24,9 +24,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
@@ -41,87 +41,86 @@
#include "logger.h"
/* branchless on many architectures. */
-#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
static int logdAvailable(log_id_t LogId);
-static int logdVersion(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
-static int logdRead(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg);
-static int logdPoll(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp);
-static void logdClose(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp);
-static int logdClear(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
-static ssize_t logdSetSize(struct android_log_logger *logger,
- struct android_log_transport_context *transp,
+static int logdVersion(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static int logdRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg);
+static int logdPoll(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
+static void logdClose(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
+static int logdClear(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static ssize_t logdSetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp,
size_t size);
-static ssize_t logdGetSize(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
-static ssize_t logdGetReadableSize(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
-static ssize_t logdGetPrune(struct android_log_logger_list *logger,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
-static ssize_t logdSetPrune(struct android_log_logger_list *logger,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
-static ssize_t logdGetStats(struct android_log_logger_list *logger,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
+static ssize_t logdGetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static ssize_t logdGetReadableSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static ssize_t logdGetPrune(struct android_log_logger_list* logger,
+ struct android_log_transport_context* transp,
+ char* buf, size_t len);
+static ssize_t logdSetPrune(struct android_log_logger_list* logger,
+ struct android_log_transport_context* transp,
+ char* buf, size_t len);
+static ssize_t logdGetStats(struct android_log_logger_list* logger,
+ struct android_log_transport_context* transp,
+ char* buf, size_t len);
LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
- .node = { &logdLoggerRead.node, &logdLoggerRead.node },
- .name = "logd",
- .available = logdAvailable,
- .version = logdVersion,
- .read = logdRead,
- .poll = logdPoll,
- .close = logdClose,
- .clear = logdClear,
- .getSize = logdGetSize,
- .setSize = logdSetSize,
- .getReadableSize = logdGetReadableSize,
- .getPrune = logdGetPrune,
- .setPrune = logdSetPrune,
- .getStats = logdGetStats,
+ .node = { &logdLoggerRead.node, &logdLoggerRead.node },
+ .name = "logd",
+ .available = logdAvailable,
+ .version = logdVersion,
+ .read = logdRead,
+ .poll = logdPoll,
+ .close = logdClose,
+ .clear = logdClear,
+ .getSize = logdGetSize,
+ .setSize = logdSetSize,
+ .getReadableSize = logdGetReadableSize,
+ .getPrune = logdGetPrune,
+ .setPrune = logdSetPrune,
+ .getStats = logdGetStats,
};
-static int logdAvailable(log_id_t logId)
-{
- if (logId > LOG_ID_KERNEL) {
- return -EINVAL;
+static int logdAvailable(log_id_t logId) {
+ if (logId >= LOG_ID_MAX) {
+ return -EINVAL;
+ }
+ if (logId == LOG_ID_SECURITY) {
+ uid_t uid = __android_log_uid();
+ if (uid != AID_SYSTEM) {
+ return -EPERM;
}
- if (logId == LOG_ID_SECURITY) {
- uid_t uid = __android_log_uid();
- if (uid != AID_SYSTEM) {
- return -EPERM;
- }
- }
- if (access("/dev/socket/logdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
+ }
+ if (access("/dev/socket/logdw", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
}
/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
#if defined(_WIN32)
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
- errno = ENOSYS;
- return -ENOSYS;
+LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId,
+ int type) {
+ errno = ENOSYS;
+ return -ENOSYS;
}
#else /* !_WIN32 */
-#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/select.h>
+#include <sys/socket.h>
#include <sys/types.h>
+#include <sys/un.h>
/* Private copy of ../libcutils/socket_local.h prevent library loops */
#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
@@ -131,78 +130,77 @@
#define LISTEN_BACKLOG 4
/* Documented in header file. */
-LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
- struct sockaddr_un *p_addr,
- socklen_t *alen)
-{
- memset (p_addr, 0, sizeof (*p_addr));
- size_t namelen;
+LIBLOG_WEAK int socket_make_sockaddr_un(const char* name, int namespaceId,
+ struct sockaddr_un* p_addr,
+ socklen_t* alen) {
+ memset(p_addr, 0, sizeof(*p_addr));
+ size_t namelen;
- switch (namespaceId) {
+ switch (namespaceId) {
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
#if defined(__linux__)
- namelen = strlen(name);
+ namelen = strlen(name);
- /* Test with length +1 for the *initial* '\0'. */
- if ((namelen + 1) > sizeof(p_addr->sun_path)) {
- goto error;
- }
+ /* Test with length +1 for the *initial* '\0'. */
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
- /*
- * Note: The path in this case is *not* supposed to be
- * '\0'-terminated. ("man 7 unix" for the gory details.)
- */
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
- p_addr->sun_path[0] = 0;
- memcpy(p_addr->sun_path + 1, name, namelen);
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
#else
- /* this OS doesn't have the Linux abstract namespace */
+ /* this OS doesn't have the Linux abstract namespace */
- namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
- strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
- strcat(p_addr->sun_path, name);
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
#endif
- break;
+ break;
case ANDROID_SOCKET_NAMESPACE_RESERVED:
- namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
- strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
- strcat(p_addr->sun_path, name);
- break;
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
- namelen = strlen(name);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
- strcpy(p_addr->sun_path, name);
- break;
+ strcpy(p_addr->sun_path, name);
+ break;
default:
- /* invalid namespace id */
- return -1;
- }
+ /* invalid namespace id */
+ return -1;
+ }
- p_addr->sun_family = AF_LOCAL;
- *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
- return 0;
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
error:
- return -1;
+ return -1;
}
/**
@@ -212,466 +210,441 @@
*
* Used by AndroidSocketImpl
*/
-LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
- int namespaceId, int type __unused)
-{
- struct sockaddr_un addr;
- socklen_t alen;
- int err;
+LIBLOG_WEAK int socket_local_client_connect(int fd, const char* name,
+ int namespaceId, int type __unused) {
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int err;
- err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+ err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
- if (err < 0) {
- goto error;
- }
+ if (err < 0) {
+ goto error;
+ }
- if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
- goto error;
- }
+ if (connect(fd, (struct sockaddr*)&addr, alen) < 0) {
+ goto error;
+ }
- return fd;
+ return fd;
error:
- return -1;
+ return -1;
}
/**
* connect to peer named "name"
* returns fd or -1 on error
*/
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
- int s;
+LIBLOG_WEAK int socket_local_client(const char* name, int namespaceId,
+ int type) {
+ int s;
- s = socket(AF_LOCAL, type, 0);
- if(s < 0) return -1;
+ s = socket(AF_LOCAL, type, 0);
+ if (s < 0) return -1;
- if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
- close(s);
- return -1;
- }
+ if (0 > socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
- return s;
+ return s;
}
#endif /* !_WIN32 */
/* End of ../libcutils/socket_local_client.c */
/* worker for sending the command to the logger */
-static ssize_t send_log_msg(struct android_log_logger *logger,
- const char *msg, char *buf, size_t buf_size)
-{
- ssize_t ret;
- size_t len;
- char *cp;
- int errno_save = 0;
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock < 0) {
- return sock;
+static ssize_t send_log_msg(struct android_log_logger* logger, const char* msg,
+ char* buf, size_t buf_size) {
+ ssize_t ret;
+ size_t len;
+ char* cp;
+ int errno_save = 0;
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock < 0) {
+ return sock;
+ }
+
+ if (msg) {
+ snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned)-1);
+ }
+
+ len = strlen(buf) + 1;
+ ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+ if (ret <= 0) {
+ goto done;
+ }
+
+ len = buf_size;
+ cp = buf;
+ while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+ struct pollfd p;
+
+ if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+ break;
}
- if (msg) {
- snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned) -1);
- }
+ len -= ret;
+ cp += ret;
- len = strlen(buf) + 1;
- ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+ memset(&p, 0, sizeof(p));
+ p.fd = sock;
+ p.events = POLLIN;
+
+ /* Give other side 20ms to refill pipe */
+ ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
if (ret <= 0) {
- goto done;
+ break;
}
- len = buf_size;
- cp = buf;
- while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
- struct pollfd p;
-
- if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
- break;
- }
-
- len -= ret;
- cp += ret;
-
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
-
- /* Give other side 20ms to refill pipe */
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
-
- if (ret <= 0) {
- break;
- }
-
- if (!(p.revents & POLLIN)) {
- ret = 0;
- break;
- }
+ if (!(p.revents & POLLIN)) {
+ ret = 0;
+ break;
}
+ }
- if (ret >= 0) {
- ret += buf_size - len;
- }
+ if (ret >= 0) {
+ ret += buf_size - len;
+ }
done:
- if ((ret == -1) && errno) {
- errno_save = errno;
- }
- close(sock);
- if (errno_save) {
- errno = errno_save;
- }
+ if ((ret == -1) && errno) {
+ errno_save = errno;
+ }
+ close(sock);
+ if (errno_save) {
+ errno = errno_save;
+ }
+ return ret;
+}
+
+LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf, size_t buf_size) {
+ return send_log_msg(NULL, NULL, buf, buf_size);
+}
+
+static int check_log_success(char* buf, ssize_t ret) {
+ if (ret < 0) {
return ret;
+ }
+
+ if (strncmp(buf, "success", 7)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
}
-LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf, size_t buf_size)
-{
- return send_log_msg(NULL, NULL, buf, buf_size);
-}
+static int logdClear(struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused) {
+ char buf[512];
-static int check_log_success(char *buf, ssize_t ret)
-{
- if (ret < 0) {
- return ret;
- }
-
- if (strncmp(buf, "success", 7)) {
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-static int logdClear(struct android_log_logger *logger,
- struct android_log_transport_context *transp __unused)
-{
- char buf[512];
-
- return check_log_success(buf,
- send_log_msg(logger, "clear %d", buf, sizeof(buf)));
+ return check_log_success(buf,
+ send_log_msg(logger, "clear %d", buf, sizeof(buf)));
}
/* returns the total size of the log's ring buffer */
-static ssize_t logdGetSize(struct android_log_logger *logger,
- struct android_log_transport_context *transp __unused)
-{
- char buf[512];
+static ssize_t logdGetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused) {
+ char buf[512];
- ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
+ ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
- if ((buf[0] < '0') || ('9' < buf[0])) {
- return -1;
- }
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
- return atol(buf);
+ return atol(buf);
}
-static ssize_t logdSetSize(
- struct android_log_logger *logger,
- struct android_log_transport_context *transp __unused,
- size_t size)
-{
- char buf[512];
+static ssize_t logdSetSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp __unused,
+ size_t size) {
+ char buf[512];
- snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
+ snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
- return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
}
/*
* returns the readable size of the log's ring buffer (that is, amount of the
* log consumed)
*/
-static ssize_t logdGetReadableSize(
- struct android_log_logger *logger,
- struct android_log_transport_context *transp __unused)
-{
- char buf[512];
+static ssize_t logdGetReadableSize(struct android_log_logger* logger,
+ struct android_log_transport_context* transp
+ __unused) {
+ char buf[512];
- ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
+ ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
- if ((buf[0] < '0') || ('9' < buf[0])) {
- return -1;
- }
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
- return atol(buf);
+ return atol(buf);
}
/*
* returns the logger version
*/
-static int logdVersion(
- struct android_log_logger *logger __unused,
- struct android_log_transport_context *transp __unused)
-{
- uid_t uid = __android_log_uid();
- return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
+static int logdVersion(struct android_log_logger* logger __unused,
+ struct android_log_transport_context* transp __unused) {
+ uid_t uid = __android_log_uid();
+ return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
}
/*
* returns statistics
*/
-static ssize_t logdGetStats(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp __unused,
- char *buf, size_t len)
-{
- struct android_log_logger *logger;
- char *cp = buf;
- size_t remaining = len;
- size_t n;
+static ssize_t logdGetStats(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp __unused,
+ char* buf, size_t len) {
+ struct android_log_logger* logger;
+ char* cp = buf;
+ size_t remaining = len;
+ size_t n;
- n = snprintf(cp, remaining, "getStatistics");
+ n = snprintf(cp, remaining, "getStatistics");
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+
+ logger_for_each(logger, logger_list) {
+ n = snprintf(cp, remaining, " %d", logger->logId);
n = min(n, remaining);
remaining -= n;
cp += n;
+ }
- logger_for_each(logger, logger_list) {
- n = snprintf(cp, remaining, " %d", logger->logId);
- n = min(n, remaining);
- remaining -= n;
- cp += n;
- }
+ if (logger_list->pid) {
+ snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ }
- if (logger_list->pid) {
- snprintf(cp, remaining, " pid=%u", logger_list->pid);
- }
-
- return send_log_msg(NULL, NULL, buf, len);
+ return send_log_msg(NULL, NULL, buf, len);
}
-static ssize_t logdGetPrune(
- struct android_log_logger_list *logger_list __unused,
- struct android_log_transport_context *transp __unused,
- char *buf, size_t len)
-{
- return send_log_msg(NULL, "getPruneList", buf, len);
+static ssize_t logdGetPrune(struct android_log_logger_list* logger_list __unused,
+ struct android_log_transport_context* transp __unused,
+ char* buf, size_t len) {
+ return send_log_msg(NULL, "getPruneList", buf, len);
}
-static ssize_t logdSetPrune(
- struct android_log_logger_list *logger_list __unused,
- struct android_log_transport_context *transp __unused,
- char *buf, size_t len)
-{
- const char cmd[] = "setPruneList ";
- const size_t cmdlen = sizeof(cmd) - 1;
+static ssize_t logdSetPrune(struct android_log_logger_list* logger_list __unused,
+ struct android_log_transport_context* transp __unused,
+ char* buf, size_t len) {
+ const char cmd[] = "setPruneList ";
+ const size_t cmdlen = sizeof(cmd) - 1;
- if (strlen(buf) > (len - cmdlen)) {
- return -ENOMEM; /* KISS */
- }
- memmove(buf + cmdlen, buf, len - cmdlen);
- buf[len - 1] = '\0';
- memcpy(buf, cmd, cmdlen);
+ if (strlen(buf) > (len - cmdlen)) {
+ return -ENOMEM; /* KISS */
+ }
+ memmove(buf + cmdlen, buf, len - cmdlen);
+ buf[len - 1] = '\0';
+ memcpy(buf, cmd, cmdlen);
- return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
}
-
-static void caught_signal(int signum __unused)
-{
+static void caught_signal(int signum __unused) {
}
-static int logdOpen(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp)
-{
- struct android_log_logger *logger;
- struct sigaction ignore;
- struct sigaction old_sigaction;
- unsigned int old_alarm = 0;
- char buffer[256], *cp, c;
- int e, ret, remaining, sock;
+static int logdOpen(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp) {
+ struct android_log_logger* logger;
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
+ char buffer[256], *cp, c;
+ int e, ret, remaining, sock;
- if (!logger_list) {
- return -EINVAL;
- }
+ if (!logger_list) {
+ return -EINVAL;
+ }
- sock = atomic_load(&transp->context.sock);
- if (sock > 0) {
- return sock;
- }
+ sock = atomic_load(&transp->context.sock);
+ if (sock > 0) {
+ return sock;
+ }
- sock = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- if (sock == 0) {
- /* Guarantee not file descriptor zero */
- int newsock = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- close(sock);
- sock = newsock;
- }
- if (sock <= 0) {
- if ((sock == -1) && errno) {
- return -errno;
- }
- return sock;
- }
-
- strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ?
- "dumpAndClose" : "stream");
- cp = buffer + strlen(buffer);
-
- strcpy(cp, " lids");
- cp += 5;
- c = '=';
- remaining = sizeof(buffer) - (cp - buffer);
- logger_for_each(logger, logger_list) {
- ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- c = ',';
- }
-
- if (logger_list->tail) {
- ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
- if (logger_list->mode & ANDROID_LOG_WRAP) {
- // ToDo: alternate API to allow timeout to be adjusted.
- ret = snprintf(cp, remaining, " timeout=%u",
- ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
- ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
- logger_list->start.tv_sec,
- logger_list->start.tv_nsec);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->pid) {
- ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
- ret = min(ret, remaining);
- cp += ret;
- }
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- /* Deal with an unresponsive logd */
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- /* particularily useful if tombstone is reporting for logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
- }
- ret = write(sock, buffer, cp - buffer);
- e = errno;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if (e == EINTR) {
- e = ETIMEDOUT;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
- }
-
- if (ret <= 0) {
- close(sock);
- if ((ret == -1) && e) {
- return -e;
- }
- if (ret == 0) {
- return -EIO;
- }
- return ret;
- }
-
- ret = atomic_exchange(&transp->context.sock, sock);
- if ((ret > 0) && (ret != sock)) {
- close(ret);
+ sock = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET);
+ if (sock == 0) {
+ /* Guarantee not file descriptor zero */
+ int newsock = socket_local_client(
+ "logdr", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
+ close(sock);
+ sock = newsock;
+ }
+ if (sock <= 0) {
+ if ((sock == -1) && errno) {
+ return -errno;
}
return sock;
+ }
+
+ strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose"
+ : "stream");
+ cp = buffer + strlen(buffer);
+
+ strcpy(cp, " lids");
+ cp += 5;
+ c = '=';
+ remaining = sizeof(buffer) - (cp - buffer);
+ logger_for_each(logger, logger_list) {
+ ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ c = ',';
+ }
+
+ if (logger_list->tail) {
+ ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+ if (logger_list->mode & ANDROID_LOG_WRAP) {
+ // ToDo: alternate API to allow timeout to be adjusted.
+ ret = snprintf(cp, remaining, " timeout=%u",
+ ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+ ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+ logger_list->start.tv_sec, logger_list->start.tv_nsec);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->pid) {
+ ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ ret = min(ret, remaining);
+ cp += ret;
+ }
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ /* Deal with an unresponsive logd */
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ ret = write(sock, buffer, cp - buffer);
+ e = errno;
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if (e == EINTR) {
+ e = ETIMEDOUT;
+ }
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
+
+ if (ret <= 0) {
+ close(sock);
+ if ((ret == -1) && e) {
+ return -e;
+ }
+ if (ret == 0) {
+ return -EIO;
+ }
+ return ret;
+ }
+
+ ret = atomic_exchange(&transp->context.sock, sock);
+ if ((ret > 0) && (ret != sock)) {
+ close(ret);
+ }
+ return sock;
}
/* Read from the selected logs */
-static int logdRead(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg)
-{
- int ret, e;
- struct sigaction ignore;
- struct sigaction old_sigaction;
- unsigned int old_alarm = 0;
+static int logdRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg) {
+ int ret, e;
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
- ret = logdOpen(logger_list, transp);
- if (ret < 0) {
- return ret;
- }
-
- memset(log_msg, 0, sizeof(*log_msg));
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- /* particularily useful if tombstone is reporting for logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
- }
-
- /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
- ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
- e = errno;
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if ((ret == 0) || (e == EINTR)) {
- e = EAGAIN;
- ret = -1;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
- }
-
- if ((ret == -1) && e) {
- return -e;
- }
+ ret = logdOpen(logger_list, transp);
+ if (ret < 0) {
return ret;
+ }
+
+ memset(log_msg, 0, sizeof(*log_msg));
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+
+ /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+ ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+ e = errno;
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if ((ret == 0) || (e == EINTR)) {
+ e = EAGAIN;
+ ret = -1;
+ }
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
+
+ if ((ret == -1) && e) {
+ return -e;
+ }
+ return ret;
}
-static int logdPoll(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp)
-{
- struct pollfd p;
+static int logdPoll(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp) {
+ struct pollfd p;
- int ret = logdOpen(logger_list, transp);
- if (ret < 0) {
- return ret;
- }
-
- memset(&p, 0, sizeof(p));
- p.fd = ret;
- p.events = POLLIN;
- ret = poll(&p, 1, 20);
- if ((ret > 0) && !(p.revents & POLLIN)) {
- ret = 0;
- }
- if ((ret == -1) && errno) {
- return -errno;
- }
+ int ret = logdOpen(logger_list, transp);
+ if (ret < 0) {
return ret;
+ }
+
+ memset(&p, 0, sizeof(p));
+ p.fd = ret;
+ p.events = POLLIN;
+ ret = poll(&p, 1, 20);
+ if ((ret > 0) && !(p.revents & POLLIN)) {
+ ret = 0;
+ }
+ if ((ret == -1) && errno) {
+ return -errno;
+ }
+ return ret;
}
/* Close all the logs */
-static void logdClose(struct android_log_logger_list *logger_list __unused,
- struct android_log_transport_context *transp)
-{
- int sock = atomic_exchange(&transp->context.sock, -1);
- if (sock > 0) {
- close (sock);
- }
+static void logdClose(struct android_log_logger_list* logger_list __unused,
+ struct android_log_transport_context* transp) {
+ int sock = atomic_exchange(&transp->context.sock, -1);
+ if (sock > 0) {
+ close(sock);
+ }
}
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
index 04c2cf2..8ebb1ae 100644
--- a/liblog/logd_reader.h
+++ b/liblog/logd_reader.h
@@ -23,7 +23,7 @@
__BEGIN_DECLS
-LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf, size_t buf_size);
+LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf, size_t buf_size);
__END_DECLS
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 2bab92e..e0e3eca 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -24,9 +24,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
@@ -40,260 +40,251 @@
#include "logger.h"
/* branchless on many architectures. */
-#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
static int logdAvailable(log_id_t LogId);
static int logdOpen();
static void logdClose();
-static int logdWrite(log_id_t logId, struct timespec *ts,
- struct iovec *vec, size_t nr);
+static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr);
LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
- .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
- .context.sock = -EBADF,
- .name = "logd",
- .available = logdAvailable,
- .open = logdOpen,
- .close = logdClose,
- .write = logdWrite,
+ .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
+ .context.sock = -EBADF,
+ .name = "logd",
+ .available = logdAvailable,
+ .open = logdOpen,
+ .close = logdClose,
+ .write = logdWrite,
};
/* log_init_lock assumed */
-static int logdOpen()
-{
- int i, ret = 0;
+static int logdOpen() {
+ int i, ret = 0;
- i = atomic_load(&logdLoggerWrite.context.sock);
- if (i < 0) {
- int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM |
- SOCK_CLOEXEC |
- SOCK_NONBLOCK, 0));
- if (sock < 0) {
- ret = -errno;
- } else {
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
+ i = atomic_load(&logdLoggerWrite.context.sock);
+ if (i < 0) {
+ int sock = TEMP_FAILURE_RETRY(
+ socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+ if (sock < 0) {
+ ret = -errno;
+ } else {
+ struct sockaddr_un un;
+ memset(&un, 0, sizeof(struct sockaddr_un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, "/dev/socket/logdw");
- if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr *)&un,
- sizeof(struct sockaddr_un))) < 0) {
- ret = -errno;
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
- /* FALLTHRU */
- default:
- break;
- }
- close(sock);
- } else {
- ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
- if ((ret >= 0) && (ret != sock)) {
- close(ret);
- }
- ret = 0;
- }
- }
- }
-
- return ret;
-}
-
-static void __logdClose(int negative_errno)
-{
- int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
- if (sock >= 0) {
- close(sock);
- }
-}
-
-static void logdClose()
-{
- __logdClose(-EBADF);
-}
-
-static int logdAvailable(log_id_t logId)
-{
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
- }
- if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
- if (access("/dev/socket/logdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
-}
-
-static int logdWrite(log_id_t logId, struct timespec *ts,
- struct iovec *vec, size_t nr)
-{
- ssize_t ret;
- int sock;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
- static atomic_int_fast32_t dropped;
- static atomic_int_fast32_t droppedSecurity;
-
- sock = atomic_load(&logdLoggerWrite.context.sock);
- if (sock < 0) switch (sock) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- break;
- default:
- return -EBADF;
- }
-
- /* logd, after initialization and priv drop */
- if (__android_log_uid() == AID_LOGD) {
- /*
- * ignore log messages we send to ourself (logd).
- * Such log messages are often generated by libraries we depend on
- * which use standard Android logging.
- */
- return 0;
- }
-
- /*
- * struct {
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char *)&header;
- newVec[0].iov_len = sizeof(header);
-
- if (sock >= 0) {
- int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
- memory_order_relaxed);
- if (snapshot) {
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_SECURITY;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
-
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&droppedSecurity, snapshot,
- memory_order_relaxed);
- }
- }
- snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
- "liblog",
- strlen("liblog"),
- ANDROID_LOG_VERBOSE)) {
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
-
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot,
- memory_order_relaxed);
- }
- }
- }
-
- header.id = logId;
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
+ if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
+ sizeof(struct sockaddr_un))) < 0) {
+ ret = -errno;
+ switch (ret) {
+ case -ENOTCONN:
+ case -ECONNREFUSED:
+ case -ENOENT:
+ i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
+ /* FALLTHRU */
+ default:
break;
}
+ close(sock);
+ } else {
+ ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
+ if ((ret >= 0) && (ret != sock)) {
+ close(ret);
+ }
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void __logdClose(int negative_errno) {
+ int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
+ if (sock >= 0) {
+ close(sock);
+ }
+}
+
+static void logdClose() {
+ __logdClose(-EBADF);
+}
+
+static int logdAvailable(log_id_t logId) {
+ if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
+ return -EINVAL;
+ }
+ if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
+ if (access("/dev/socket/logdw", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
+ }
+ return 1;
+}
+
+static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr) {
+ ssize_t ret;
+ int sock;
+ static const unsigned headerLength = 1;
+ struct iovec newVec[nr + headerLength];
+ android_log_header_t header;
+ size_t i, payloadSize;
+ static atomic_int_fast32_t dropped;
+ static atomic_int_fast32_t droppedSecurity;
+
+ sock = atomic_load(&logdLoggerWrite.context.sock);
+ if (sock < 0) switch (sock) {
+ case -ENOTCONN:
+ case -ECONNREFUSED:
+ case -ENOENT:
+ break;
+ default:
+ return -EBADF;
}
+ /* logd, after initialization and priv drop */
+ if (__android_log_uid() == AID_LOGD) {
/*
- * The write below could be lost, but will never block.
- *
- * ENOTCONN occurs if logd has died.
- * ENOENT occurs if logd is not running and socket is missing.
- * ECONNREFUSED occurs if we can not reconnect to logd.
- * EAGAIN occurs if logd is overloaded.
+ * ignore log messages we send to ourself (logd).
+ * Such log messages are often generated by libraries we depend on
+ * which use standard Android logging.
*/
- if (sock < 0) {
- ret = sock;
- } else {
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
+ return 0;
+ }
+
+ /*
+ * struct {
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
+
+ header.tid = gettid();
+ header.realtime.tv_sec = ts->tv_sec;
+ header.realtime.tv_nsec = ts->tv_nsec;
+
+ newVec[0].iov_base = (unsigned char*)&header;
+ newVec[0].iov_len = sizeof(header);
+
+ if (sock >= 0) {
+ int32_t snapshot =
+ atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
+ if (snapshot) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_SECURITY;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&droppedSecurity, snapshot,
+ memory_order_relaxed);
+ }
}
- switch(ret) {
+ snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+ if (snapshot &&
+ __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog",
+ strlen("liblog"), ANDROID_LOG_VERBOSE)) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+ }
+ }
+ }
+
+ header.id = logId;
+
+ for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+ newVec[i].iov_base = vec[i - headerLength].iov_base;
+ payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+ if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+ newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+ if (newVec[i].iov_len) {
+ ++i;
+ }
+ break;
+ }
+ }
+
+ /*
+ * The write below could be lost, but will never block.
+ *
+ * ENOTCONN occurs if logd has died.
+ * ENOENT occurs if logd is not running and socket is missing.
+ * ECONNREFUSED occurs if we can not reconnect to logd.
+ * EAGAIN occurs if logd is overloaded.
+ */
+ if (sock < 0) {
+ ret = sock;
+ } else {
+ ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ }
+ switch (ret) {
case -ENOTCONN:
case -ECONNREFUSED:
case -ENOENT:
- if (__android_log_trylock()) {
- return ret; /* in a signal handler? try again when less stressed */
- }
- __logdClose(ret);
- ret = logdOpen();
- __android_log_unlock();
+ if (__android_log_trylock()) {
+ return ret; /* in a signal handler? try again when less stressed */
+ }
+ __logdClose(ret);
+ ret = logdOpen();
+ __android_log_unlock();
- if (ret < 0) {
- return ret;
- }
+ if (ret < 0) {
+ return ret;
+ }
- ret = TEMP_FAILURE_RETRY(writev(
- atomic_load(&logdLoggerWrite.context.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- /* FALLTHRU */
+ ret = TEMP_FAILURE_RETRY(
+ writev(atomic_load(&logdLoggerWrite.context.sock), newVec, i));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ /* FALLTHRU */
default:
- break;
- }
+ break;
+ }
- if (ret > (ssize_t)sizeof(header)) {
- ret -= sizeof(header);
- } else if (ret == -EAGAIN) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
- if (logId == LOG_ID_SECURITY) {
- atomic_fetch_add_explicit(&droppedSecurity, 1,
- memory_order_relaxed);
- }
+ if (ret > (ssize_t)sizeof(header)) {
+ ret -= sizeof(header);
+ } else if (ret == -EAGAIN) {
+ atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+ if (logId == LOG_ID_SECURITY) {
+ atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
}
+ }
- return ret;
+ return ret;
}
diff --git a/liblog/logger.h b/liblog/logger.h
index d332c03..246b33c 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -30,25 +30,25 @@
/* Union, sock or fd of zero is not allowed unless static initialized */
union android_log_context {
- void *private;
+ void* priv;
atomic_int sock;
atomic_int fd;
- struct listnode *node;
+ struct listnode* node;
atomic_uintptr_t atomic_pointer;
};
struct android_log_transport_write {
struct listnode node;
- const char *name; /* human name to describe the transport */
- unsigned logMask; /* mask cache of available() success */
+ const char* name; /* human name to describe the transport */
+ unsigned logMask; /* mask cache of available() success */
union android_log_context context; /* Initialized by static allocation */
int (*available)(log_id_t logId); /* Does not cause resources to be taken */
int (*open)(); /* can be called multiple times, reusing current resources */
void (*close)(); /* free up resources */
/* write log to transport, returns number of bytes propagated, or -errno */
- int (*write)(log_id_t logId, struct timespec *ts,
- struct iovec *vec, size_t nr);
+ int (*write)(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr);
};
struct android_log_logger_list;
@@ -57,48 +57,48 @@
struct android_log_transport_read {
struct listnode node;
- const char *name; /* human name to describe the transport */
+ const char* name; /* human name to describe the transport */
/* Does not cause resources to be taken */
int (*available)(log_id_t logId);
- int (*version)(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
+ int (*version)(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
/* Release resources taken by the following interfaces */
- void (*close)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp);
+ void (*close)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
/*
* Expect all to instantiate open automagically on any call,
* so we do not have an explicit open call.
*/
- int (*read)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg);
+ int (*read)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg);
/* Must only be called if not ANDROID_LOG_NONBLOCK (blocking) */
- int (*poll)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp);
+ int (*poll)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
- int (*clear)(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
- ssize_t (*setSize)(struct android_log_logger *logger,
- struct android_log_transport_context *transp,
- size_t size);
- ssize_t (*getSize)(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
- ssize_t (*getReadableSize)(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
+ int (*clear)(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+ ssize_t (*setSize)(struct android_log_logger* logger,
+ struct android_log_transport_context* transp, size_t size);
+ ssize_t (*getSize)(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+ ssize_t (*getReadableSize)(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
- ssize_t (*getPrune)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
- ssize_t (*setPrune)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
- ssize_t (*getStats)(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- char *buf, size_t len);
+ ssize_t (*getPrune)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp, char* buf,
+ size_t len);
+ ssize_t (*setPrune)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp, char* buf,
+ size_t len);
+ ssize_t (*getStats)(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp, char* buf,
+ size_t len);
};
struct android_log_logger_list {
+ struct listnode node;
struct listnode logger;
struct listnode transport;
int mode;
@@ -109,7 +109,7 @@
struct android_log_logger {
struct listnode node;
- struct android_log_logger_list *parent;
+ struct android_log_logger_list* parent;
log_id_t logId;
};
@@ -117,49 +117,84 @@
struct android_log_transport_context {
struct listnode node;
union android_log_context context; /* zero init per-transport context */
- struct android_log_logger_list *parent;
+ struct android_log_logger_list* parent;
- struct android_log_transport_read *transport;
+ struct android_log_transport_read* transport;
unsigned logMask; /* mask of requested log buffers */
int ret; /* return value associated with following data */
struct log_msg logMsg; /* peek at upcoming data, valid if logMsg.len != 0 */
};
/* assumes caller has structures read-locked, single threaded, or fenced */
-#define transport_context_for_each(transp, logger_list) \
- for ((transp) = node_to_item((logger_list)->transport.next, \
- struct android_log_transport_context, \
- node); \
- ((transp) != node_to_item(&(logger_list)->transport, \
- struct android_log_transport_context, \
- node)) && \
- ((transp)->parent == (logger_list)); \
- (transp) = node_to_item((transp)->node.next, \
- struct android_log_transport_context, node))
+#define transport_context_for_each(transp, logger_list) \
+ for ((transp) = node_to_item((logger_list)->transport.next, \
+ struct android_log_transport_context, node); \
+ ((transp) != node_to_item(&(logger_list)->transport, \
+ struct android_log_transport_context, node)) && \
+ ((transp)->parent == (logger_list)); \
+ (transp) = node_to_item((transp)->node.next, \
+ struct android_log_transport_context, node))
#define logger_for_each(logp, logger_list) \
- for ((logp) = node_to_item((logger_list)->logger.next, \
+ for ((logp) = node_to_item((logger_list)->logger.next, \
struct android_log_logger, node); \
- ((logp) != node_to_item(&(logger_list)->logger, \
+ ((logp) != node_to_item(&(logger_list)->logger, \
struct android_log_logger, node)) && \
- ((logp)->parent == (logger_list)); \
- (logp) = node_to_item((logp)->node.next, \
- struct android_log_logger, node))
+ ((logp)->parent == (logger_list)); \
+ (logp) = \
+ node_to_item((logp)->node.next, struct android_log_logger, node))
+
+/*
+ * Global list of log readers.
+ *
+ * Usage case: search out transport contexts for all readers
+ */
+
+LIBLOG_HIDDEN struct listnode __android_log_readers;
+
+#if defined(_WIN32)
+#define logger_list_rdlock()
+#define logger_list_wrlock()
+#define logger_list_unlock()
+#else
+LIBLOG_HIDDEN pthread_rwlock_t __android_log_readers_lock;
+
+#define logger_list_rdlock() pthread_rwlock_rdlock(&__android_log_readers_lock)
+#define logger_list_wrlock() pthread_rwlock_wrlock(&__android_log_readers_lock)
+#define logger_list_unlock() pthread_rwlock_unlock(&__android_log_readers_lock)
+#endif
+
+/* Must be called with logger_list_rdlock() or logger_list_wrlock() held */
+#define logger_list_for_each(logger_list) \
+ for ((logger_list) = node_to_item(&__android_log_readers, \
+ struct android_log_logger_list, node); \
+ (logger_list) != node_to_item(&__android_log_readers, \
+ struct android_log_logger_list, node) && \
+ (logger_list) != node_to_item((logger_list)->node.next, \
+ struct android_log_logger_list, node); \
+ (logger_list) = node_to_item((logger_list)->node.next, \
+ struct android_log_logger_list, node))
/* OS specific dribs and drabs */
#if defined(_WIN32)
#include <private/android_filesystem_config.h>
typedef uint32_t uid_t;
-static inline uid_t __android_log_uid() { return AID_SYSTEM; }
+static inline uid_t __android_log_uid() {
+ return AID_SYSTEM;
+}
#else
-static inline uid_t __android_log_uid() { return getuid(); }
+static inline uid_t __android_log_uid() {
+ return getuid();
+}
#endif
LIBLOG_HIDDEN void __android_log_lock();
LIBLOG_HIDDEN int __android_log_trylock();
LIBLOG_HIDDEN void __android_log_unlock();
+LIBLOG_HIDDEN int __android_log_transport;
+
__END_DECLS
#endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_lock.c b/liblog/logger_lock.c
index 14feee0..d4e3a75 100644
--- a/liblog/logger_lock.c
+++ b/liblog/logger_lock.c
@@ -28,29 +28,26 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
-LIBLOG_HIDDEN void __android_log_lock()
-{
+LIBLOG_HIDDEN void __android_log_lock() {
#if !defined(_WIN32)
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&log_init_lock);
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ pthread_mutex_lock(&log_init_lock);
#endif
}
-LIBLOG_HIDDEN int __android_log_trylock()
-{
+LIBLOG_HIDDEN int __android_log_trylock() {
#if !defined(_WIN32)
- return pthread_mutex_trylock(&log_init_lock);
+ return pthread_mutex_trylock(&log_init_lock);
#else
- return 0;
+ return 0;
#endif
}
-LIBLOG_HIDDEN void __android_log_unlock()
-{
+LIBLOG_HIDDEN void __android_log_unlock() {
#if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
+ pthread_mutex_unlock(&log_init_lock);
#endif
}
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
index 5c4feaf..a5a83e0 100644
--- a/liblog/logger_name.c
+++ b/liblog/logger_name.c
@@ -21,44 +21,44 @@
#include "log_portability.h"
/* In the future, we would like to make this list extensible */
-static const char *LOG_NAME[LOG_ID_MAX] = {
- [LOG_ID_MAIN] = "main",
- [LOG_ID_RADIO] = "radio",
- [LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash",
- [LOG_ID_SECURITY] = "security",
- [LOG_ID_KERNEL] = "kernel",
+static const char* LOG_NAME[LOG_ID_MAX] = {
+ /* clang-format off */
+ [LOG_ID_MAIN] = "main",
+ [LOG_ID_RADIO] = "radio",
+ [LOG_ID_EVENTS] = "events",
+ [LOG_ID_SYSTEM] = "system",
+ [LOG_ID_CRASH] = "crash",
+ [LOG_ID_SECURITY] = "security",
+ [LOG_ID_KERNEL] = "kernel",
+ /* clang-format on */
};
-LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
-{
- if (log_id >= LOG_ID_MAX) {
- log_id = LOG_ID_MAIN;
- }
- return LOG_NAME[log_id];
+LIBLOG_ABI_PUBLIC const char* android_log_id_to_name(log_id_t log_id) {
+ if (log_id >= LOG_ID_MAX) {
+ log_id = LOG_ID_MAIN;
+ }
+ return LOG_NAME[log_id];
}
-LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
-{
- const char *b;
- int ret;
+LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char* logName) {
+ const char* b;
+ int ret;
- if (!logName) {
- return -1; /* NB: log_id_t is unsigned */
- }
- b = strrchr(logName, '/');
- if (!b) {
- b = logName;
- } else {
- ++b;
- }
+ if (!logName) {
+ return -1; /* NB: log_id_t is unsigned */
+ }
+ b = strrchr(logName, '/');
+ if (!b) {
+ b = logName;
+ } else {
+ ++b;
+ }
- for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
- const char *l = LOG_NAME[ret];
- if (l && !strcmp(b, l)) {
- return ret;
- }
+ for (ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+ const char* l = LOG_NAME[ret];
+ if (l && !strcmp(b, l)) {
+ return ret;
}
- return -1; /* should never happen */
+ }
+ return -1; /* should never happen */
}
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index c3cb7ad..0fd6efa 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -33,135 +33,128 @@
/* android_logger_alloc unimplemented, no use case */
/* android_logger_free not exported */
-static void android_logger_free(struct logger *logger)
-{
- struct android_log_logger *logger_internal =
- (struct android_log_logger *)logger;
+static void android_logger_free(struct logger* logger) {
+ struct android_log_logger* logger_internal =
+ (struct android_log_logger*)logger;
- if (!logger_internal) {
- return;
- }
+ if (!logger_internal) {
+ return;
+ }
- list_remove(&logger_internal->node);
+ list_remove(&logger_internal->node);
- free(logger_internal);
+ free(logger_internal);
}
/* android_logger_alloc unimplemented, no use case */
/* method for getting the associated sublog id */
-LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
-{
- return ((struct android_log_logger *)logger)->logId;
+LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger* logger) {
+ return ((struct android_log_logger*)logger)->logId;
}
-static int init_transport_context(struct android_log_logger_list *logger_list)
-{
- struct android_log_transport_read *transport;
- struct listnode *node;
+static int init_transport_context(struct android_log_logger_list* logger_list) {
+ struct android_log_transport_read* transport;
+ struct listnode* node;
- if (!logger_list) {
- return -EINVAL;
- }
+ if (!logger_list) {
+ return -EINVAL;
+ }
- if (list_empty(&logger_list->logger)) {
- return -EINVAL;
- }
+ if (list_empty(&logger_list->logger)) {
+ return -EINVAL;
+ }
- if (!list_empty(&logger_list->transport)) {
- return 0;
- }
-
- __android_log_lock();
- /* mini __write_to_log_initialize() to populate transports */
- if (list_empty(&__android_log_transport_read) &&
- list_empty(&__android_log_persist_read)) {
- __android_log_config_read();
- }
- __android_log_unlock();
-
- node = (logger_list->mode & ANDROID_LOG_PSTORE) ?
- &__android_log_persist_read : &__android_log_transport_read;
-
- read_transport_for_each(transport, node) {
- struct android_log_transport_context *transp;
- struct android_log_logger *logger;
- unsigned logMask = 0;
-
- logger_for_each(logger, logger_list) {
- log_id_t logId = logger->logId;
-
- if ((logId == LOG_ID_SECURITY) &&
- (__android_log_uid() != AID_SYSTEM)) {
- continue;
- }
- if (transport->read &&
- (!transport->available ||
- (transport->available(logId) >= 0))) {
- logMask |= 1 << logId;
- }
- }
- if (!logMask) {
- continue;
- }
- transp = calloc(1, sizeof(*transp));
- if (!transp) {
- return -ENOMEM;
- }
- transp->parent = logger_list;
- transp->transport = transport;
- transp->logMask = logMask;
- transp->ret = 1;
- list_add_tail(&logger_list->transport, &transp->node);
- }
- if (list_empty(&logger_list->transport)) {
- return -ENODEV;
- }
+ if (!list_empty(&logger_list->transport)) {
return 0;
+ }
+
+ __android_log_lock();
+ /* mini __write_to_log_initialize() to populate transports */
+ if (list_empty(&__android_log_transport_read) &&
+ list_empty(&__android_log_persist_read)) {
+ __android_log_config_read();
+ }
+ __android_log_unlock();
+
+ node = (logger_list->mode & ANDROID_LOG_PSTORE)
+ ? &__android_log_persist_read
+ : &__android_log_transport_read;
+
+ read_transport_for_each(transport, node) {
+ struct android_log_transport_context* transp;
+ struct android_log_logger* logger;
+ unsigned logMask = 0;
+
+ logger_for_each(logger, logger_list) {
+ log_id_t logId = logger->logId;
+
+ if ((logId == LOG_ID_SECURITY) && (__android_log_uid() != AID_SYSTEM)) {
+ continue;
+ }
+ if (transport->read &&
+ (!transport->available || (transport->available(logId) >= 0))) {
+ logMask |= 1 << logId;
+ }
+ }
+ if (!logMask) {
+ continue;
+ }
+ transp = calloc(1, sizeof(*transp));
+ if (!transp) {
+ return -ENOMEM;
+ }
+ transp->parent = logger_list;
+ transp->transport = transport;
+ transp->logMask = logMask;
+ transp->ret = 1;
+ list_add_tail(&logger_list->transport, &transp->node);
+ }
+ if (list_empty(&logger_list->transport)) {
+ return -ENODEV;
+ }
+ return 0;
}
-#define LOGGER_FUNCTION(logger, def, func, args...) \
- ssize_t ret = -EINVAL; \
- struct android_log_transport_context *transp; \
- struct android_log_logger *logger_internal = \
- (struct android_log_logger *)(logger); \
- \
- if (!logger_internal) { \
- return ret; \
- } \
- ret = init_transport_context(logger_internal->parent); \
- if (ret < 0) { \
- return ret; \
- } \
- \
- ret = (def); \
- transport_context_for_each(transp, logger_internal->parent) { \
- if ((transp->logMask & (1 << logger_internal->logId)) && \
- transp->transport && transp->transport->func) { \
- ssize_t retval = (transp->transport->func)(logger_internal, \
- transp, ## args); \
- if ((ret >= 0) || (ret == (def))) { \
- ret = retval; \
- } \
- } \
- } \
- return ret
+#define LOGGER_FUNCTION(logger, def, func, args...) \
+ ssize_t ret = -EINVAL; \
+ struct android_log_transport_context* transp; \
+ struct android_log_logger* logger_internal = \
+ (struct android_log_logger*)(logger); \
+ \
+ if (!logger_internal) { \
+ return ret; \
+ } \
+ ret = init_transport_context(logger_internal->parent); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ \
+ ret = (def); \
+ transport_context_for_each(transp, logger_internal->parent) { \
+ if ((transp->logMask & (1 << logger_internal->logId)) && \
+ transp->transport && transp->transport->func) { \
+ ssize_t retval = \
+ (transp->transport->func)(logger_internal, transp, ##args); \
+ if ((ret >= 0) || (ret == (def))) { \
+ ret = retval; \
+ } \
+ } \
+ } \
+ return ret
-LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
-{
- LOGGER_FUNCTION(logger, -ENODEV, clear);
+LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger* logger) {
+ LOGGER_FUNCTION(logger, -ENODEV, clear);
}
/* returns the total size of the log's ring buffer */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
-{
- LOGGER_FUNCTION(logger, -ENODEV, getSize);
+LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger* logger) {
+ LOGGER_FUNCTION(logger, -ENODEV, getSize);
}
-LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
- unsigned long size)
-{
- LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
+LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger* logger,
+ unsigned long size) {
+ LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
}
/*
@@ -169,357 +162,338 @@
* log consumed)
*/
LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
- struct logger *logger)
-{
- LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
+ struct logger* logger) {
+ LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
}
/*
* returns the logger version
*/
-LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger)
-{
- LOGGER_FUNCTION(logger, 4, version);
+LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger* logger) {
+ LOGGER_FUNCTION(logger, 4, version);
}
-#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
- struct android_log_transport_context *transp; \
- struct android_log_logger_list *logger_list_internal = \
- (struct android_log_logger_list *)(logger_list); \
- \
- ssize_t ret = init_transport_context(logger_list_internal); \
- if (ret < 0) { \
- return ret; \
- } \
- \
- ret = (def); \
- transport_context_for_each(transp, logger_list_internal) { \
- if (transp->transport && (transp->transport->func)) { \
- ssize_t retval = (transp->transport->func)(logger_list_internal, \
- transp, ## args); \
- if ((ret >= 0) || (ret == (def))) { \
- ret = retval; \
- } \
- } \
- } \
- return ret
+#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
+ struct android_log_transport_context* transp; \
+ struct android_log_logger_list* logger_list_internal = \
+ (struct android_log_logger_list*)(logger_list); \
+ \
+ ssize_t ret = init_transport_context(logger_list_internal); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ \
+ ret = (def); \
+ transport_context_for_each(transp, logger_list_internal) { \
+ if (transp->transport && (transp->transport->func)) { \
+ ssize_t retval = \
+ (transp->transport->func)(logger_list_internal, transp, ##args); \
+ if ((ret >= 0) || (ret == (def))) { \
+ ret = retval; \
+ } \
+ } \
+ } \
+ return ret
/*
* returns statistics
*/
LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
- struct logger_list *logger_list,
- char *buf, size_t len)
-{
- LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
+ struct logger_list* logger_list, char* buf, size_t len) {
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
}
LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
- struct logger_list *logger_list,
- char *buf, size_t len)
-{
- LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
+ struct logger_list* logger_list, char* buf, size_t len) {
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
}
LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
- struct logger_list *logger_list,
- char *buf, size_t len)
-{
- LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
+ struct logger_list* logger_list, char* buf, size_t len) {
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
}
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
- int mode,
- unsigned int tail,
- pid_t pid)
-{
- struct android_log_logger_list *logger_list;
+LIBLOG_HIDDEN struct listnode __android_log_readers = { &__android_log_readers,
+ &__android_log_readers };
+#if !defined(_WIN32)
+LIBLOG_HIDDEN pthread_rwlock_t __android_log_readers_lock =
+ PTHREAD_RWLOCK_INITIALIZER;
+#endif
- logger_list = calloc(1, sizeof(*logger_list));
- if (!logger_list) {
- return NULL;
- }
+LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_alloc(
+ int mode, unsigned int tail, pid_t pid) {
+ struct android_log_logger_list* logger_list;
- list_init(&logger_list->logger);
- list_init(&logger_list->transport);
- logger_list->mode = mode;
- logger_list->tail = tail;
- logger_list->pid = pid;
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
- return (struct logger_list *)logger_list;
+ list_init(&logger_list->logger);
+ list_init(&logger_list->transport);
+ logger_list->mode = mode;
+ logger_list->tail = tail;
+ logger_list->pid = pid;
+
+ logger_list_wrlock();
+ list_add_tail(&__android_log_readers, &logger_list->node);
+ logger_list_unlock();
+
+ return (struct logger_list*)logger_list;
}
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
- int mode,
- log_time start,
- pid_t pid)
-{
- struct android_log_logger_list *logger_list;
+LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_alloc_time(
+ int mode, log_time start, pid_t pid) {
+ struct android_log_logger_list* logger_list;
- logger_list = calloc(1, sizeof(*logger_list));
- if (!logger_list) {
- return NULL;
- }
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
- list_init(&logger_list->logger);
- list_init(&logger_list->transport);
- logger_list->mode = mode;
- logger_list->start = start;
- logger_list->pid = pid;
+ list_init(&logger_list->logger);
+ list_init(&logger_list->transport);
+ logger_list->mode = mode;
+ logger_list->start = start;
+ logger_list->pid = pid;
- return (struct logger_list *)logger_list;
+ logger_list_wrlock();
+ list_add_tail(&__android_log_readers, &logger_list->node);
+ logger_list_unlock();
+
+ return (struct logger_list*)logger_list;
}
/* android_logger_list_register unimplemented, no use case */
/* android_logger_list_unregister unimplemented, no use case */
/* Open the named log and add it to the logger list */
-LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
- struct logger_list *logger_list,
- log_id_t logId)
-{
- struct android_log_logger_list *logger_list_internal =
- (struct android_log_logger_list *)logger_list;
- struct android_log_logger *logger;
+LIBLOG_ABI_PUBLIC struct logger* android_logger_open(
+ struct logger_list* logger_list, log_id_t logId) {
+ struct android_log_logger_list* logger_list_internal =
+ (struct android_log_logger_list*)logger_list;
+ struct android_log_logger* logger;
- if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
- goto err;
+ if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
+ goto err;
+ }
+
+ logger_for_each(logger, logger_list_internal) {
+ if (logger->logId == logId) {
+ goto ok;
}
+ }
- logger_for_each(logger, logger_list_internal) {
- if (logger->logId == logId) {
- goto ok;
- }
- }
+ logger = calloc(1, sizeof(*logger));
+ if (!logger) {
+ goto err;
+ }
- logger = calloc(1, sizeof(*logger));
- if (!logger) {
- goto err;
- }
+ logger->logId = logId;
+ list_add_tail(&logger_list_internal->logger, &logger->node);
+ logger->parent = logger_list_internal;
- logger->logId = logId;
- list_add_tail(&logger_list_internal->logger, &logger->node);
- logger->parent = logger_list_internal;
+ /* Reset known transports to re-evaluate, we just added one */
+ while (!list_empty(&logger_list_internal->transport)) {
+ struct listnode* node = list_head(&logger_list_internal->transport);
+ struct android_log_transport_context* transp =
+ node_to_item(node, struct android_log_transport_context, node);
- /* Reset known transports to re-evaluate, we just added one */
- while (!list_empty(&logger_list_internal->transport)) {
- struct listnode *node = list_head(&logger_list_internal->transport);
- struct android_log_transport_context *transp =
- node_to_item(node, struct android_log_transport_context, node);
-
- list_remove(&transp->node);
- free(transp);
- }
- goto ok;
+ list_remove(&transp->node);
+ free(transp);
+ }
+ goto ok;
err:
- logger = NULL;
+ logger = NULL;
ok:
- return (struct logger *)logger;
+ return (struct logger*)logger;
}
/* Open the single named log and make it part of a new logger list */
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
- log_id_t logId,
- int mode,
- unsigned int tail,
- pid_t pid)
-{
- struct logger_list *logger_list =
- android_logger_list_alloc(mode, tail, pid);
+LIBLOG_ABI_PUBLIC struct logger_list* android_logger_list_open(
+ log_id_t logId, int mode, unsigned int tail, pid_t pid) {
+ struct logger_list* logger_list = android_logger_list_alloc(mode, tail, pid);
- if (!logger_list) {
- return NULL;
- }
+ if (!logger_list) {
+ return NULL;
+ }
- if (!android_logger_open(logger_list, logId)) {
- android_logger_list_free(logger_list);
- return NULL;
- }
+ if (!android_logger_open(logger_list, logId)) {
+ android_logger_list_free(logger_list);
+ return NULL;
+ }
- return logger_list;
+ return logger_list;
}
/* Validate log_msg packet, read function has already been null checked */
-static int android_transport_read(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg)
-{
- int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+static int android_transport_read(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg) {
+ int ret = (*transp->transport->read)(logger_list, transp, log_msg);
- if (ret > (int)sizeof(*log_msg)) {
- ret = sizeof(*log_msg);
+ if (ret > (int)sizeof(*log_msg)) {
+ ret = sizeof(*log_msg);
+ }
+
+ transp->ret = ret;
+
+ /* propagate errors, or make sure len & hdr_size members visible */
+ if (ret < (int)(sizeof(log_msg->entry.len) + sizeof(log_msg->entry.hdr_size))) {
+ if (ret >= (int)sizeof(log_msg->entry.len)) {
+ log_msg->entry.len = 0;
}
-
- transp->ret = ret;
-
- /* propagate errors, or make sure len & hdr_size members visible */
- if (ret < (int)(sizeof(log_msg->entry.len) +
- sizeof(log_msg->entry.hdr_size))) {
- if (ret >= (int)sizeof(log_msg->entry.len)) {
- log_msg->entry.len = 0;
- }
- return ret;
- }
-
- /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
- if (log_msg->entry_v2.hdr_size == 0) {
- log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
- }
- if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
- (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
- return -EINVAL;
- }
-
- /* len validation */
- if (ret <= log_msg->entry_v2.hdr_size) {
- log_msg->entry.len = 0;
- } else {
- log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
- }
-
return ret;
+ }
+
+ /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+ if (log_msg->entry_v2.hdr_size == 0) {
+ log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+ }
+ if ((log_msg->entry_v2.hdr_size < sizeof(log_msg->entry_v1)) ||
+ (log_msg->entry_v2.hdr_size > sizeof(log_msg->entry))) {
+ return -EINVAL;
+ }
+
+ /* len validation */
+ if (ret <= log_msg->entry_v2.hdr_size) {
+ log_msg->entry.len = 0;
+ } else {
+ log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+ }
+
+ return ret;
}
/* Read from the selected logs */
-LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
- struct log_msg *log_msg)
-{
- struct android_log_transport_context *transp;
- struct android_log_logger_list *logger_list_internal =
- (struct android_log_logger_list *)logger_list;
+LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list* logger_list,
+ struct log_msg* log_msg) {
+ struct android_log_transport_context* transp;
+ struct android_log_logger_list* logger_list_internal =
+ (struct android_log_logger_list*)logger_list;
- int ret = init_transport_context(logger_list_internal);
- if (ret < 0) {
- return ret;
- }
+ int ret = init_transport_context(logger_list_internal);
+ if (ret < 0) {
+ return ret;
+ }
- /* at least one transport */
- transp = node_to_item(logger_list_internal->transport.next,
- struct android_log_transport_context, node);
+ /* at least one transport */
+ transp = node_to_item(logger_list_internal->transport.next,
+ struct android_log_transport_context, node);
- /* more than one transport? */
- if (transp->node.next != &logger_list_internal->transport) {
- /* Poll and merge sort the entries if from multiple transports */
- struct android_log_transport_context *oldest = NULL;
- int ret;
- int polled = 0;
- do {
- if (polled) {
- sched_yield();
+ /* more than one transport? */
+ if (transp->node.next != &logger_list_internal->transport) {
+ /* Poll and merge sort the entries if from multiple transports */
+ struct android_log_transport_context* oldest = NULL;
+ int ret;
+ int polled = 0;
+ do {
+ if (polled) {
+ sched_yield();
+ }
+ ret = -1000;
+ polled = 0;
+ do {
+ int retval = transp->ret;
+ if ((retval > 0) && !transp->logMsg.entry.len) {
+ if (!transp->transport->read) {
+ retval = transp->ret = 0;
+ } else if ((logger_list_internal->mode & ANDROID_LOG_NONBLOCK) ||
+ !transp->transport->poll) {
+ retval = android_transport_read(logger_list_internal, transp,
+ &transp->logMsg);
+ } else {
+ int pollval =
+ (*transp->transport->poll)(logger_list_internal, transp);
+ if (pollval <= 0) {
+ sched_yield();
+ pollval = (*transp->transport->poll)(logger_list_internal, transp);
}
- ret = -1000;
- polled = 0;
- do {
- int retval = transp->ret;
- if ((retval > 0) && !transp->logMsg.entry.len) {
- if (!transp->transport->read) {
- retval = transp->ret = 0;
- } else if ((logger_list_internal->mode &
- ANDROID_LOG_NONBLOCK) ||
- !transp->transport->poll) {
- retval = android_transport_read(
- logger_list_internal,
- transp,
- &transp->logMsg);
- } else {
- int pollval = (*transp->transport->poll)(
- logger_list_internal, transp);
- if (pollval <= 0) {
- sched_yield();
- pollval = (*transp->transport->poll)(
- logger_list_internal, transp);
- }
- polled = 1;
- if (pollval < 0) {
- if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
- return -EAGAIN;
- }
- retval = transp->ret = pollval;
- } else if (pollval > 0) {
- retval = android_transport_read(
- logger_list_internal,
- transp,
- &transp->logMsg);
- }
- }
- }
- if (ret < retval) {
- ret = retval;
- }
- if ((transp->ret > 0) && transp->logMsg.entry.len &&
- (!oldest ||
- (oldest->logMsg.entry.sec >
- transp->logMsg.entry.sec) ||
- ((oldest->logMsg.entry.sec ==
- transp->logMsg.entry.sec) &&
- (oldest->logMsg.entry.nsec >
- transp->logMsg.entry.nsec)))) {
- oldest = transp;
- }
- transp = node_to_item(transp->node.next,
+ polled = 1;
+ if (pollval < 0) {
+ if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
+ return -EAGAIN;
+ }
+ retval = transp->ret = pollval;
+ } else if (pollval > 0) {
+ retval = android_transport_read(logger_list_internal, transp,
+ &transp->logMsg);
+ }
+ }
+ }
+ if (ret < retval) {
+ ret = retval;
+ }
+ if ((transp->ret > 0) && transp->logMsg.entry.len &&
+ (!oldest || (oldest->logMsg.entry.sec > transp->logMsg.entry.sec) ||
+ ((oldest->logMsg.entry.sec == transp->logMsg.entry.sec) &&
+ (oldest->logMsg.entry.nsec > transp->logMsg.entry.nsec)))) {
+ oldest = transp;
+ }
+ transp = node_to_item(transp->node.next,
+ struct android_log_transport_context, node);
+ } while (transp != node_to_item(&logger_list_internal->transport,
struct android_log_transport_context,
- node);
- } while (transp != node_to_item(
- &logger_list_internal->transport,
- struct android_log_transport_context,
- node));
- if (!oldest &&
- (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
- return (ret < 0) ? ret : -EAGAIN;
- }
- transp = node_to_item(logger_list_internal->transport.next,
- struct android_log_transport_context, node);
- } while (!oldest && (ret > 0));
- if (!oldest) {
- return ret;
- }
- // ret is a positive value less than sizeof(struct log_msg)
- ret = oldest->ret;
- if (ret < oldest->logMsg.entry.hdr_size) {
- // zero truncated header fields.
- memset(log_msg, 0,
- (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
- sizeof(oldest->logMsg) :
- oldest->logMsg.entry.hdr_size));
- }
- memcpy(log_msg, &oldest->logMsg, ret);
- oldest->logMsg.entry.len = 0; /* Mark it as copied */
- return ret;
+ node));
+ if (!oldest && (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
+ return (ret < 0) ? ret : -EAGAIN;
+ }
+ transp = node_to_item(logger_list_internal->transport.next,
+ struct android_log_transport_context, node);
+ } while (!oldest && (ret > 0));
+ if (!oldest) {
+ return ret;
}
+ // ret is a positive value less than sizeof(struct log_msg)
+ ret = oldest->ret;
+ if (ret < oldest->logMsg.entry.hdr_size) {
+ // zero truncated header fields.
+ memset(log_msg, 0,
+ (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg)
+ ? sizeof(oldest->logMsg)
+ : oldest->logMsg.entry.hdr_size));
+ }
+ memcpy(log_msg, &oldest->logMsg, ret);
+ oldest->logMsg.entry.len = 0; /* Mark it as copied */
+ return ret;
+ }
- /* if only one, no need to copy into transport_context and merge-sort */
- return android_transport_read(logger_list_internal, transp, log_msg);
+ /* if only one, no need to copy into transport_context and merge-sort */
+ return android_transport_read(logger_list_internal, transp, log_msg);
}
/* Close all the logs */
-LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
-{
- struct android_log_logger_list *logger_list_internal =
- (struct android_log_logger_list *)logger_list;
+LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list* logger_list) {
+ struct android_log_logger_list* logger_list_internal =
+ (struct android_log_logger_list*)logger_list;
- if (logger_list_internal == NULL) {
- return;
+ if (logger_list_internal == NULL) {
+ return;
+ }
+
+ logger_list_wrlock();
+ list_remove(&logger_list_internal->node);
+ logger_list_unlock();
+
+ while (!list_empty(&logger_list_internal->transport)) {
+ struct listnode* node = list_head(&logger_list_internal->transport);
+ struct android_log_transport_context* transp =
+ node_to_item(node, struct android_log_transport_context, node);
+
+ if (transp->transport && transp->transport->close) {
+ (*transp->transport->close)(logger_list_internal, transp);
}
+ list_remove(&transp->node);
+ free(transp);
+ }
- while (!list_empty(&logger_list_internal->transport)) {
- struct listnode *node = list_head(&logger_list_internal->transport);
- struct android_log_transport_context *transp =
- node_to_item(node, struct android_log_transport_context, node);
+ while (!list_empty(&logger_list_internal->logger)) {
+ struct listnode* node = list_head(&logger_list_internal->logger);
+ struct android_log_logger* logger =
+ node_to_item(node, struct android_log_logger, node);
+ android_logger_free((struct logger*)logger);
+ }
- if (transp->transport && transp->transport->close) {
- (*transp->transport->close)(logger_list_internal, transp);
- }
- list_remove(&transp->node);
- free(transp);
- }
-
- while (!list_empty(&logger_list_internal->logger)) {
- struct listnode *node = list_head(&logger_list_internal->logger);
- struct android_log_logger *logger =
- node_to_item(node, struct android_log_logger, node);
- android_logger_free((struct logger *)logger);
- }
-
- free(logger_list_internal);
+ free(logger_list_internal);
}
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 4324125..d322c0f 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -25,17 +25,20 @@
#endif
#include <log/event_tag_map.h>
+#include <log/log_transport.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#include "config_read.h" /* __android_log_config_read_close() definition */
#include "config_write.h"
#include "log_portability.h"
#include "logger.h"
#define LOG_BUF_SIZE 1024
-static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+static int __write_to_log_init(log_id_t, struct iovec* vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec* vec,
+ size_t nr) = __write_to_log_init;
/*
* This is used by the C++ code to decide if it should write logs through
@@ -43,91 +46,84 @@
* the simulator rather than a desktop tool and want to use the device.
*/
static enum {
- kLogUninitialized, kLogNotAvailable, kLogAvailable
+ kLogUninitialized,
+ kLogNotAvailable,
+ kLogAvailable
} g_log_status = kLogUninitialized;
-static int check_log_uid_permissions()
-{
+static int check_log_uid_permissions() {
#if defined(__ANDROID__)
- uid_t uid = __android_log_uid();
+ uid_t uid = __android_log_uid();
- /* Matches clientHasLogCredentials() in logd */
+ /* Matches clientHasLogCredentials() in logd */
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+ uid = geteuid();
if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- uid = geteuid();
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- gid_t gid = getgid();
- if ((gid != AID_SYSTEM) &&
- (gid != AID_ROOT) &&
- (gid != AID_LOG)) {
- gid = getegid();
- if ((gid != AID_SYSTEM) &&
- (gid != AID_ROOT) &&
- (gid != AID_LOG)) {
- int num_groups;
- gid_t *groups;
+ gid_t gid = getgid();
+ if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+ gid = getegid();
+ if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+ int num_groups;
+ gid_t* groups;
- num_groups = getgroups(0, NULL);
- if (num_groups <= 0) {
- return -EPERM;
- }
- groups = calloc(num_groups, sizeof(gid_t));
- if (!groups) {
- return -ENOMEM;
- }
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- free(groups);
- if (num_groups <= 0) {
- return -EPERM;
- }
- }
+ num_groups = getgroups(0, NULL);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
+ groups = calloc(num_groups, sizeof(gid_t));
+ if (!groups) {
+ return -ENOMEM;
+ }
+ num_groups = getgroups(num_groups, groups);
+ while (num_groups > 0) {
+ if (groups[num_groups - 1] == AID_LOG) {
+ break;
}
+ --num_groups;
+ }
+ free(groups);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
}
+ }
}
+ }
#endif
- return 0;
+ return 0;
}
static void __android_log_cache_available(
- struct android_log_transport_write *node)
-{
- size_t i;
+ struct android_log_transport_write* node) {
+ size_t i;
- if (node->logMask) {
- return;
- }
+ if (node->logMask) {
+ return;
+ }
- for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- if (node->write &&
- (i != LOG_ID_KERNEL) &&
- ((i != LOG_ID_SECURITY) ||
- (check_log_uid_permissions() == 0)) &&
- (!node->available || ((*node->available)(i) >= 0))) {
- node->logMask |= 1 << i;
- }
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ if (node->write && (i != LOG_ID_KERNEL) &&
+ ((i != LOG_ID_SECURITY) || (check_log_uid_permissions() == 0)) &&
+ (!node->available || ((*node->available)(i) >= 0))) {
+ node->logMask |= 1 << i;
}
+ }
}
-LIBLOG_ABI_PUBLIC int __android_log_dev_available()
-{
- struct android_log_transport_write *node;
+LIBLOG_ABI_PUBLIC int __android_log_dev_available() {
+ struct android_log_transport_write* node;
- if (list_empty(&__android_log_transport_write)) {
- return kLogUninitialized;
- }
+ if (list_empty(&__android_log_transport_write)) {
+ return kLogUninitialized;
+ }
- write_transport_for_each(node, &__android_log_transport_write) {
- __android_log_cache_available(node);
- if (node->logMask) {
- return kLogAvailable;
- }
+ write_transport_for_each(node, &__android_log_transport_write) {
+ __android_log_cache_available(node);
+ if (node->logMask) {
+ return kLogAvailable;
}
- return kLogNotAvailable;
+ }
+ return kLogNotAvailable;
}
#if defined(__ANDROID__)
@@ -137,421 +133,400 @@
/*
* Release any logger resources. A new log write will immediately re-acquire.
*/
-LIBLOG_ABI_PUBLIC void __android_log_close()
-{
- struct android_log_transport_write *transport;
+LIBLOG_ABI_PUBLIC void __android_log_close() {
+ struct android_log_transport_write* transport;
#if defined(__ANDROID__)
- EventTagMap *m;
+ EventTagMap* m;
#endif
- __android_log_lock();
+ __android_log_lock();
- write_to_log = __write_to_log_init;
+ write_to_log = __write_to_log_init;
- /*
- * Threads that are actively writing at this point are not held back
- * by a lock and are at risk of dropping the messages with a return code
- * -EBADF. Prefer to return error code than add the overhead of a lock to
- * each log writing call to guarantee delivery. In addition, anyone
- * calling this is doing so to release the logging resources and shut down,
- * for them to do so with outstanding log requests in other threads is a
- * disengenuous use of this function.
- */
+ /*
+ * Threads that are actively writing at this point are not held back
+ * by a lock and are at risk of dropping the messages with a return code
+ * -EBADF. Prefer to return error code than add the overhead of a lock to
+ * each log writing call to guarantee delivery. In addition, anyone
+ * calling this is doing so to release the logging resources and shut down,
+ * for them to do so with outstanding log requests in other threads is a
+ * disengenuous use of this function.
+ */
- write_transport_for_each(transport, &__android_log_persist_write) {
- if (transport->close) {
- (*transport->close)();
- }
+ write_transport_for_each(transport, &__android_log_persist_write) {
+ if (transport->close) {
+ (*transport->close)();
}
+ }
- write_transport_for_each(transport, &__android_log_transport_write) {
- if (transport->close) {
- (*transport->close)();
- }
+ write_transport_for_each(transport, &__android_log_transport_write) {
+ if (transport->close) {
+ (*transport->close)();
}
+ }
+
+ __android_log_config_write_close();
#if defined(__ANDROID__)
- /*
- * Additional risk here somewhat mitigated by immediately unlock flushing
- * the processor cache. The multi-threaded race that we choose to accept,
- * to minimize locking, is an atomic_load in a writer picking up a value
- * just prior to entering this routine. There will be an use after free.
- *
- * Again, anyone calling this is doing so to release the logging resources
- * is most probably going to quiesce then shut down; or to restart after
- * a fork so the risk should be non-existent. For this reason we
- * choose a mitigation stance for efficiency instead of incuring the cost
- * of a lock for every log write.
- */
- m = (EventTagMap *)atomic_exchange(&tagMap, (uintptr_t)0);
+ /*
+ * Additional risk here somewhat mitigated by immediately unlock flushing
+ * the processor cache. The multi-threaded race that we choose to accept,
+ * to minimize locking, is an atomic_load in a writer picking up a value
+ * just prior to entering this routine. There will be an use after free.
+ *
+ * Again, anyone calling this is doing so to release the logging resources
+ * is most probably going to quiesce then shut down; or to restart after
+ * a fork so the risk should be non-existent. For this reason we
+ * choose a mitigation stance for efficiency instead of incuring the cost
+ * of a lock for every log write.
+ */
+ m = (EventTagMap*)atomic_exchange(&tagMap, (uintptr_t)0);
#endif
- __android_log_unlock();
+ __android_log_unlock();
#if defined(__ANDROID__)
- if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
+ if (m != (EventTagMap*)(uintptr_t)-1LL) android_closeEventTagMap(m);
#endif
-
}
/* log_init_lock assumed */
-static int __write_to_log_initialize()
-{
- struct android_log_transport_write *transport;
- struct listnode *n;
- int i = 0, ret = 0;
+static int __write_to_log_initialize() {
+ struct android_log_transport_write* transport;
+ struct listnode* n;
+ int i = 0, ret = 0;
- __android_log_config_write();
- write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
- __android_log_cache_available(transport);
- if (!transport->logMask) {
- list_remove(&transport->node);
- continue;
- }
- if (!transport->open || ((*transport->open)() < 0)) {
- if (transport->close) {
- (*transport->close)();
- }
- list_remove(&transport->node);
- continue;
- }
- ++ret;
+ __android_log_config_write();
+ write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+ __android_log_cache_available(transport);
+ if (!transport->logMask) {
+ list_remove(&transport->node);
+ continue;
}
- write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
- __android_log_cache_available(transport);
- if (!transport->logMask) {
- list_remove(&transport->node);
- continue;
- }
- if (!transport->open || ((*transport->open)() < 0)) {
- if (transport->close) {
- (*transport->close)();
- }
- list_remove(&transport->node);
- continue;
- }
- ++i;
+ if (!transport->open || ((*transport->open)() < 0)) {
+ if (transport->close) {
+ (*transport->close)();
+ }
+ list_remove(&transport->node);
+ continue;
}
- if (!ret && !i) {
- return -ENODEV;
+ ++ret;
+ }
+ write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+ __android_log_cache_available(transport);
+ if (!transport->logMask) {
+ list_remove(&transport->node);
+ continue;
}
+ if (!transport->open || ((*transport->open)() < 0)) {
+ if (transport->close) {
+ (*transport->close)();
+ }
+ list_remove(&transport->node);
+ continue;
+ }
+ ++i;
+ }
+ if (!ret && !i) {
+ return -ENODEV;
+ }
- return ret;
+ return ret;
}
/*
* Extract a 4-byte value from a byte stream. le32toh open coded
*/
-static inline uint32_t get4LE(const uint8_t* src)
-{
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+static inline uint32_t get4LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
-{
- struct android_log_transport_write *node;
- int ret;
- struct timespec ts;
- size_t len, i;
+static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
+ struct android_log_transport_write* node;
+ int ret;
+ struct timespec ts;
+ size_t len, i;
- for (len = i = 0; i < nr; ++i) {
- len += vec[i].iov_len;
- }
- if (!len) {
- return -EINVAL;
- }
+ for (len = i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+ if (!len) {
+ return -EINVAL;
+ }
#if defined(__ANDROID__)
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(android_log_clockid(), &ts);
- if (log_id == LOG_ID_SECURITY) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
+ if (log_id == LOG_ID_SECURITY) {
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
- ret = check_log_uid_permissions();
- if (ret < 0) {
- return ret;
- }
- if (!__android_log_security()) {
- /* If only we could reset downstream logd counter */
- return -EPERM;
- }
- } else if (log_id == LOG_ID_EVENTS) {
- const char *tag;
- size_t len;
- EventTagMap *m, *f;
+ ret = check_log_uid_permissions();
+ if (ret < 0) {
+ return ret;
+ }
+ if (!__android_log_security()) {
+ /* If only we could reset downstream logd counter */
+ return -EPERM;
+ }
+ } else if (log_id == LOG_ID_EVENTS) {
+ const char* tag;
+ size_t len;
+ EventTagMap *m, *f;
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
- tag = NULL;
- len = 0;
- f = NULL;
- m = (EventTagMap *)atomic_load(&tagMap);
+ tag = NULL;
+ len = 0;
+ f = NULL;
+ m = (EventTagMap*)atomic_load(&tagMap);
- if (!m) {
- ret = __android_log_trylock();
- m = (EventTagMap *)atomic_load(&tagMap); /* trylock flush cache */
- if (!m) {
- m = android_openEventTagMap(NULL);
- if (ret) { /* trylock failed, use local copy, mark for close */
- f = m;
- } else {
- if (!m) { /* One chance to open map file */
- m = (EventTagMap *)(uintptr_t)-1LL;
- }
- atomic_store(&tagMap, (uintptr_t)m);
- }
- }
- if (!ret) { /* trylock succeeded, unlock */
- __android_log_unlock();
- }
+ if (!m) {
+ ret = __android_log_trylock();
+ m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
+ if (!m) {
+ m = android_openEventTagMap(NULL);
+ if (ret) { /* trylock failed, use local copy, mark for close */
+ f = m;
+ } else {
+ if (!m) { /* One chance to open map file */
+ m = (EventTagMap*)(uintptr_t)-1LL;
+ }
+ atomic_store(&tagMap, (uintptr_t)m);
}
- if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
- tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
- }
- ret = __android_log_is_loggable_len(ANDROID_LOG_INFO,
- tag, len,
- ANDROID_LOG_VERBOSE);
- if (f) { /* local copy marked for close */
- android_closeEventTagMap(f);
- }
- if (!ret) {
- return -EPERM;
- }
- } else {
- /* Validate the incoming tag, tag content can not split across iovec */
- char prio = ANDROID_LOG_VERBOSE;
- const char *tag = vec[0].iov_base;
- size_t len = vec[0].iov_len;
+ }
+ if (!ret) { /* trylock succeeded, unlock */
+ __android_log_unlock();
+ }
+ }
+ if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
+ tag = android_lookupEventTag_len(m, &len, get4LE(vec[0].iov_base));
+ }
+ ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
+ ANDROID_LOG_VERBOSE);
+ if (f) { /* local copy marked for close */
+ android_closeEventTagMap(f);
+ }
+ if (!ret) {
+ return -EPERM;
+ }
+ } else {
+ /* Validate the incoming tag, tag content can not split across iovec */
+ char prio = ANDROID_LOG_VERBOSE;
+ const char* tag = vec[0].iov_base;
+ size_t len = vec[0].iov_len;
+ if (!tag) {
+ len = 0;
+ }
+ if (len > 0) {
+ prio = *tag;
+ if (len > 1) {
+ --len;
+ ++tag;
+ } else {
+ len = vec[1].iov_len;
+ tag = ((const char*)vec[1].iov_base);
if (!tag) {
- len = 0;
+ len = 0;
}
- if (len > 0) {
- prio = *tag;
- if (len > 1) {
- --len;
- ++tag;
- } else {
- len = vec[1].iov_len;
- tag = ((const char *)vec[1].iov_base);
- if (!tag) {
- len = 0;
- }
- }
- }
- /* tag must be nul terminated */
- if (strnlen(tag, len) >= len) {
- tag = NULL;
- }
+ }
+ }
+ /* tag must be nul terminated */
+ if (tag && strnlen(tag, len) >= len) {
+ tag = NULL;
+ }
- if (!__android_log_is_loggable_len(prio,
- tag, len - 1,
- ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
+ if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
+ return -EPERM;
}
+ }
#else
- /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
- }
+ /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ }
#endif
- ret = 0;
- i = 1 << log_id;
- write_transport_for_each(node, &__android_log_transport_write) {
- if (node->logMask & i) {
- ssize_t retval;
- retval = (*node->write)(log_id, &ts, vec, nr);
- if (ret >= 0) {
- ret = retval;
- }
- }
+ ret = 0;
+ i = 1 << log_id;
+ write_transport_for_each(node, &__android_log_transport_write) {
+ if (node->logMask & i) {
+ ssize_t retval;
+ retval = (*node->write)(log_id, &ts, vec, nr);
+ if (ret >= 0) {
+ ret = retval;
+ }
}
+ }
- write_transport_for_each(node, &__android_log_persist_write) {
- if (node->logMask & i) {
- (void)(*node->write)(log_id, &ts, vec, nr);
- }
+ write_transport_for_each(node, &__android_log_persist_write) {
+ if (node->logMask & i) {
+ (void)(*node->write)(log_id, &ts, vec, nr);
}
+ }
- return ret;
+ return ret;
}
-static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
-{
- __android_log_lock();
+static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
+ __android_log_lock();
- if (write_to_log == __write_to_log_init) {
- int ret;
+ if (write_to_log == __write_to_log_init) {
+ int ret;
- ret = __write_to_log_initialize();
- if (ret < 0) {
- __android_log_unlock();
- if (!list_empty(&__android_log_persist_write)) {
- __write_to_log_daemon(log_id, vec, nr);
- }
- return ret;
- }
-
- write_to_log = __write_to_log_daemon;
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ __android_log_unlock();
+ if (!list_empty(&__android_log_persist_write)) {
+ __write_to_log_daemon(log_id, vec, nr);
+ }
+ return ret;
}
- __android_log_unlock();
+ write_to_log = __write_to_log_daemon;
+ }
- return write_to_log(log_id, vec, nr);
+ __android_log_unlock();
+
+ return write_to_log(log_id, vec, nr);
}
-LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
- const char *msg)
-{
- return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
+LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char* tag,
+ const char* msg) {
+ return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
}
LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
- const char *tag, const char *msg)
-{
- struct iovec vec[3];
- char tmp_tag[32];
+ const char* tag, const char* msg) {
+ struct iovec vec[3];
+ char tmp_tag[32];
- if (!tag)
- tag = "";
+ if (!tag) tag = "";
- /* XXX: This needs to go! */
- if ((bufID != LOG_ID_RADIO) &&
- (!strcmp(tag, "HTC_RIL") ||
- !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
- !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
- !strcmp(tag, "AT") ||
- !strcmp(tag, "GSM") ||
- !strcmp(tag, "STK") ||
- !strcmp(tag, "CDMA") ||
- !strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS"))) {
- bufID = LOG_ID_RADIO;
- /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
- snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
- tag = tmp_tag;
- }
+ /* XXX: This needs to go! */
+ if ((bufID != LOG_ID_RADIO) &&
+ (!strcmp(tag, "HTC_RIL") ||
+ !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+ !strcmp(tag, "AT") || !strcmp(tag, "GSM") || !strcmp(tag, "STK") ||
+ !strcmp(tag, "CDMA") || !strcmp(tag, "PHONE") || !strcmp(tag, "SMS"))) {
+ bufID = LOG_ID_RADIO;
+ /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+ tag = tmp_tag;
+ }
#if __BIONIC__
- if (prio == ANDROID_LOG_FATAL) {
- android_set_abort_message(msg);
- }
+ if (prio == ANDROID_LOG_FATAL) {
+ android_set_abort_message(msg);
+ }
#endif
- vec[0].iov_base = (unsigned char *)&prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *)tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *)msg;
- vec[2].iov_len = strlen(msg) + 1;
+ vec[0].iov_base = (unsigned char*)&prio;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void*)tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void*)msg;
+ vec[2].iov_len = strlen(msg) + 1;
- return write_to_log(bufID, vec, 3);
+ return write_to_log(bufID, vec, 3);
}
-LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
- const char *fmt, va_list ap)
-{
- char buf[LOG_BUF_SIZE];
+LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char* tag,
+ const char* fmt, va_list ap) {
+ char buf[LOG_BUF_SIZE];
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- return __android_log_write(prio, tag, buf);
+ return __android_log_write(prio, tag, buf);
}
-LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
- const char *fmt, ...)
-{
- va_list ap;
- char buf[LOG_BUF_SIZE];
+LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char* tag,
+ const char* fmt, ...) {
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
- return __android_log_write(prio, tag, buf);
+ return __android_log_write(prio, tag, buf);
}
LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
- const char *tag,
- const char *fmt, ...)
-{
- va_list ap;
- char buf[LOG_BUF_SIZE];
+ const char* tag, const char* fmt,
+ ...) {
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC void __android_log_assert(const char* cond, const char* tag,
+ const char* fmt, ...) {
+ char buf[LOG_BUF_SIZE];
+
+ if (fmt) {
+ va_list ap;
va_start(ap, fmt);
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
va_end(ap);
+ } else {
+ /* Msg not provided, log condition. N.B. Do not use cond directly as
+ * format string as it could contain spurious '%' syntax (e.g.
+ * "%d" in "blocks%devs == 0").
+ */
+ if (cond)
+ snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+ else
+ strcpy(buf, "Unspecified assertion failed");
+ }
- return __android_log_buf_write(bufID, prio, tag, buf);
+ // Log assertion failures to stderr for the benefit of "adb shell" users
+ // and gtests (http://b/23675822).
+ struct iovec iov[2] = {
+ { buf, strlen(buf) }, { (char*)"\n", 1 },
+ };
+ TEMP_FAILURE_RETRY(writev(2, iov, 2));
+
+ __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+ abort(); /* abort so we have a chance to debug the situation */
+ /* NOTREACHED */
}
-LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
-{
- char buf[LOG_BUF_SIZE];
+LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag, const void* payload,
+ size_t len) {
+ struct iovec vec[2];
- if (fmt) {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- } else {
- /* Msg not provided, log condition. N.B. Do not use cond directly as
- * format string as it could contain spurious '%' syntax (e.g.
- * "%d" in "blocks%devs == 0").
- */
- if (cond)
- snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
- else
- strcpy(buf, "Unspecified assertion failed");
- }
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
- // Log assertion failures to stderr for the benefit of "adb shell" users
- // and gtests (http://b/23675822).
- struct iovec iov[2] = {
- { buf, strlen(buf) },
- { (char*) "\n", 1 },
- };
- TEMP_FAILURE_RETRY(writev(2, iov, 2));
-
- __android_log_write(ANDROID_LOG_FATAL, tag, buf);
- abort(); /* abort so we have a chance to debug the situation */
- /* NOTREACHED */
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
- const void *payload, size_t len)
-{
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 2);
+ return write_to_log(LOG_ID_EVENTS, vec, 2);
}
LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
- const void *payload,
- size_t len)
-{
- struct iovec vec[2];
+ const void* payload,
+ size_t len) {
+ struct iovec vec[2];
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
- return write_to_log(LOG_ID_SECURITY, vec, 2);
+ return write_to_log(LOG_ID_SECURITY, vec, 2);
}
/*
@@ -560,40 +535,38 @@
* handy if we just want to dump an integer into the log.
*/
LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
- const void *payload, size_t len)
-{
- struct iovec vec[3];
+ const void* payload, size_t len) {
+ struct iovec vec[3];
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = (void*)payload;
- vec[2].iov_len = len;
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = (void*)payload;
+ vec[2].iov_len = len;
- return write_to_log(LOG_ID_EVENTS, vec, 3);
+ return write_to_log(LOG_ID_EVENTS, vec, 3);
}
/*
* Like __android_log_bwrite, but used for writing strings to the
* event log.
*/
-LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
-{
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
+LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char* payload) {
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
- return write_to_log(LOG_ID_EVENTS, vec, 4);
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
}
/*
@@ -601,20 +574,100 @@
* security log.
*/
LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
- const char *payload)
-{
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
+ const char* payload) {
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
- return write_to_log(LOG_ID_SECURITY, vec, 4);
+ return write_to_log(LOG_ID_SECURITY, vec, 4);
+}
+
+static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr) {
+ size_t len, i;
+
+ if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
+ return -EINVAL;
+ }
+
+ for (len = i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+ if (!len) {
+ return -EINVAL;
+ }
+ return len;
+}
+
+/* Following functions need access to our internal write_to_log status */
+
+LIBLOG_HIDDEN int __android_log_transport;
+
+LIBLOG_ABI_PUBLIC int android_set_log_transport(int transport_flag) {
+ int retval;
+
+ if (transport_flag < 0) {
+ return -EINVAL;
+ }
+
+ retval = LOGGER_NULL;
+
+ __android_log_lock();
+
+ if (transport_flag & LOGGER_NULL) {
+ write_to_log = __write_to_log_null;
+
+ __android_log_unlock();
+
+ return retval;
+ }
+
+ __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
+
+ transport_flag &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
+
+ if (__android_log_transport != transport_flag) {
+ __android_log_transport = transport_flag;
+ __android_log_config_write_close();
+ __android_log_config_read_close();
+
+ write_to_log = __write_to_log_init;
+ /* generically we only expect these two values for write_to_log */
+ } else if ((write_to_log != __write_to_log_init) &&
+ (write_to_log != __write_to_log_daemon)) {
+ write_to_log = __write_to_log_init;
+ }
+
+ retval = __android_log_transport;
+
+ __android_log_unlock();
+
+ return retval;
+}
+
+LIBLOG_ABI_PUBLIC int android_get_log_transport() {
+ int ret = LOGGER_DEFAULT;
+
+ __android_log_lock();
+ if (write_to_log == __write_to_log_null) {
+ ret = LOGGER_NULL;
+ } else {
+ __android_log_transport &= LOGGER_LOCAL | LOGGER_LOGD | LOGGER_STDERR;
+ ret = __android_log_transport;
+ if ((write_to_log != __write_to_log_init) &&
+ (write_to_log != __write_to_log_daemon)) {
+ ret = -EINVAL;
+ }
+ }
+ __android_log_unlock();
+
+ return ret;
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 18af9de..2ade7b0 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -16,13 +16,17 @@
*/
#define _GNU_SOURCE /* for asprintf */
+#ifndef __MINGW32__
+#define HAVE_STRSEP
+#endif
-#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
+#ifndef __MINGW32__
#include <pwd.h>
+#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -40,26 +44,30 @@
#define MS_PER_NSEC 1000000
#define US_PER_NSEC 1000
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
typedef struct FilterInfo_t {
- char *mTag;
- android_LogPriority mPri;
- struct FilterInfo_t *p_next;
+ char* mTag;
+ android_LogPriority mPri;
+ struct FilterInfo_t* p_next;
} FilterInfo;
struct AndroidLogFormat_t {
- android_LogPriority global_pri;
- FilterInfo *filters;
- AndroidLogPrintFormat format;
- bool colored_output;
- bool usec_time_output;
- bool nsec_time_output;
- bool printable_output;
- bool year_output;
- bool zone_output;
- bool epoch_output;
- bool monotonic_output;
- bool uid_output;
- bool descriptive_output;
+ android_LogPriority global_pri;
+ FilterInfo* filters;
+ AndroidLogPrintFormat format;
+ bool colored_output;
+ bool usec_time_output;
+ bool nsec_time_output;
+ bool printable_output;
+ bool year_output;
+ bool zone_output;
+ bool epoch_output;
+ bool monotonic_output;
+ bool uid_output;
+ bool descriptive_output;
};
/*
@@ -75,22 +83,21 @@
* The color manipulation character stream is defined as:
* ESC [ 3 8 ; 5 ; <color#> m
*/
-#define ANDROID_COLOR_BLUE 75
+#define ANDROID_COLOR_BLUE 75
#define ANDROID_COLOR_DEFAULT 231
-#define ANDROID_COLOR_GREEN 40
-#define ANDROID_COLOR_ORANGE 166
-#define ANDROID_COLOR_RED 196
-#define ANDROID_COLOR_YELLOW 226
+#define ANDROID_COLOR_GREEN 40
+#define ANDROID_COLOR_ORANGE 166
+#define ANDROID_COLOR_RED 196
+#define ANDROID_COLOR_YELLOW 226
-static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
-{
- FilterInfo *p_ret;
+static FilterInfo* filterinfo_new(const char* tag, android_LogPriority pri) {
+ FilterInfo* p_ret;
- p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
- p_ret->mTag = strdup(tag);
- p_ret->mPri = pri;
+ p_ret = (FilterInfo*)calloc(1, sizeof(FilterInfo));
+ p_ret->mTag = strdup(tag);
+ p_ret->mPri = pri;
- return p_ret;
+ return p_ret;
}
/* balance to above, filterinfo_free left unimplemented */
@@ -99,197 +106,193 @@
* Note: also accepts 0-9 priorities
* returns ANDROID_LOG_UNKNOWN if the character is unrecognized
*/
-static android_LogPriority filterCharToPri (char c)
-{
- android_LogPriority pri;
+static android_LogPriority filterCharToPri(char c) {
+ android_LogPriority pri;
- c = tolower(c);
+ c = tolower(c);
- if (c >= '0' && c <= '9') {
- if (c >= ('0'+ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
+ if (c >= '0' && c <= '9') {
+ if (c >= ('0' + ANDROID_LOG_SILENT)) {
+ pri = ANDROID_LOG_VERBOSE;
} else {
- pri = ANDROID_LOG_UNKNOWN;
+ pri = (android_LogPriority)(c - '0');
}
+ } else if (c == 'v') {
+ pri = ANDROID_LOG_VERBOSE;
+ } else if (c == 'd') {
+ pri = ANDROID_LOG_DEBUG;
+ } else if (c == 'i') {
+ pri = ANDROID_LOG_INFO;
+ } else if (c == 'w') {
+ pri = ANDROID_LOG_WARN;
+ } else if (c == 'e') {
+ pri = ANDROID_LOG_ERROR;
+ } else if (c == 'f') {
+ pri = ANDROID_LOG_FATAL;
+ } else if (c == 's') {
+ pri = ANDROID_LOG_SILENT;
+ } else if (c == '*') {
+ pri = ANDROID_LOG_DEFAULT;
+ } else {
+ pri = ANDROID_LOG_UNKNOWN;
+ }
- return pri;
+ return pri;
}
-static char filterPriToChar (android_LogPriority pri)
-{
- switch (pri) {
- case ANDROID_LOG_VERBOSE: return 'V';
- case ANDROID_LOG_DEBUG: return 'D';
- case ANDROID_LOG_INFO: return 'I';
- case ANDROID_LOG_WARN: return 'W';
- case ANDROID_LOG_ERROR: return 'E';
- case ANDROID_LOG_FATAL: return 'F';
- case ANDROID_LOG_SILENT: return 'S';
+static char filterPriToChar(android_LogPriority pri) {
+ switch (pri) {
+ /* clang-format off */
+ case ANDROID_LOG_VERBOSE: return 'V';
+ case ANDROID_LOG_DEBUG: return 'D';
+ case ANDROID_LOG_INFO: return 'I';
+ case ANDROID_LOG_WARN: return 'W';
+ case ANDROID_LOG_ERROR: return 'E';
+ case ANDROID_LOG_FATAL: return 'F';
+ case ANDROID_LOG_SILENT: return 'S';
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return '?';
- }
+ case ANDROID_LOG_DEFAULT:
+ case ANDROID_LOG_UNKNOWN:
+ default: return '?';
+ /* clang-format on */
+ }
}
-static int colorFromPri (android_LogPriority pri)
-{
- switch (pri) {
- case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
- case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
- case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
- case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE;
- case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
- case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
- case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
+static int colorFromPri(android_LogPriority pri) {
+ switch (pri) {
+ /* clang-format off */
+ case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
+ case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
+ case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
+ case ANDROID_LOG_WARN: return ANDROID_COLOR_ORANGE;
+ case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
+ case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
+ case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return ANDROID_COLOR_DEFAULT;
- }
+ case ANDROID_LOG_DEFAULT:
+ case ANDROID_LOG_UNKNOWN:
+ default: return ANDROID_COLOR_DEFAULT;
+ /* clang-format on */
+ }
}
-static android_LogPriority filterPriForTag(
- AndroidLogFormat *p_format, const char *tag)
-{
- FilterInfo *p_curFilter;
+static android_LogPriority filterPriForTag(AndroidLogFormat* p_format,
+ const char* tag) {
+ FilterInfo* p_curFilter;
- for (p_curFilter = p_format->filters
- ; p_curFilter != NULL
- ; p_curFilter = p_curFilter->p_next
- ) {
- if (0 == strcmp(tag, p_curFilter->mTag)) {
- if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
- return p_format->global_pri;
- } else {
- return p_curFilter->mPri;
- }
- }
+ for (p_curFilter = p_format->filters; p_curFilter != NULL;
+ p_curFilter = p_curFilter->p_next) {
+ if (0 == strcmp(tag, p_curFilter->mTag)) {
+ if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
+ return p_format->global_pri;
+ } else {
+ return p_curFilter->mPri;
+ }
}
+ }
- return p_format->global_pri;
+ return p_format->global_pri;
}
/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
-LIBLOG_ABI_PUBLIC int android_log_shouldPrintLine (
- AndroidLogFormat *p_format,
- const char *tag,
- android_LogPriority pri)
-{
- return pri >= filterPriForTag(p_format, tag);
+LIBLOG_ABI_PUBLIC int android_log_shouldPrintLine(AndroidLogFormat* p_format,
+ const char* tag,
+ android_LogPriority pri) {
+ return pri >= filterPriForTag(p_format, tag);
}
-LIBLOG_ABI_PUBLIC AndroidLogFormat *android_log_format_new()
-{
- AndroidLogFormat *p_ret;
+LIBLOG_ABI_PUBLIC AndroidLogFormat* android_log_format_new() {
+ AndroidLogFormat* p_ret;
- p_ret = calloc(1, sizeof(AndroidLogFormat));
+ p_ret = calloc(1, sizeof(AndroidLogFormat));
- p_ret->global_pri = ANDROID_LOG_VERBOSE;
- p_ret->format = FORMAT_BRIEF;
- p_ret->colored_output = false;
- p_ret->usec_time_output = false;
- p_ret->nsec_time_output = false;
- p_ret->printable_output = false;
- p_ret->year_output = false;
- p_ret->zone_output = false;
- p_ret->epoch_output = false;
- p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
- p_ret->uid_output = false;
- p_ret->descriptive_output = false;
- descriptive_output = false;
+ p_ret->global_pri = ANDROID_LOG_VERBOSE;
+ p_ret->format = FORMAT_BRIEF;
+ p_ret->colored_output = false;
+ p_ret->usec_time_output = false;
+ p_ret->nsec_time_output = false;
+ p_ret->printable_output = false;
+ p_ret->year_output = false;
+ p_ret->zone_output = false;
+ p_ret->epoch_output = false;
+#ifdef __ANDROID__
+ p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
+#else
+ p_ret->monotonic_output = false;
+#endif
+ p_ret->uid_output = false;
+ p_ret->descriptive_output = false;
+ descriptive_output = false;
- return p_ret;
+ return p_ret;
}
static list_declare(convertHead);
-LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat *p_format)
-{
- FilterInfo *p_info, *p_info_old;
+LIBLOG_ABI_PUBLIC void android_log_format_free(AndroidLogFormat* p_format) {
+ FilterInfo *p_info, *p_info_old;
- p_info = p_format->filters;
+ p_info = p_format->filters;
- while (p_info != NULL) {
- p_info_old = p_info;
- p_info = p_info->p_next;
+ while (p_info != NULL) {
+ p_info_old = p_info;
+ p_info = p_info->p_next;
- free(p_info_old);
- }
+ free(p_info_old);
+ }
- free(p_format);
+ free(p_format);
- /* Free conversion resource, can always be reconstructed */
- while (!list_empty(&convertHead)) {
- struct listnode *node = list_head(&convertHead);
- list_remove(node);
- free(node);
- }
+ /* Free conversion resource, can always be reconstructed */
+ while (!list_empty(&convertHead)) {
+ struct listnode* node = list_head(&convertHead);
+ list_remove(node);
+ free(node);
+ }
}
-LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(
- AndroidLogFormat *p_format,
- AndroidLogPrintFormat format)
-{
- switch (format) {
+LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(AndroidLogFormat* p_format,
+ AndroidLogPrintFormat format) {
+ switch (format) {
case FORMAT_MODIFIER_COLOR:
- p_format->colored_output = true;
- return 0;
+ p_format->colored_output = true;
+ return 0;
case FORMAT_MODIFIER_TIME_USEC:
- p_format->usec_time_output = true;
- return 0;
+ p_format->usec_time_output = true;
+ return 0;
case FORMAT_MODIFIER_TIME_NSEC:
- p_format->nsec_time_output = true;
- return 0;
+ p_format->nsec_time_output = true;
+ return 0;
case FORMAT_MODIFIER_PRINTABLE:
- p_format->printable_output = true;
- return 0;
+ p_format->printable_output = true;
+ return 0;
case FORMAT_MODIFIER_YEAR:
- p_format->year_output = true;
- return 0;
+ p_format->year_output = true;
+ return 0;
case FORMAT_MODIFIER_ZONE:
- p_format->zone_output = !p_format->zone_output;
- return 0;
+ p_format->zone_output = !p_format->zone_output;
+ return 0;
case FORMAT_MODIFIER_EPOCH:
- p_format->epoch_output = true;
- return 0;
+ p_format->epoch_output = true;
+ return 0;
case FORMAT_MODIFIER_MONOTONIC:
- p_format->monotonic_output = true;
- return 0;
+ p_format->monotonic_output = true;
+ return 0;
case FORMAT_MODIFIER_UID:
- p_format->uid_output = true;
- return 0;
+ p_format->uid_output = true;
+ return 0;
case FORMAT_MODIFIER_DESCRIPT:
- p_format->descriptive_output = true;
- descriptive_output = true;
- return 0;
+ p_format->descriptive_output = true;
+ descriptive_output = true;
+ return 0;
default:
- break;
- }
- p_format->format = format;
- return 1;
+ break;
+ }
+ p_format->format = format;
+ return 1;
}
static const char tz[] = "TZ";
@@ -298,63 +301,65 @@
/**
* Returns FORMAT_OFF on invalid string
*/
-LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(
- const char * formatString)
-{
- static AndroidLogPrintFormat format;
+LIBLOG_ABI_PUBLIC AndroidLogPrintFormat
+android_log_formatFromString(const char* formatString) {
+ static AndroidLogPrintFormat format;
- if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
- else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
- else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
- else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
- else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
- else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
- else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
- else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
- else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
- else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
- else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
- else if (strcmp(formatString, "nsec") == 0) format = FORMAT_MODIFIER_TIME_NSEC;
- else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
- else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
- else if (strcmp(formatString, "zone") == 0) format = FORMAT_MODIFIER_ZONE;
- else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
- else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
- else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
- else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
- else {
- extern char *tzname[2];
- static const char gmt[] = "GMT";
- char *cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, formatString, 1);
- /*
- * Run tzset here to determine if the timezone is legitimate. If the
- * zone is GMT, check if that is what was asked for, if not then
- * did not match any on the system; report an error to caller.
- */
- tzset();
- if (!tzname[0]
- || ((!strcmp(tzname[0], utc)
- || !strcmp(tzname[0], gmt)) /* error? */
- && strcasecmp(formatString, utc)
- && strcasecmp(formatString, gmt))) { /* ok */
- if (cp) {
- setenv(tz, cp, 1);
- } else {
- unsetenv(tz);
- }
- tzset();
- format = FORMAT_OFF;
- } else {
- format = FORMAT_MODIFIER_ZONE;
- }
- free(cp);
+ /* clang-format off */
+ if (!strcmp(formatString, "brief")) format = FORMAT_BRIEF;
+ else if (!strcmp(formatString, "process")) format = FORMAT_PROCESS;
+ else if (!strcmp(formatString, "tag")) format = FORMAT_TAG;
+ else if (!strcmp(formatString, "thread")) format = FORMAT_THREAD;
+ else if (!strcmp(formatString, "raw")) format = FORMAT_RAW;
+ else if (!strcmp(formatString, "time")) format = FORMAT_TIME;
+ else if (!strcmp(formatString, "threadtime")) format = FORMAT_THREADTIME;
+ else if (!strcmp(formatString, "long")) format = FORMAT_LONG;
+ else if (!strcmp(formatString, "color")) format = FORMAT_MODIFIER_COLOR;
+ else if (!strcmp(formatString, "colour")) format = FORMAT_MODIFIER_COLOR;
+ else if (!strcmp(formatString, "usec")) format = FORMAT_MODIFIER_TIME_USEC;
+ else if (!strcmp(formatString, "nsec")) format = FORMAT_MODIFIER_TIME_NSEC;
+ else if (!strcmp(formatString, "printable")) format = FORMAT_MODIFIER_PRINTABLE;
+ else if (!strcmp(formatString, "year")) format = FORMAT_MODIFIER_YEAR;
+ else if (!strcmp(formatString, "zone")) format = FORMAT_MODIFIER_ZONE;
+ else if (!strcmp(formatString, "epoch")) format = FORMAT_MODIFIER_EPOCH;
+ else if (!strcmp(formatString, "monotonic")) format = FORMAT_MODIFIER_MONOTONIC;
+ else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
+ else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
+ /* clang-format on */
+#ifndef __MINGW32__
+ else {
+ extern char* tzname[2];
+ static const char gmt[] = "GMT";
+ char* cp = getenv(tz);
+ if (cp) {
+ cp = strdup(cp);
}
+ setenv(tz, formatString, 1);
+ /*
+ * Run tzset here to determine if the timezone is legitimate. If the
+ * zone is GMT, check if that is what was asked for, if not then
+ * did not match any on the system; report an error to caller.
+ */
+ tzset();
+ if (!tzname[0] ||
+ ((!strcmp(tzname[0], utc) || !strcmp(tzname[0], gmt)) /* error? */
+ && strcasecmp(formatString, utc) &&
+ strcasecmp(formatString, gmt))) { /* ok */
+ if (cp) {
+ setenv(tz, cp, 1);
+ } else {
+ unsetenv(tz);
+ }
+ tzset();
+ format = FORMAT_OFF;
+ } else {
+ format = FORMAT_MODIFIER_ZONE;
+ }
+ free(cp);
+ }
+#endif
- return format;
+ return format;
}
/**
@@ -366,73 +371,91 @@
* Assumes single threaded execution
*/
-LIBLOG_ABI_PUBLIC int android_log_addFilterRule(
- AndroidLogFormat *p_format,
- const char *filterExpression)
-{
- size_t tagNameLength;
- android_LogPriority pri = ANDROID_LOG_DEFAULT;
+LIBLOG_ABI_PUBLIC int android_log_addFilterRule(AndroidLogFormat* p_format,
+ const char* filterExpression) {
+ size_t tagNameLength;
+ android_LogPriority pri = ANDROID_LOG_DEFAULT;
- tagNameLength = strcspn(filterExpression, ":");
+ tagNameLength = strcspn(filterExpression, ":");
- if (tagNameLength == 0) {
- goto error;
+ if (tagNameLength == 0) {
+ goto error;
+ }
+
+ if (filterExpression[tagNameLength] == ':') {
+ pri = filterCharToPri(filterExpression[tagNameLength + 1]);
+
+ if (pri == ANDROID_LOG_UNKNOWN) {
+ goto error;
+ }
+ }
+
+ if (0 == strncmp("*", filterExpression, tagNameLength)) {
+ /*
+ * This filter expression refers to the global filter
+ * The default level for this is DEBUG if the priority
+ * is unspecified
+ */
+ if (pri == ANDROID_LOG_DEFAULT) {
+ pri = ANDROID_LOG_DEBUG;
}
- if(filterExpression[tagNameLength] == ':') {
- pri = filterCharToPri(filterExpression[tagNameLength+1]);
-
- if (pri == ANDROID_LOG_UNKNOWN) {
- goto error;
- }
+ p_format->global_pri = pri;
+ } else {
+ /*
+ * for filter expressions that don't refer to the global
+ * filter, the default is verbose if the priority is unspecified
+ */
+ if (pri == ANDROID_LOG_DEFAULT) {
+ pri = ANDROID_LOG_VERBOSE;
}
- if(0 == strncmp("*", filterExpression, tagNameLength)) {
- /*
- * This filter expression refers to the global filter
- * The default level for this is DEBUG if the priority
- * is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_DEBUG;
- }
-
- p_format->global_pri = pri;
- } else {
- /*
- * for filter expressions that don't refer to the global
- * filter, the default is verbose if the priority is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_VERBOSE;
- }
-
- char *tagName;
+ char* tagName;
/*
* Presently HAVE_STRNDUP is never defined, so the second case is always taken
- * Darwin doesn't have strnup, everything else does
+ * Darwin doesn't have strndup, everything else does
*/
#ifdef HAVE_STRNDUP
- tagName = strndup(filterExpression, tagNameLength);
+ tagName = strndup(filterExpression, tagNameLength);
#else
- /* a few extra bytes copied... */
- tagName = strdup(filterExpression);
- tagName[tagNameLength] = '\0';
+ /* a few extra bytes copied... */
+ tagName = strdup(filterExpression);
+ tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
- FilterInfo *p_fi = filterinfo_new(tagName, pri);
- free(tagName);
+ FilterInfo* p_fi = filterinfo_new(tagName, pri);
+ free(tagName);
- p_fi->p_next = p_format->filters;
- p_format->filters = p_fi;
- }
+ p_fi->p_next = p_format->filters;
+ p_format->filters = p_fi;
+ }
- return 0;
+ return 0;
error:
- return -1;
+ return -1;
}
+#ifndef HAVE_STRSEP
+/* KISS replacement helper for below */
+static char* strsep(char** stringp, const char* delim) {
+ char* token;
+ char* ret = *stringp;
+
+ if (!ret || !*ret) {
+ return NULL;
+ }
+ token = strpbrk(ret, delim);
+ if (token) {
+ *token = '\0';
+ ++token;
+ } else {
+ token = ret + strlen(ret);
+ }
+ *stringp = token;
+ return ret;
+}
+#endif
/**
* filterString: a comma/whitespace-separated set of filter expressions
@@ -444,33 +467,30 @@
* Assumes single threaded execution
*
*/
+LIBLOG_ABI_PUBLIC int android_log_addFilterString(AndroidLogFormat* p_format,
+ const char* filterString) {
+ char* filterStringCopy = strdup(filterString);
+ char* p_cur = filterStringCopy;
+ char* p_ret;
+ int err;
-LIBLOG_ABI_PUBLIC int android_log_addFilterString(
- AndroidLogFormat *p_format,
- const char *filterString)
-{
- char *filterStringCopy = strdup (filterString);
- char *p_cur = filterStringCopy;
- char *p_ret;
- int err;
+ /* Yes, I'm using strsep */
+ while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
+ /* ignore whitespace-only entries */
+ if (p_ret[0] != '\0') {
+ err = android_log_addFilterRule(p_format, p_ret);
- /* Yes, I'm using strsep */
- while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- /* ignore whitespace-only entries */
- if(p_ret[0] != '\0') {
- err = android_log_addFilterRule(p_format, p_ret);
-
- if (err < 0) {
- goto error;
- }
- }
+ if (err < 0) {
+ goto error;
+ }
}
+ }
- free (filterStringCopy);
- return 0;
+ free(filterStringCopy);
+ return 0;
error:
- free (filterStringCopy);
- return -1;
+ free(filterStringCopy);
+ return -1;
}
/**
@@ -480,125 +500,124 @@
* Returns 0 on success and -1 on invalid wire format (entry will be
* in unspecified state)
*/
-LIBLOG_ABI_PUBLIC int android_log_processLogBuffer(
- struct logger_entry *buf,
- AndroidLogEntry *entry)
-{
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
+LIBLOG_ABI_PUBLIC int android_log_processLogBuffer(struct logger_entry* buf,
+ AndroidLogEntry* entry) {
+ entry->message = NULL;
+ entry->messageLen = 0;
+ entry->tv_sec = buf->sec;
+ entry->tv_nsec = buf->nsec;
+ entry->uid = -1;
+ entry->pid = buf->pid;
+ entry->tid = buf->tid;
+
+ /*
+ * format: <priority:1><tag:N>\0<message:N>\0
+ *
+ * tag str
+ * starts at buf->msg+1
+ * msg
+ * starts at buf->msg+1+len(tag)+1
+ *
+ * The message may have been truncated by the kernel log driver.
+ * When that happens, we must null-terminate the message ourselves.
+ */
+ if (buf->len < 3) {
/*
- * format: <priority:1><tag:N>\0<message:N>\0
- *
- * tag str
- * starts at buf->msg+1
- * msg
- * starts at buf->msg+1+len(tag)+1
- *
- * The message may have been truncated by the kernel log driver.
- * When that happens, we must null-terminate the message ourselves.
+ * An well-formed entry must consist of at least a priority
+ * and two null characters
*/
- if (buf->len < 3) {
- /*
- * An well-formed entry must consist of at least a priority
- * and two null characters
- */
- fprintf(stderr, "+++ LOG: entry too small\n");
- return -1;
- }
+ fprintf(stderr, "+++ LOG: entry too small\n");
+ return -1;
+ }
- int msgStart = -1;
- int msgEnd = -1;
+ int msgStart = -1;
+ int msgEnd = -1;
- int i;
- char *msg = buf->msg;
- struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
- if (buf2->hdr_size) {
- if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
- (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
- fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
- return -1;
- }
- msg = ((char *)buf2) + buf2->hdr_size;
- if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
- entry->uid = ((struct logger_entry_v4 *)buf)->uid;
- }
+ int i;
+ char* msg = buf->msg;
+ struct logger_entry_v2* buf2 = (struct logger_entry_v2*)buf;
+ if (buf2->hdr_size) {
+ if ((buf2->hdr_size < sizeof(((struct log_msg*)NULL)->entry_v1)) ||
+ (buf2->hdr_size > sizeof(((struct log_msg*)NULL)->entry))) {
+ fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+ return -1;
}
+ msg = ((char*)buf2) + buf2->hdr_size;
+ if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+ entry->uid = ((struct logger_entry_v4*)buf)->uid;
+ }
+ }
+ for (i = 1; i < buf->len; i++) {
+ if (msg[i] == '\0') {
+ if (msgStart == -1) {
+ msgStart = i + 1;
+ } else {
+ msgEnd = i;
+ break;
+ }
+ }
+ }
+
+ if (msgStart == -1) {
+ /* +++ LOG: malformed log message, DYB */
for (i = 1; i < buf->len; i++) {
- if (msg[i] == '\0') {
- if (msgStart == -1) {
- msgStart = i + 1;
- } else {
- msgEnd = i;
- break;
- }
- }
+ /* odd characters in tag? */
+ if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
+ msg[i] = '\0';
+ msgStart = i + 1;
+ break;
+ }
}
-
if (msgStart == -1) {
- /* +++ LOG: malformed log message, DYB */
- for (i = 1; i < buf->len; i++) {
- /* odd characters in tag? */
- if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
- msg[i] = '\0';
- msgStart = i + 1;
- break;
- }
- }
- if (msgStart == -1) {
- msgStart = buf->len - 1; /* All tag, no message, print truncates */
- }
+ msgStart = buf->len - 1; /* All tag, no message, print truncates */
}
- if (msgEnd == -1) {
- /* incoming message not null-terminated; force it */
- msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
- msg[msgEnd] = '\0';
- }
+ }
+ if (msgEnd == -1) {
+ /* incoming message not null-terminated; force it */
+ msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
+ msg[msgEnd] = '\0';
+ }
- entry->priority = msg[0];
- entry->tag = msg + 1;
- entry->tagLen = msgStart - 1;
- entry->message = msg + msgStart;
- entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
+ entry->priority = msg[0];
+ entry->tag = msg + 1;
+ entry->tagLen = msgStart - 1;
+ entry->message = msg + msgStart;
+ entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
- return 0;
+ return 0;
}
/*
* Extract a 4-byte value from a byte stream.
*/
-static inline uint32_t get4LE(const uint8_t* src)
-{
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+static inline uint32_t get4LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
/*
* Extract an 8-byte value from a byte stream.
*/
-static inline uint64_t get8LE(const uint8_t* src)
-{
- uint32_t low, high;
+static inline uint64_t get8LE(const uint8_t* src) {
+ uint32_t low, high;
- low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
- high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
- return ((uint64_t) high << 32) | (uint64_t) low;
+ low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+ return ((uint64_t)high << 32) | (uint64_t)low;
}
static bool findChar(const char** cp, size_t* len, int c) {
- while (*len && isspace(**cp)) {
- ++*cp;
- --*len;
- }
- if (c == INT_MAX) return *len;
- if (*len && (**cp == c)) {
- ++*cp;
- --*len;
- return true;
- }
- return false;
+ while ((*len) && isspace(*(*cp))) {
+ ++(*cp);
+ --(*len);
+ }
+ if (c == INT_MAX) return *len;
+ if ((*len) && (*(*cp) == c)) {
+ ++(*cp);
+ --(*len);
+ return true;
+ }
+ return false;
}
/*
@@ -613,333 +632,337 @@
* Returns 0 on success, 1 on buffer full, -1 on failure.
*/
enum objectType {
- TYPE_OBJECTS = '1',
- TYPE_BYTES = '2',
- TYPE_MILLISECONDS = '3',
- TYPE_ALLOCATIONS = '4',
- TYPE_ID = '5',
- TYPE_PERCENT = '6'
+ TYPE_OBJECTS = '1',
+ TYPE_BYTES = '2',
+ TYPE_MILLISECONDS = '3',
+ TYPE_ALLOCATIONS = '4',
+ TYPE_ID = '5',
+ TYPE_PERCENT = '6'
};
static int android_log_printBinaryEvent(const unsigned char** pEventData,
- size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
- const char** fmtStr, size_t* fmtLen)
-{
- const unsigned char* eventData = *pEventData;
- size_t eventDataLen = *pEventDataLen;
- char* outBuf = *pOutBuf;
- char* outBufSave = outBuf;
- size_t outBufLen = *pOutBufLen;
- size_t outBufLenSave = outBufLen;
- unsigned char type;
- size_t outCount;
- int result = 0;
- const char* cp;
- size_t len;
- int64_t lval;
+ size_t* pEventDataLen, char** pOutBuf,
+ size_t* pOutBufLen, const char** fmtStr,
+ size_t* fmtLen) {
+ const unsigned char* eventData = *pEventData;
+ size_t eventDataLen = *pEventDataLen;
+ char* outBuf = *pOutBuf;
+ char* outBufSave = outBuf;
+ size_t outBufLen = *pOutBufLen;
+ size_t outBufLenSave = outBufLen;
+ unsigned char type;
+ size_t outCount;
+ int result = 0;
+ const char* cp;
+ size_t len;
+ int64_t lval;
- if (eventDataLen < 1) return -1;
+ if (eventDataLen < 1) return -1;
- type = *eventData++;
- eventDataLen--;
+ type = *eventData++;
+ eventDataLen--;
- cp = NULL;
+ cp = NULL;
+ len = 0;
+ if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+ cp = *fmtStr;
+ len = *fmtLen;
+ }
+ /*
+ * event.logtag format specification:
+ *
+ * Optionally, after the tag names can be put a description for the value(s)
+ * of the tag. Description are in the format
+ * (<name>|data type[|data unit])
+ * Multiple values are separated by commas.
+ *
+ * The data type is a number from the following values:
+ * 1: int
+ * 2: long
+ * 3: string
+ * 4: list
+ * 5: float
+ *
+ * The data unit is a number taken from the following list:
+ * 1: Number of objects
+ * 2: Number of bytes
+ * 3: Number of milliseconds
+ * 4: Number of allocations
+ * 5: Id
+ * 6: Percent
+ * Default value for data of type int/long is 2 (bytes).
+ */
+ if (!cp || !findChar(&cp, &len, '(')) {
len = 0;
- if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
- cp = *fmtStr;
- len = *fmtLen;
+ } else {
+ char* outBufLastSpace = NULL;
+
+ findChar(&cp, &len, INT_MAX);
+ while (len && *cp && (*cp != '|') && (*cp != ')')) {
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+ *outBuf = *cp;
+ ++outBuf;
+ ++cp;
+ --outBufLen;
+ --len;
}
- /*
- * event.logtag format specification:
- *
- * Optionally, after the tag names can be put a description for the value(s)
- * of the tag. Description are in the format
- * (<name>|data type[|data unit])
- * Multiple values are separated by commas.
- *
- * The data type is a number from the following values:
- * 1: int
- * 2: long
- * 3: string
- * 4: list
- * 5: float
- *
- * The data unit is a number taken from the following list:
- * 1: Number of objects
- * 2: Number of bytes
- * 3: Number of milliseconds
- * 4: Number of allocations
- * 5: Id
- * 6: Percent
- * Default value for data of type int/long is 2 (bytes).
- */
- if (!cp || !findChar(&cp, &len, '(')) {
+ if (outBufLastSpace) {
+ outBufLen += outBuf - outBufLastSpace;
+ outBuf = outBufLastSpace;
+ }
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ if (outBufSave != outBuf) {
+ *outBuf = '=';
+ ++outBuf;
+ --outBufLen;
+ }
+
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ static const unsigned char typeTable[] = {
+ EVENT_TYPE_INT, EVENT_TYPE_LONG, EVENT_TYPE_STRING, EVENT_TYPE_LIST,
+ EVENT_TYPE_FLOAT
+ };
+
+ if ((*cp >= '1') &&
+ (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+ (type != typeTable[(size_t)(*cp - '1')]))
len = 0;
- } else {
- char* outBufLastSpace = NULL;
- findChar(&cp, &len, INT_MAX);
- while (len && *cp && (*cp != '|') && (*cp != ')')) {
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- outBufLastSpace = isspace(*cp) ? outBuf : NULL;
- *outBuf = *cp;
- ++outBuf;
- ++cp;
- --outBufLen;
- --len;
- }
- if (outBufLastSpace) {
- outBufLen += outBuf - outBufLastSpace;
- outBuf = outBufLastSpace;
- }
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- if (outBufSave != outBuf) {
- *outBuf = '=';
- ++outBuf;
- --outBufLen;
- }
-
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- static const unsigned char typeTable[] = {
- EVENT_TYPE_INT,
- EVENT_TYPE_LONG,
- EVENT_TYPE_STRING,
- EVENT_TYPE_LIST,
- EVENT_TYPE_FLOAT
- };
-
- if ((*cp >= '1') &&
- (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
- (type != typeTable[(size_t)(*cp - '1')])) len = 0;
-
- if (len) {
- ++cp;
- --len;
- } else {
- /* reset the format */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- }
+ if (len) {
+ ++cp;
+ --len;
+ } else {
+ /* reset the format */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
}
- lval = 0;
- switch (type) {
+ }
+ outCount = 0;
+ lval = 0;
+ switch (type) {
case EVENT_TYPE_INT:
- /* 32-bit signed int */
- {
- int32_t ival;
+ /* 32-bit signed int */
+ {
+ int32_t ival;
- if (eventDataLen < 4) return -1;
- ival = get4LE(eventData);
- eventData += 4;
- eventDataLen -= 4;
+ if (eventDataLen < 4) return -1;
+ ival = get4LE(eventData);
+ eventData += 4;
+ eventDataLen -= 4;
- lval = ival;
- }
- goto pr_lval;
+ lval = ival;
+ }
+ goto pr_lval;
case EVENT_TYPE_LONG:
- /* 64-bit signed long */
- if (eventDataLen < 8) return -1;
- lval = get8LE(eventData);
- eventData += 8;
- eventDataLen -= 8;
+ /* 64-bit signed long */
+ if (eventDataLen < 8) return -1;
+ lval = get8LE(eventData);
+ eventData += 8;
+ eventDataLen -= 8;
pr_lval:
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
- break;
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
+ }
+ break;
case EVENT_TYPE_FLOAT:
- /* float */
- {
- uint32_t ival;
- float fval;
+ /* float */
+ {
+ uint32_t ival;
+ float fval;
- if (eventDataLen < 4) return -1;
- ival = get4LE(eventData);
- fval = *(float*)&ival;
- eventData += 4;
- eventDataLen -= 4;
+ if (eventDataLen < 4) return -1;
+ ival = get4LE(eventData);
+ fval = *(float*)&ival;
+ eventData += 4;
+ eventDataLen -= 4;
- outCount = snprintf(outBuf, outBufLen, "%f", fval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ outCount = snprintf(outBuf, outBufLen, "%f", fval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
}
- break;
+ }
+ break;
case EVENT_TYPE_STRING:
- /* UTF-8 chars, not NULL-terminated */
- {
- unsigned int strLen;
+ /* UTF-8 chars, not NULL-terminated */
+ {
+ unsigned int strLen;
- if (eventDataLen < 4) return -1;
- strLen = get4LE(eventData);
- eventData += 4;
- eventDataLen -= 4;
+ if (eventDataLen < 4) return -1;
+ strLen = get4LE(eventData);
+ eventData += 4;
+ eventDataLen -= 4;
- if (eventDataLen < strLen) return -1;
-
- if (cp && (strLen == 0)) {
- /* reset the format if no content */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- if (strLen < outBufLen) {
- memcpy(outBuf, eventData, strLen);
- outBuf += strLen;
- outBufLen -= strLen;
- } else if (outBufLen > 0) {
- /* copy what we can */
- memcpy(outBuf, eventData, outBufLen);
- outBuf += outBufLen;
- outBufLen -= outBufLen;
- goto no_room;
- }
- eventData += strLen;
- eventDataLen -= strLen;
- break;
+ if (eventDataLen < strLen) {
+ result = -1; /* mark truncated */
+ strLen = eventDataLen;
}
- case EVENT_TYPE_LIST:
- /* N items, all different types */
- {
- unsigned char count;
- int i;
- if (eventDataLen < 1) return -1;
-
- count = *eventData++;
- eventDataLen--;
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = '[';
- outBufLen--;
-
- for (i = 0; i < count; i++) {
- result = android_log_printBinaryEvent(&eventData, &eventDataLen,
- &outBuf, &outBufLen, fmtStr, fmtLen);
- if (result != 0) goto bail;
-
- if (i < (count - 1)) {
- if (outBufLen <= 0) goto no_room;
- *outBuf++ = ',';
- outBufLen--;
- }
- }
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = ']';
- outBufLen--;
+ if (cp && (strLen == 0)) {
+ /* reset the format if no content */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
}
+ if (strLen < outBufLen) {
+ memcpy(outBuf, eventData, strLen);
+ outBuf += strLen;
+ outBufLen -= strLen;
+ } else {
+ if (outBufLen > 0) {
+ /* copy what we can */
+ memcpy(outBuf, eventData, outBufLen);
+ outBuf += outBufLen;
+ outBufLen -= outBufLen;
+ }
+ if (!result) result = 1; /* if not truncated, return no room */
+ }
+ eventData += strLen;
+ eventDataLen -= strLen;
+ if (result != 0) goto bail;
break;
- default:
- fprintf(stderr, "Unknown binary event type %d\n", type);
- return -1;
- }
- if (cp && len) {
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- switch (*cp) {
- case TYPE_OBJECTS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " objects"); */
- break;
- case TYPE_BYTES:
- if ((lval != 0) && ((lval % 1024) == 0)) {
- /* repaint with multiplier */
- static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
- size_t idx = 0;
- outBuf -= outCount;
- outBufLen += outCount;
- do {
- lval /= 1024;
- if ((lval % 1024) != 0) break;
- } while (++idx < ((sizeof(suffixTable) /
- sizeof(suffixTable[0])) - 1));
- outCount = snprintf(outBuf, outBufLen,
- "%" PRId64 "%cB",
- lval, suffixTable[idx]);
- } else {
- outCount = snprintf(outBuf, outBufLen, "B");
- }
- break;
- case TYPE_MILLISECONDS:
- if (((lval <= -1000) || (1000 <= lval)) &&
- (outBufLen || (outBuf[-1] == '0'))) {
- /* repaint as (fractional) seconds, possibly saving space */
- if (outBufLen) outBuf[0] = outBuf[-1];
- outBuf[-1] = outBuf[-2];
- outBuf[-2] = outBuf[-3];
- outBuf[-3] = '.';
- while ((outBufLen == 0) || (*outBuf == '0')) {
- --outBuf;
- ++outBufLen;
- }
- if (*outBuf != '.') {
- ++outBuf;
- --outBufLen;
- }
- outCount = snprintf(outBuf, outBufLen, "s");
- } else {
- outCount = snprintf(outBuf, outBufLen, "ms");
- }
- break;
- case TYPE_ALLOCATIONS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
- break;
- case TYPE_ID:
- outCount = 0;
- break;
- case TYPE_PERCENT:
- outCount = snprintf(outBuf, outBufLen, "%%");
- break;
- default: /* ? */
- outCount = 0;
- break;
- }
- ++cp;
- --len;
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else if (outCount) {
- /* halt output */
- goto no_room;
- }
+ }
+ case EVENT_TYPE_LIST:
+ /* N items, all different types */
+ {
+ unsigned char count;
+ int i;
+
+ if (eventDataLen < 1) return -1;
+
+ count = *eventData++;
+ eventDataLen--;
+
+ if (outBufLen <= 0) goto no_room;
+
+ *outBuf++ = '[';
+ outBufLen--;
+
+ for (i = 0; i < count; i++) {
+ result = android_log_printBinaryEvent(
+ &eventData, &eventDataLen, &outBuf, &outBufLen, fmtStr, fmtLen);
+ if (result != 0) goto bail;
+
+ if (i < (count - 1)) {
+ if (outBufLen <= 0) goto no_room;
+ *outBuf++ = ',';
+ outBufLen--;
+ }
}
- if (!findChar(&cp, &len, ')')) len = 0;
- if (!findChar(&cp, &len, ',')) len = 0;
+
+ if (outBufLen <= 0) goto no_room;
+
+ *outBuf++ = ']';
+ outBufLen--;
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown binary event type %d\n", type);
+ return -1;
+ }
+ if (cp && len) {
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ switch (*cp) {
+ case TYPE_OBJECTS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+ break;
+ case TYPE_BYTES:
+ if ((lval != 0) && ((lval % 1024) == 0)) {
+ /* repaint with multiplier */
+ static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+ size_t idx = 0;
+ outBuf -= outCount;
+ outBufLen += outCount;
+ do {
+ lval /= 1024;
+ if ((lval % 1024) != 0) break;
+ } while (++idx <
+ ((sizeof(suffixTable) / sizeof(suffixTable[0])) - 1));
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64 "%cB", lval,
+ suffixTable[idx]);
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "B");
+ }
+ break;
+ case TYPE_MILLISECONDS:
+ if (((lval <= -1000) || (1000 <= lval)) &&
+ (outBufLen || (outBuf[-1] == '0'))) {
+ /* repaint as (fractional) seconds, possibly saving space */
+ if (outBufLen) outBuf[0] = outBuf[-1];
+ outBuf[-1] = outBuf[-2];
+ outBuf[-2] = outBuf[-3];
+ outBuf[-3] = '.';
+ while ((outBufLen == 0) || (*outBuf == '0')) {
+ --outBuf;
+ ++outBufLen;
+ }
+ if (*outBuf != '.') {
+ ++outBuf;
+ --outBufLen;
+ }
+ outCount = snprintf(outBuf, outBufLen, "s");
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "ms");
+ }
+ break;
+ case TYPE_ALLOCATIONS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+ break;
+ case TYPE_ID:
+ outCount = 0;
+ break;
+ case TYPE_PERCENT:
+ outCount = snprintf(outBuf, outBufLen, "%%");
+ break;
+ default: /* ? */
+ outCount = 0;
+ break;
+ }
+ ++cp;
+ --len;
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else if (outCount) {
+ /* halt output */
+ goto no_room;
+ }
}
+ if (!findChar(&cp, &len, ')')) len = 0;
+ if (!findChar(&cp, &len, ',')) len = 0;
+ }
bail:
- *pEventData = eventData;
- *pEventDataLen = eventDataLen;
- *pOutBuf = outBuf;
- *pOutBufLen = outBufLen;
- if (cp) {
- *fmtStr = cp;
- *fmtLen = len;
- }
- return result;
+ *pEventData = eventData;
+ *pEventDataLen = eventDataLen;
+ *pOutBuf = outBuf;
+ *pOutBufLen = outBufLen;
+ if (cp) {
+ *fmtStr = cp;
+ *fmtLen = len;
+ }
+ return result;
no_room:
- result = 1;
- goto bail;
+ result = 1;
+ goto bail;
}
/**
@@ -951,141 +974,144 @@
* here.
*/
LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
- struct logger_entry *buf,
- AndroidLogEntry *entry,
- const EventTagMap *map,
- char *messageBuf, int messageBufLen)
-{
- size_t inCount;
- uint32_t tagIndex;
- const unsigned char* eventData;
+ struct logger_entry* buf, AndroidLogEntry* entry,
+ const EventTagMap* map __unused, /* only on !__ANDROID__ */
+ char* messageBuf, int messageBufLen) {
+ size_t inCount;
+ uint32_t tagIndex;
+ const unsigned char* eventData;
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->priority = ANDROID_LOG_INFO;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
+ entry->message = NULL;
+ entry->messageLen = 0;
- /*
- * Pull the tag out, fill in some additional details based on incoming
- * buffer version (v3 adds lid, v4 adds uid).
- */
- eventData = (const unsigned char*) buf->msg;
- struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
+ entry->tv_sec = buf->sec;
+ entry->tv_nsec = buf->nsec;
+ entry->priority = ANDROID_LOG_INFO;
+ entry->uid = -1;
+ entry->pid = buf->pid;
+ entry->tid = buf->tid;
+
+ /*
+ * Pull the tag out, fill in some additional details based on incoming
+ * buffer version (v3 adds lid, v4 adds uid).
+ */
+ eventData = (const unsigned char*)buf->msg;
+ struct logger_entry_v2* buf2 = (struct logger_entry_v2*)buf;
+ if (buf2->hdr_size) {
+ if ((buf2->hdr_size < sizeof(((struct log_msg*)NULL)->entry_v1)) ||
+ (buf2->hdr_size > sizeof(((struct log_msg*)NULL)->entry))) {
+ fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
+ return -1;
+ }
+ eventData = ((unsigned char*)buf2) + buf2->hdr_size;
+ if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
+ (((struct logger_entry_v3*)buf)->lid == LOG_ID_SECURITY)) {
+ entry->priority = ANDROID_LOG_WARN;
+ }
+ if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+ entry->uid = ((struct logger_entry_v4*)buf)->uid;
+ }
+ }
+ inCount = buf->len;
+ if (inCount < 4) return -1;
+ tagIndex = get4LE(eventData);
+ eventData += 4;
+ inCount -= 4;
+
+ entry->tagLen = 0;
+ entry->tag = NULL;
+#ifdef __ANDROID__
+ if (map != NULL) {
+ entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
+ }
+#endif
+
+ /*
+ * If we don't have a map, or didn't find the tag number in the map,
+ * stuff a generated tag value into the start of the output buffer and
+ * shift the buffer pointers down.
+ */
+ if (entry->tag == NULL) {
+ size_t tagLen;
+
+ tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
+ if (tagLen >= (size_t)messageBufLen) {
+ tagLen = messageBufLen - 1;
+ }
+ entry->tag = messageBuf;
+ entry->tagLen = tagLen;
+ messageBuf += tagLen + 1;
+ messageBufLen -= tagLen + 1;
+ }
+
+ /*
+ * Format the event log data into the buffer.
+ */
+ const char* fmtStr = NULL;
+ size_t fmtLen = 0;
+#ifdef __ANDROID__
+ if (descriptive_output && map) {
+ fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
+ }
+#endif
+
+ char* outBuf = messageBuf;
+ size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
+ int result = 0;
+
+ if ((inCount > 0) || fmtLen) {
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, &fmtStr, &fmtLen);
+ }
+ if ((result == 1) && fmtStr) {
+ /* We overflowed :-(, let's repaint the line w/o format dressings */
+ eventData = (const unsigned char*)buf->msg;
if (buf2->hdr_size) {
- if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) ||
- (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) {
- fprintf(stderr, "+++ LOG: entry illegal hdr_size\n");
- return -1;
- }
- eventData = ((unsigned char *)buf2) + buf2->hdr_size;
- if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
- (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
- entry->priority = ANDROID_LOG_WARN;
- }
- if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
- entry->uid = ((struct logger_entry_v4 *)buf)->uid;
- }
+ eventData = ((unsigned char*)buf2) + buf2->hdr_size;
}
- inCount = buf->len;
- if (inCount < 4) return -1;
- tagIndex = get4LE(eventData);
eventData += 4;
- inCount -= 4;
-
- entry->tagLen = 0;
- if (map != NULL) {
- entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
- } else {
- entry->tag = NULL;
+ outBuf = messageBuf;
+ outRemaining = messageBufLen - 1;
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, NULL, NULL);
+ }
+ if (result < 0) {
+ fprintf(stderr, "Binary log entry conversion failed\n");
+ }
+ if (result) {
+ if (!outRemaining) {
+ /* make space to leave an indicator */
+ --outBuf;
+ ++outRemaining;
}
+ *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
+ outRemaining--;
+ /* pretend we ate all the data to prevent log stutter */
+ inCount = 0;
+ if (result > 0) result = 0;
+ }
- /*
- * If we don't have a map, or didn't find the tag number in the map,
- * stuff a generated tag value into the start of the output buffer and
- * shift the buffer pointers down.
- */
- if (entry->tag == NULL) {
- size_t tagLen;
+ /* eat the silly terminating '\n' */
+ if (inCount == 1 && *eventData == '\n') {
+ eventData++;
+ inCount--;
+ }
- tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
- if (tagLen >= (size_t)messageBufLen) {
- tagLen = messageBufLen - 1;
- }
- entry->tag = messageBuf;
- entry->tagLen = tagLen;
- messageBuf += tagLen + 1;
- messageBufLen -= tagLen + 1;
- }
+ if (inCount != 0) {
+ fprintf(stderr, "Warning: leftover binary log data (%zu bytes)\n", inCount);
+ }
- /*
- * Format the event log data into the buffer.
- */
- const char* fmtStr = NULL;
- size_t fmtLen = 0;
- if (descriptive_output && map) {
- fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
- }
+ /*
+ * Terminate the buffer. The NUL byte does not count as part of
+ * entry->messageLen.
+ */
+ *outBuf = '\0';
+ entry->messageLen = outBuf - messageBuf;
+ assert(entry->messageLen == (messageBufLen - 1) - outRemaining);
- char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
- int result = 0;
+ entry->message = messageBuf;
- if ((inCount > 0) || fmtLen) {
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
- &outRemaining, &fmtStr, &fmtLen);
- }
- if ((result == 1) && fmtStr) {
- /* We overflowed :-(, let's repaint the line w/o format dressings */
- eventData = (const unsigned char*)buf->msg;
- if (buf2->hdr_size) {
- eventData = ((unsigned char *)buf2) + buf2->hdr_size;
- }
- eventData += 4;
- outBuf = messageBuf;
- outRemaining = messageBufLen - 1;
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
- &outRemaining, NULL, NULL);
- }
- if (result < 0) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- }
- if (result) {
- if (!outRemaining) {
- /* make space to leave an indicator */
- --outBuf;
- ++outRemaining;
- }
- *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
- outRemaining--;
- /* pretend we ate all the data to prevent log stutter */
- inCount = 0;
- if (result > 0) result = 0;
- }
-
- /* eat the silly terminating '\n' */
- if (inCount == 1 && *eventData == '\n') {
- eventData++;
- inCount--;
- }
-
- if (inCount != 0) {
- fprintf(stderr,
- "Warning: leftover binary log data (%zu bytes)\n", inCount);
- }
-
- /*
- * Terminate the buffer. The NUL byte does not count as part of
- * entry->messageLen.
- */
- *outBuf = '\0';
- entry->messageLen = outBuf - messageBuf;
- assert(entry->messageLen == (messageBufLen-1) - outRemaining);
-
- entry->message = messageBuf;
-
- return result;
+ return result;
}
/*
@@ -1100,388 +1126,379 @@
* _also_ be part of libutils/Unicode.cpp if its usefullness needs to
* propagate globally.
*/
-LIBLOG_WEAK ssize_t utf8_character_length(const char *src, size_t len)
-{
- const char *cur = src;
- const char first_char = *cur++;
- static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
- int32_t mask, to_ignore_mask;
- size_t num_to_read;
- uint32_t utf32;
+LIBLOG_WEAK ssize_t utf8_character_length(const char* src, size_t len) {
+ const char* cur = src;
+ const char first_char = *cur++;
+ static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
+ int32_t mask, to_ignore_mask;
+ size_t num_to_read;
+ uint32_t utf32;
- if ((first_char & 0x80) == 0) { /* ASCII */
- return first_char ? 1 : -1;
- }
+ if ((first_char & 0x80) == 0) { /* ASCII */
+ return first_char ? 1 : -1;
+ }
- /*
- * (UTF-8's character must not be like 10xxxxxx,
- * but 110xxxxx, 1110xxxx, ... or 1111110x)
- */
- if ((first_char & 0x40) == 0) {
- return -1;
- }
+ /*
+ * (UTF-8's character must not be like 10xxxxxx,
+ * but 110xxxxx, 1110xxxx, ... or 1111110x)
+ */
+ if ((first_char & 0x40) == 0) {
+ return -1;
+ }
- for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
- num_to_read < 5 && (first_char & mask);
- num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
- if (num_to_read > len) {
- return -1;
- }
- if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
- return -1;
- }
- utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
+ for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+ num_to_read < 5 && (first_char & mask);
+ num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+ if (num_to_read > len) {
+ return -1;
}
- /* "first_char" must be (110xxxxx - 11110xxx) */
- if (num_to_read >= 5) {
- return -1;
+ if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
+ return -1;
}
- to_ignore_mask |= mask;
- utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
- if (utf32 > kUnicodeMaxCodepoint) {
- return -1;
- }
- return num_to_read;
+ utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
+ }
+ /* "first_char" must be (110xxxxx - 11110xxx) */
+ if (num_to_read >= 5) {
+ return -1;
+ }
+ to_ignore_mask |= mask;
+ utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+ if (utf32 > kUnicodeMaxCodepoint) {
+ return -1;
+ }
+ return num_to_read;
}
/*
* Convert to printable from message to p buffer, return string length. If p is
* NULL, do not copy, but still return the expected string length.
*/
-static size_t convertPrintable(char *p, const char *message, size_t messageLen)
-{
- char *begin = p;
- bool print = p != NULL;
+static size_t convertPrintable(char* p, const char* message, size_t messageLen) {
+ char* begin = p;
+ bool print = p != NULL;
- while (messageLen) {
- char buf[6];
- ssize_t len = sizeof(buf) - 1;
- if ((size_t)len > messageLen) {
- len = messageLen;
+ while (messageLen) {
+ char buf[6];
+ ssize_t len = sizeof(buf) - 1;
+ if ((size_t)len > messageLen) {
+ len = messageLen;
+ }
+ len = utf8_character_length(message, len);
+
+ if (len < 0) {
+ snprintf(buf, sizeof(buf),
+ ((messageLen > 1) && isdigit(message[1])) ? "\\%03o" : "\\%o",
+ *message & 0377);
+ len = 1;
+ } else {
+ buf[0] = '\0';
+ if (len == 1) {
+ if (*message == '\a') {
+ strcpy(buf, "\\a");
+ } else if (*message == '\b') {
+ strcpy(buf, "\\b");
+ } else if (*message == '\t') {
+ strcpy(buf, "\t"); /* Do not escape tabs */
+ } else if (*message == '\v') {
+ strcpy(buf, "\\v");
+ } else if (*message == '\f') {
+ strcpy(buf, "\\f");
+ } else if (*message == '\r') {
+ strcpy(buf, "\\r");
+ } else if (*message == '\\') {
+ strcpy(buf, "\\\\");
+ } else if ((*message < ' ') || (*message & 0x80)) {
+ snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
}
- len = utf8_character_length(message, len);
+ }
+ if (!buf[0]) {
+ strncpy(buf, message, len);
+ buf[len] = '\0';
+ }
+ }
+ if (print) {
+ strcpy(p, buf);
+ }
+ p += strlen(buf);
+ message += len;
+ messageLen -= len;
+ }
+ return p - begin;
+}
- if (len < 0) {
- snprintf(buf, sizeof(buf),
- ((messageLen > 1) && isdigit(message[1]))
- ? "\\%03o"
- : "\\%o",
- *message & 0377);
- len = 1;
+static char* readSeconds(char* e, struct timespec* t) {
+ unsigned long multiplier;
+ char* p;
+ t->tv_sec = strtoul(e, &p, 10);
+ if (*p != '.') {
+ return NULL;
+ }
+ t->tv_nsec = 0;
+ multiplier = NS_PER_SEC;
+ while (isdigit(*++p) && (multiplier /= 10)) {
+ t->tv_nsec += (*p - '0') * multiplier;
+ }
+ return p;
+}
+
+static struct timespec* sumTimespec(struct timespec* left,
+ struct timespec* right) {
+ left->tv_nsec += right->tv_nsec;
+ left->tv_sec += right->tv_sec;
+ if (left->tv_nsec >= (long)NS_PER_SEC) {
+ left->tv_nsec -= NS_PER_SEC;
+ left->tv_sec += 1;
+ }
+ return left;
+}
+
+static struct timespec* subTimespec(struct timespec* result,
+ struct timespec* left,
+ struct timespec* right) {
+ result->tv_nsec = left->tv_nsec - right->tv_nsec;
+ result->tv_sec = left->tv_sec - right->tv_sec;
+ if (result->tv_nsec < 0) {
+ result->tv_nsec += NS_PER_SEC;
+ result->tv_sec -= 1;
+ }
+ return result;
+}
+
+static long long nsecTimespec(struct timespec* now) {
+ return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
+}
+
+#ifdef __ANDROID__
+static void convertMonotonic(struct timespec* result,
+ const AndroidLogEntry* entry) {
+ struct listnode* node;
+ struct conversionList {
+ struct listnode node; /* first */
+ struct timespec time;
+ struct timespec convert;
+ } * list, *next;
+ struct timespec time, convert;
+
+ /* If we do not have a conversion list, build one up */
+ if (list_empty(&convertHead)) {
+ bool suspended_pending = false;
+ struct timespec suspended_monotonic = { 0, 0 };
+ struct timespec suspended_diff = { 0, 0 };
+
+ /*
+ * Read dmesg for _some_ synchronization markers and insert
+ * Anything in the Android Logger before the dmesg logging span will
+ * be highly suspect regarding the monotonic time calculations.
+ */
+ FILE* p = popen("/system/bin/dmesg", "re");
+ if (p) {
+ char* line = NULL;
+ size_t len = 0;
+ while (getline(&line, &len, p) > 0) {
+ static const char suspend[] = "PM: suspend entry ";
+ static const char resume[] = "PM: suspend exit ";
+ static const char healthd[] = "healthd";
+ static const char battery[] = ": battery ";
+ static const char suspended[] = "Suspended for ";
+ struct timespec monotonic;
+ struct tm tm;
+ char *cp, *e = line;
+ bool add_entry = true;
+
+ if (*e == '<') {
+ while (*e && (*e != '>')) {
+ ++e;
+ }
+ if (*e != '>') {
+ continue;
+ }
+ }
+ if (*e != '[') {
+ continue;
+ }
+ while (*++e == ' ') {
+ ;
+ }
+ e = readSeconds(e, &monotonic);
+ if (!e || (*e != ']')) {
+ continue;
+ }
+
+ if ((e = strstr(e, suspend))) {
+ e += sizeof(suspend) - 1;
+ } else if ((e = strstr(line, resume))) {
+ e += sizeof(resume) - 1;
+ } else if (((e = strstr(line, healthd))) &&
+ ((e = strstr(e + sizeof(healthd) - 1, battery)))) {
+ /* NB: healthd is roughly 150us late, worth the price to
+ * deal with ntp-induced or hardware clock drift. */
+ e += sizeof(battery) - 1;
+ } else if ((e = strstr(line, suspended))) {
+ e += sizeof(suspended) - 1;
+ e = readSeconds(e, &time);
+ if (!e) {
+ continue;
+ }
+ add_entry = false;
+ suspended_pending = true;
+ suspended_monotonic = monotonic;
+ suspended_diff = time;
} else {
- buf[0] = '\0';
- if (len == 1) {
- if (*message == '\a') {
- strcpy(buf, "\\a");
- } else if (*message == '\b') {
- strcpy(buf, "\\b");
- } else if (*message == '\t') {
- strcpy(buf, "\t"); // Do not escape tabs
- } else if (*message == '\v') {
- strcpy(buf, "\\v");
- } else if (*message == '\f') {
- strcpy(buf, "\\f");
- } else if (*message == '\r') {
- strcpy(buf, "\\r");
- } else if (*message == '\\') {
- strcpy(buf, "\\\\");
- } else if ((*message < ' ') || (*message & 0x80)) {
- snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
- }
- }
- if (!buf[0]) {
- strncpy(buf, message, len);
- buf[len] = '\0';
- }
+ continue;
}
- if (print) {
- strcpy(p, buf);
+ if (add_entry) {
+ /* look for "????-??-?? ??:??:??.????????? UTC" */
+ cp = strstr(e, " UTC");
+ if (!cp || ((cp - e) < 29) || (cp[-10] != '.')) {
+ continue;
+ }
+ e = cp - 29;
+ cp = readSeconds(cp - 10, &time);
+ if (!cp) {
+ continue;
+ }
+ cp = strptime(e, "%Y-%m-%d %H:%M:%S.", &tm);
+ if (!cp) {
+ continue;
+ }
+ cp = getenv(tz);
+ if (cp) {
+ cp = strdup(cp);
+ }
+ setenv(tz, utc, 1);
+ time.tv_sec = mktime(&tm);
+ if (cp) {
+ setenv(tz, cp, 1);
+ free(cp);
+ } else {
+ unsetenv(tz);
+ }
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ list->time = time;
+ subTimespec(&list->convert, &time, &monotonic);
+ list_add_tail(&convertHead, &list->node);
}
- p += strlen(buf);
- message += len;
- messageLen -= len;
- }
- return p - begin;
-}
-
-static char *readSeconds(char *e, struct timespec *t)
-{
- unsigned long multiplier;
- char *p;
- t->tv_sec = strtoul(e, &p, 10);
- if (*p != '.') {
- return NULL;
- }
- t->tv_nsec = 0;
- multiplier = NS_PER_SEC;
- while (isdigit(*++p) && (multiplier /= 10)) {
- t->tv_nsec += (*p - '0') * multiplier;
- }
- return p;
-}
-
-static struct timespec *sumTimespec(struct timespec *left,
- struct timespec *right)
-{
- left->tv_nsec += right->tv_nsec;
- left->tv_sec += right->tv_sec;
- if (left->tv_nsec >= (long)NS_PER_SEC) {
- left->tv_nsec -= NS_PER_SEC;
- left->tv_sec += 1;
- }
- return left;
-}
-
-static struct timespec *subTimespec(struct timespec *result,
- struct timespec *left,
- struct timespec *right)
-{
- result->tv_nsec = left->tv_nsec - right->tv_nsec;
- result->tv_sec = left->tv_sec - right->tv_sec;
- if (result->tv_nsec < 0) {
- result->tv_nsec += NS_PER_SEC;
- result->tv_sec -= 1;
- }
- return result;
-}
-
-static long long nsecTimespec(struct timespec *now)
-{
- return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
-}
-
-static void convertMonotonic(struct timespec *result,
- const AndroidLogEntry *entry)
-{
- struct listnode *node;
- struct conversionList {
- struct listnode node; /* first */
- struct timespec time;
- struct timespec convert;
- } *list, *next;
- struct timespec time, convert;
-
- /* If we do not have a conversion list, build one up */
- if (list_empty(&convertHead)) {
- bool suspended_pending = false;
- struct timespec suspended_monotonic = { 0, 0 };
- struct timespec suspended_diff = { 0, 0 };
-
- /*
- * Read dmesg for _some_ synchronization markers and insert
- * Anything in the Android Logger before the dmesg logging span will
- * be highly suspect regarding the monotonic time calculations.
- */
- FILE *p = popen("/system/bin/dmesg", "re");
- if (p) {
- char *line = NULL;
- size_t len = 0;
- while (getline(&line, &len, p) > 0) {
- static const char suspend[] = "PM: suspend entry ";
- static const char resume[] = "PM: suspend exit ";
- static const char healthd[] = "healthd";
- static const char battery[] = ": battery ";
- static const char suspended[] = "Suspended for ";
- struct timespec monotonic;
- struct tm tm;
- char *cp, *e = line;
- bool add_entry = true;
-
- if (*e == '<') {
- while (*e && (*e != '>')) {
- ++e;
- }
- if (*e != '>') {
- continue;
- }
- }
- if (*e != '[') {
- continue;
- }
- while (*++e == ' ') {
- ;
- }
- e = readSeconds(e, &monotonic);
- if (!e || (*e != ']')) {
- continue;
- }
-
- if ((e = strstr(e, suspend))) {
- e += sizeof(suspend) - 1;
- } else if ((e = strstr(line, resume))) {
- e += sizeof(resume) - 1;
- } else if (((e = strstr(line, healthd)))
- && ((e = strstr(e + sizeof(healthd) - 1, battery)))) {
- /* NB: healthd is roughly 150us late, worth the price to
- * deal with ntp-induced or hardware clock drift. */
- e += sizeof(battery) - 1;
- } else if ((e = strstr(line, suspended))) {
- e += sizeof(suspended) - 1;
- e = readSeconds(e, &time);
- if (!e) {
- continue;
- }
- add_entry = false;
- suspended_pending = true;
- suspended_monotonic = monotonic;
- suspended_diff = time;
- } else {
- continue;
- }
- if (add_entry) {
- /* look for "????-??-?? ??:??:??.????????? UTC" */
- cp = strstr(e, " UTC");
- if (!cp || ((cp - e) < 29) || (cp[-10] != '.')) {
- continue;
- }
- e = cp - 29;
- cp = readSeconds(cp - 10, &time);
- if (!cp) {
- continue;
- }
- cp = strptime(e, "%Y-%m-%d %H:%M:%S.", &tm);
- if (!cp) {
- continue;
- }
- cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, utc, 1);
- time.tv_sec = mktime(&tm);
- if (cp) {
- setenv(tz, cp, 1);
- free(cp);
- } else {
- unsetenv(tz);
- }
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- list->time = time;
- subTimespec(&list->convert, &time, &monotonic);
- list_add_tail(&convertHead, &list->node);
- }
- if (suspended_pending && !list_empty(&convertHead)) {
- list = node_to_item(list_tail(&convertHead),
- struct conversionList, node);
- if (subTimespec(&time,
- subTimespec(&time,
- &list->time,
- &list->convert),
- &suspended_monotonic)->tv_sec > 0) {
- /* resume, what is convert factor before? */
- subTimespec(&convert, &list->convert, &suspended_diff);
- } else {
- /* suspend */
- convert = list->convert;
- }
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just before sleep */
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_tail(&convertHead, &list->node);
- /* breakpoint just after sleep */
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_tail(&convertHead, &list->node);
- suspended_pending = false;
- }
- }
- pclose(p);
- }
- /* last entry is our current time conversion */
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- clock_gettime(CLOCK_REALTIME, &list->time);
- clock_gettime(CLOCK_MONOTONIC, &convert);
- clock_gettime(CLOCK_MONOTONIC, &time);
- /* Correct for instant clock_gettime latency (syscall or ~30ns) */
- subTimespec(&time, &convert, subTimespec(&time, &time, &convert));
- /* Calculate conversion factor */
- subTimespec(&list->convert, &list->time, &time);
- list_add_tail(&convertHead, &list->node);
- if (suspended_pending) {
- /* manufacture a suspend @ point before */
+ if (suspended_pending && !list_empty(&convertHead)) {
+ list = node_to_item(list_tail(&convertHead), struct conversionList,
+ node);
+ if (subTimespec(&time, subTimespec(&time, &list->time, &list->convert),
+ &suspended_monotonic)
+ ->tv_sec > 0) {
+ /* resume, what is convert factor before? */
subTimespec(&convert, &list->convert, &suspended_diff);
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just after sleep */
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_head(&convertHead, &list->node);
- /* breakpoint just before sleep */
- list = calloc(1, sizeof(struct conversionList));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_head(&convertHead, &list->node);
+ } else {
+ /* suspend */
+ convert = list->convert;
+ }
+ time = suspended_monotonic;
+ sumTimespec(&time, &convert);
+ /* breakpoint just before sleep */
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ list->time = time;
+ list->convert = convert;
+ list_add_tail(&convertHead, &list->node);
+ /* breakpoint just after sleep */
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ list->time = time;
+ sumTimespec(&list->time, &suspended_diff);
+ list->convert = convert;
+ sumTimespec(&list->convert, &suspended_diff);
+ list_add_tail(&convertHead, &list->node);
+ suspended_pending = false;
}
+ }
+ pclose(p);
}
+ /* last entry is our current time conversion */
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ clock_gettime(CLOCK_REALTIME, &list->time);
+ clock_gettime(CLOCK_MONOTONIC, &convert);
+ clock_gettime(CLOCK_MONOTONIC, &time);
+ /* Correct for instant clock_gettime latency (syscall or ~30ns) */
+ subTimespec(&time, &convert, subTimespec(&time, &time, &convert));
+ /* Calculate conversion factor */
+ subTimespec(&list->convert, &list->time, &time);
+ list_add_tail(&convertHead, &list->node);
+ if (suspended_pending) {
+ /* manufacture a suspend @ point before */
+ subTimespec(&convert, &list->convert, &suspended_diff);
+ time = suspended_monotonic;
+ sumTimespec(&time, &convert);
+ /* breakpoint just after sleep */
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ list->time = time;
+ sumTimespec(&list->time, &suspended_diff);
+ list->convert = convert;
+ sumTimespec(&list->convert, &suspended_diff);
+ list_add_head(&convertHead, &list->node);
+ /* breakpoint just before sleep */
+ list = calloc(1, sizeof(struct conversionList));
+ list_init(&list->node);
+ list->time = time;
+ list->convert = convert;
+ list_add_head(&convertHead, &list->node);
+ }
+ }
- /* Find the breakpoint in the conversion list */
- list = node_to_item(list_head(&convertHead), struct conversionList, node);
- next = NULL;
- list_for_each(node, &convertHead) {
- next = node_to_item(node, struct conversionList, node);
- if (entry->tv_sec < next->time.tv_sec) {
- break;
- } else if (entry->tv_sec == next->time.tv_sec) {
- if (entry->tv_nsec < next->time.tv_nsec) {
- break;
- }
+ /* Find the breakpoint in the conversion list */
+ list = node_to_item(list_head(&convertHead), struct conversionList, node);
+ next = NULL;
+ list_for_each(node, &convertHead) {
+ next = node_to_item(node, struct conversionList, node);
+ if (entry->tv_sec < next->time.tv_sec) {
+ break;
+ } else if (entry->tv_sec == next->time.tv_sec) {
+ if (entry->tv_nsec < next->time.tv_nsec) {
+ break;
+ }
+ }
+ list = next;
+ }
+
+ /* blend time from one breakpoint to the next */
+ convert = list->convert;
+ if (next) {
+ unsigned long long total, run;
+
+ total = nsecTimespec(subTimespec(&time, &next->time, &list->time));
+ time.tv_sec = entry->tv_sec;
+ time.tv_nsec = entry->tv_nsec;
+ run = nsecTimespec(subTimespec(&time, &time, &list->time));
+ if (run < total) {
+ long long crun;
+
+ float f = nsecTimespec(subTimespec(&time, &next->convert, &convert));
+ f *= run;
+ f /= total;
+ crun = f;
+ convert.tv_sec += crun / (long long)NS_PER_SEC;
+ if (crun < 0) {
+ convert.tv_nsec -= (-crun) % NS_PER_SEC;
+ if (convert.tv_nsec < 0) {
+ convert.tv_nsec += NS_PER_SEC;
+ convert.tv_sec -= 1;
}
- list = next;
- }
-
- /* blend time from one breakpoint to the next */
- convert = list->convert;
- if (next) {
- unsigned long long total, run;
-
- total = nsecTimespec(subTimespec(&time, &next->time, &list->time));
- time.tv_sec = entry->tv_sec;
- time.tv_nsec = entry->tv_nsec;
- run = nsecTimespec(subTimespec(&time, &time, &list->time));
- if (run < total) {
- long long crun;
-
- float f = nsecTimespec(subTimespec(&time, &next->convert, &convert));
- f *= run;
- f /= total;
- crun = f;
- convert.tv_sec += crun / (long long)NS_PER_SEC;
- if (crun < 0) {
- convert.tv_nsec -= (-crun) % NS_PER_SEC;
- if (convert.tv_nsec < 0) {
- convert.tv_nsec += NS_PER_SEC;
- convert.tv_sec -= 1;
- }
- } else {
- convert.tv_nsec += crun % NS_PER_SEC;
- if (convert.tv_nsec >= (long)NS_PER_SEC) {
- convert.tv_nsec -= NS_PER_SEC;
- convert.tv_sec += 1;
- }
- }
+ } else {
+ convert.tv_nsec += crun % NS_PER_SEC;
+ if (convert.tv_nsec >= (long)NS_PER_SEC) {
+ convert.tv_nsec -= NS_PER_SEC;
+ convert.tv_sec += 1;
}
+ }
}
+ }
- /* Apply the correction factor */
- result->tv_sec = entry->tv_sec;
- result->tv_nsec = entry->tv_nsec;
- subTimespec(result, result, &convert);
+ /* Apply the correction factor */
+ result->tv_sec = entry->tv_sec;
+ result->tv_nsec = entry->tv_nsec;
+ subTimespec(result, result, &convert);
}
+#endif
/**
* Formats a log message into a buffer
@@ -1491,295 +1508,295 @@
* Returns NULL on malloc error
*/
-LIBLOG_ABI_PUBLIC char *android_log_formatLogLine (
- AndroidLogFormat *p_format,
- char *defaultBuffer,
- size_t defaultBufferSize,
- const AndroidLogEntry *entry,
- size_t *p_outLength)
-{
+LIBLOG_ABI_PUBLIC char* android_log_formatLogLine(AndroidLogFormat* p_format,
+ char* defaultBuffer,
+ size_t defaultBufferSize,
+ const AndroidLogEntry* entry,
+ size_t* p_outLength) {
#if !defined(_WIN32)
- struct tm tmBuf;
+ struct tm tmBuf;
#endif
- struct tm* ptm;
- /* good margin, 23+nul for msec, 26+nul for usec, 29+nul to nsec */
- char timeBuf[64];
- char prefixBuf[128], suffixBuf[128];
- char priChar;
- int prefixSuffixIsHeaderFooter = 0;
- char *ret;
- time_t now;
- unsigned long nsec;
+ struct tm* ptm;
+ /* good margin, 23+nul for msec, 26+nul for usec, 29+nul to nsec */
+ char timeBuf[64];
+ char prefixBuf[128], suffixBuf[128];
+ char priChar;
+ int prefixSuffixIsHeaderFooter = 0;
+ char* ret;
+ time_t now;
+ unsigned long nsec;
- priChar = filterPriToChar(entry->priority);
- size_t prefixLen = 0, suffixLen = 0;
- size_t len;
+ priChar = filterPriToChar(entry->priority);
+ size_t prefixLen = 0, suffixLen = 0;
+ size_t len;
- /*
- * Get the current date/time in pretty form
- *
- * It's often useful when examining a log with "less" to jump to
- * a specific point in the file by searching for the date/time stamp.
- * For this reason it's very annoying to have regexp meta characters
- * in the time stamp. Don't use forward slashes, parenthesis,
- * brackets, asterisks, or other special chars here.
- *
- * The caller may have affected the timezone environment, this is
- * expected to be sensitive to that.
- */
- now = entry->tv_sec;
- nsec = entry->tv_nsec;
- if (p_format->monotonic_output) {
- // prevent convertMonotonic from being called if logd is monotonic
- if (android_log_clockid() != CLOCK_MONOTONIC) {
- struct timespec time;
- convertMonotonic(&time, entry);
- now = time.tv_sec;
- nsec = time.tv_nsec;
- }
+ /*
+ * Get the current date/time in pretty form
+ *
+ * It's often useful when examining a log with "less" to jump to
+ * a specific point in the file by searching for the date/time stamp.
+ * For this reason it's very annoying to have regexp meta characters
+ * in the time stamp. Don't use forward slashes, parenthesis,
+ * brackets, asterisks, or other special chars here.
+ *
+ * The caller may have affected the timezone environment, this is
+ * expected to be sensitive to that.
+ */
+ now = entry->tv_sec;
+ nsec = entry->tv_nsec;
+#if __ANDROID__
+ if (p_format->monotonic_output) {
+ /* prevent convertMonotonic from being called if logd is monotonic */
+ if (android_log_clockid() != CLOCK_MONOTONIC) {
+ struct timespec time;
+ convertMonotonic(&time, entry);
+ now = time.tv_sec;
+ nsec = time.tv_nsec;
}
- if (now < 0) {
- nsec = NS_PER_SEC - nsec;
- }
- if (p_format->epoch_output || p_format->monotonic_output) {
- ptm = NULL;
- snprintf(timeBuf, sizeof(timeBuf),
- p_format->monotonic_output ? "%6lld" : "%19lld",
- (long long)now);
- } else {
+ }
+#endif
+ if (now < 0) {
+ nsec = NS_PER_SEC - nsec;
+ }
+ if (p_format->epoch_output || p_format->monotonic_output) {
+ ptm = NULL;
+ snprintf(timeBuf, sizeof(timeBuf),
+ p_format->monotonic_output ? "%6lld" : "%19lld", (long long)now);
+ } else {
#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
+ ptm = localtime_r(&now, &tmBuf);
#else
- ptm = localtime(&now);
+ ptm = localtime(&now);
#endif
- strftime(timeBuf, sizeof(timeBuf),
- &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3],
- ptm);
- }
- len = strlen(timeBuf);
- if (p_format->nsec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
- ".%09ld", nsec);
- } else if (p_format->usec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
- ".%06ld", nsec / US_PER_NSEC);
- } else {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len,
- ".%03ld", nsec / MS_PER_NSEC);
- }
- if (p_format->zone_output && ptm) {
- strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm);
- }
+ strftime(timeBuf, sizeof(timeBuf),
+ &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3], ptm);
+ }
+ len = strlen(timeBuf);
+ if (p_format->nsec_time_output) {
+ len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%09ld", nsec);
+ } else if (p_format->usec_time_output) {
+ len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%06ld",
+ nsec / US_PER_NSEC);
+ } else {
+ len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%03ld",
+ nsec / MS_PER_NSEC);
+ }
+ if (p_format->zone_output && ptm) {
+ strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm);
+ }
- /*
- * Construct a buffer containing the log header and log message.
- */
- if (p_format->colored_output) {
- prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm",
- colorFromPri(entry->priority));
- prefixLen = MIN(prefixLen, sizeof(prefixBuf));
- suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m");
- suffixLen = MIN(suffixLen, sizeof(suffixBuf));
- }
+ /*
+ * Construct a buffer containing the log header and log message.
+ */
+ if (p_format->colored_output) {
+ prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[38;5;%dm",
+ colorFromPri(entry->priority));
+ prefixLen = MIN(prefixLen, sizeof(prefixBuf));
+ suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), "\x1B[0m");
+ suffixLen = MIN(suffixLen, sizeof(suffixBuf));
+ }
- char uid[16];
- uid[0] = '\0';
- if (p_format->uid_output) {
- if (entry->uid >= 0) {
-
- /*
- * This code is Android specific, bionic guarantees that
- * calls to non-reentrant getpwuid() are thread safe.
- */
+ char uid[16];
+ uid[0] = '\0';
+ if (p_format->uid_output) {
+ if (entry->uid >= 0) {
+/*
+ * This code is Android specific, bionic guarantees that
+ * calls to non-reentrant getpwuid() are thread safe.
+ */
+#if !defined(__MINGW32__)
+#if (FAKE_LOG_DEVICE == 0)
#ifndef __BIONIC__
-#warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
+#warning \
+ "This code assumes that getpwuid is thread safe, only true with Bionic!"
#endif
- struct passwd* pwd = getpwuid(entry->uid);
- if (pwd && (strlen(pwd->pw_name) <= 5)) {
- snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
- } else {
- // Not worth parsing package list, names all longer than 5
- snprintf(uid, sizeof(uid), "%5d:", entry->uid);
- }
- } else {
- snprintf(uid, sizeof(uid), " ");
- }
- }
-
- switch (p_format->format) {
- case FORMAT_TAG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c/%-8.*s: ", priChar, (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_PROCESS:
- len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
- " (%.*s)\n", (int)entry->tagLen, entry->tag);
- suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c(%s%5d) ", priChar, uid, entry->pid);
- break;
- case FORMAT_THREAD:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c(%s%5d:%5d) ", priChar, uid, entry->pid, entry->tid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_RAW:
- prefixBuf[prefixLen] = 0;
- len = 0;
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_TIME:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar,
- (int)entry->tagLen, entry->tag, uid, entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_THREADTIME:
- ret = strchr(uid, ':');
- if (ret) {
- *ret = ' ';
- }
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid,
- entry->tid, priChar, (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_LONG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "[ %s %s%5d:%5d %c/%-8.*s ]\n",
- timeBuf, uid, entry->pid, entry->tid, priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n\n");
- suffixLen += 2;
- prefixSuffixIsHeaderFooter = 1;
- break;
- case FORMAT_BRIEF:
- default:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag,
- uid, entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- }
-
- /* snprintf has a weird return value. It returns what would have been
- * written given a large enough buffer. In the case that the prefix is
- * longer then our buffer(128), it messes up the calculations below
- * possibly causing heap corruption. To avoid this we double check and
- * set the length at the maximum (size minus null byte)
- */
- prefixLen += len;
- if (prefixLen >= sizeof(prefixBuf)) {
- prefixLen = sizeof(prefixBuf) - 1;
- prefixBuf[sizeof(prefixBuf) - 1] = '\0';
- }
- if (suffixLen >= sizeof(suffixBuf)) {
- suffixLen = sizeof(suffixBuf) - 1;
- suffixBuf[sizeof(suffixBuf) - 2] = '\n';
- suffixBuf[sizeof(suffixBuf) - 1] = '\0';
- }
-
- /* the following code is tragically unreadable */
-
- size_t numLines;
- char *p;
- size_t bufferSize;
- const char *pm;
-
- if (prefixSuffixIsHeaderFooter) {
- /* we're just wrapping message with a header/footer */
- numLines = 1;
+#endif
+ struct passwd* pwd = getpwuid(entry->uid);
+ if (pwd && (strlen(pwd->pw_name) <= 5)) {
+ snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
+ } else
+#endif
+ {
+ /* Not worth parsing package list, names all longer than 5 */
+ snprintf(uid, sizeof(uid), "%5d:", entry->uid);
+ }
} else {
- pm = entry->message;
- numLines = 0;
-
- /*
- * The line-end finding here must match the line-end finding
- * in for ( ... numLines...) loop below
- */
- while (pm < (entry->message + entry->messageLen)) {
- if (*pm++ == '\n') numLines++;
- }
- /* plus one line for anything not newline-terminated at the end */
- if (pm > entry->message && *(pm-1) != '\n') numLines++;
+ snprintf(uid, sizeof(uid), " ");
}
+ }
+
+ switch (p_format->format) {
+ case FORMAT_TAG:
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%c/%-8.*s: ", priChar, (int)entry->tagLen, entry->tag);
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ case FORMAT_PROCESS:
+ len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen,
+ " (%.*s)\n", (int)entry->tagLen, entry->tag);
+ suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%c(%s%5d) ", priChar, uid, entry->pid);
+ break;
+ case FORMAT_THREAD:
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%c(%s%5d:%5d) ", priChar, uid, entry->pid, entry->tid);
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ case FORMAT_RAW:
+ prefixBuf[prefixLen] = 0;
+ len = 0;
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ case FORMAT_TIME:
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar,
+ (int)entry->tagLen, entry->tag, uid, entry->pid);
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ case FORMAT_THREADTIME:
+ ret = strchr(uid, ':');
+ if (ret) {
+ *ret = ' ';
+ }
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid,
+ entry->tid, priChar, (int)entry->tagLen, entry->tag);
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ case FORMAT_LONG:
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "[ %s %s%5d:%5d %c/%-8.*s ]\n", timeBuf, uid, entry->pid,
+ entry->tid, priChar, (int)entry->tagLen, entry->tag);
+ strcpy(suffixBuf + suffixLen, "\n\n");
+ suffixLen += 2;
+ prefixSuffixIsHeaderFooter = 1;
+ break;
+ case FORMAT_BRIEF:
+ default:
+ len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
+ "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen,
+ entry->tag, uid, entry->pid);
+ strcpy(suffixBuf + suffixLen, "\n");
+ ++suffixLen;
+ break;
+ }
+
+ /* snprintf has a weird return value. It returns what would have been
+ * written given a large enough buffer. In the case that the prefix is
+ * longer then our buffer(128), it messes up the calculations below
+ * possibly causing heap corruption. To avoid this we double check and
+ * set the length at the maximum (size minus null byte)
+ */
+ prefixLen += len;
+ if (prefixLen >= sizeof(prefixBuf)) {
+ prefixLen = sizeof(prefixBuf) - 1;
+ prefixBuf[sizeof(prefixBuf) - 1] = '\0';
+ }
+ if (suffixLen >= sizeof(suffixBuf)) {
+ suffixLen = sizeof(suffixBuf) - 1;
+ suffixBuf[sizeof(suffixBuf) - 2] = '\n';
+ suffixBuf[sizeof(suffixBuf) - 1] = '\0';
+ }
+
+ /* the following code is tragically unreadable */
+
+ size_t numLines;
+ char* p;
+ size_t bufferSize;
+ const char* pm;
+
+ if (prefixSuffixIsHeaderFooter) {
+ /* we're just wrapping message with a header/footer */
+ numLines = 1;
+ } else {
+ pm = entry->message;
+ numLines = 0;
/*
- * this is an upper bound--newlines in message may be counted
- * extraneously
+ * The line-end finding here must match the line-end finding
+ * in for ( ... numLines...) loop below
*/
- bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
+ while (pm < (entry->message + entry->messageLen)) {
+ if (*pm++ == '\n') numLines++;
+ }
+ /* plus one line for anything not newline-terminated at the end */
+ if (pm > entry->message && *(pm - 1) != '\n') numLines++;
+ }
+
+ /*
+ * this is an upper bound--newlines in message may be counted
+ * extraneously
+ */
+ bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
+ if (p_format->printable_output) {
+ /* Calculate extra length to convert non-printable to printable */
+ bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
+ } else {
+ bufferSize += entry->messageLen;
+ }
+
+ if (defaultBufferSize >= bufferSize) {
+ ret = defaultBuffer;
+ } else {
+ ret = (char*)malloc(bufferSize);
+
+ if (ret == NULL) {
+ return ret;
+ }
+ }
+
+ ret[0] = '\0'; /* to start strcat off */
+
+ p = ret;
+ pm = entry->message;
+
+ if (prefixSuffixIsHeaderFooter) {
+ strcat(p, prefixBuf);
+ p += prefixLen;
if (p_format->printable_output) {
- /* Calculate extra length to convert non-printable to printable */
- bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
+ p += convertPrintable(p, entry->message, entry->messageLen);
} else {
- bufferSize += entry->messageLen;
+ strncat(p, entry->message, entry->messageLen);
+ p += entry->messageLen;
}
+ strcat(p, suffixBuf);
+ p += suffixLen;
+ } else {
+ do {
+ const char* lineStart;
+ size_t lineLen;
+ lineStart = pm;
- if (defaultBufferSize >= bufferSize) {
- ret = defaultBuffer;
- } else {
- ret = (char *)malloc(bufferSize);
+ /* Find the next end-of-line in message */
+ while (pm < (entry->message + entry->messageLen) && *pm != '\n') pm++;
+ lineLen = pm - lineStart;
- if (ret == NULL) {
- return ret;
- }
- }
+ strcat(p, prefixBuf);
+ p += prefixLen;
+ if (p_format->printable_output) {
+ p += convertPrintable(p, lineStart, lineLen);
+ } else {
+ strncat(p, lineStart, lineLen);
+ p += lineLen;
+ }
+ strcat(p, suffixBuf);
+ p += suffixLen;
- ret[0] = '\0'; /* to start strcat off */
+ if (*pm == '\n') pm++;
+ } while (pm < (entry->message + entry->messageLen));
+ }
- p = ret;
- pm = entry->message;
+ if (p_outLength != NULL) {
+ *p_outLength = p - ret;
+ }
- if (prefixSuffixIsHeaderFooter) {
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, entry->message, entry->messageLen);
- } else {
- strncat(p, entry->message, entry->messageLen);
- p += entry->messageLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
- } else {
- do {
- const char *lineStart;
- size_t lineLen;
- lineStart = pm;
-
- /* Find the next end-of-line in message */
- while (pm < (entry->message + entry->messageLen)
- && *pm != '\n') pm++;
- lineLen = pm - lineStart;
-
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, lineStart, lineLen);
- } else {
- strncat(p, lineStart, lineLen);
- p += lineLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
-
- if (*pm == '\n') pm++;
- } while (pm < (entry->message + entry->messageLen));
- }
-
- if (p_outLength != NULL) {
- *p_outLength = p - ret;
- }
-
- return ret;
+ return ret;
}
/**
@@ -1788,41 +1805,38 @@
* Returns count bytes written
*/
-LIBLOG_ABI_PUBLIC int android_log_printLogLine(
- AndroidLogFormat *p_format,
- int fd,
- const AndroidLogEntry *entry)
-{
- int ret;
- char defaultBuffer[512];
- char *outBuffer = NULL;
- size_t totalLen;
+LIBLOG_ABI_PUBLIC int android_log_printLogLine(AndroidLogFormat* p_format,
+ int fd,
+ const AndroidLogEntry* entry) {
+ int ret;
+ char defaultBuffer[512];
+ char* outBuffer = NULL;
+ size_t totalLen;
- outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
- sizeof(defaultBuffer), entry, &totalLen);
+ outBuffer = android_log_formatLogLine(
+ p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);
- if (!outBuffer) return -1;
+ if (!outBuffer) return -1;
- do {
- ret = write(fd, outBuffer, totalLen);
- } while (ret < 0 && errno == EINTR);
+ do {
+ ret = write(fd, outBuffer, totalLen);
+ } while (ret < 0 && errno == EINTR);
- if (ret < 0) {
- fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
- ret = 0;
- goto done;
- }
+ if (ret < 0) {
+ fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
+ ret = 0;
+ goto done;
+ }
- if (((size_t)ret) < totalLen) {
- fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
- (int)totalLen);
- goto done;
- }
+ if (((size_t)ret) < totalLen) {
+ fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret, (int)totalLen);
+ goto done;
+ }
done:
- if (outBuffer != defaultBuffer) {
- free(outBuffer);
- }
+ if (outBuffer != defaultBuffer) {
+ free(outBuffer);
+ }
- return ret;
+ return ret;
}
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index e1b81aa..c3ed8a2 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -29,591 +29,571 @@
#include "logger.h"
static int pmsgAvailable(log_id_t logId);
-static int pmsgVersion(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
-static int pmsgRead(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg);
-static void pmsgClose(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp);
-static int pmsgClear(struct android_log_logger *logger,
- struct android_log_transport_context *transp);
+static int pmsgVersion(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
+static int pmsgRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg);
+static void pmsgClose(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp);
+static int pmsgClear(struct android_log_logger* logger,
+ struct android_log_transport_context* transp);
LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = {
- .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node },
- .name = "pmsg",
- .available = pmsgAvailable,
- .version = pmsgVersion,
- .read = pmsgRead,
- .poll = NULL,
- .close = pmsgClose,
- .clear = pmsgClear,
- .setSize = NULL,
- .getSize = NULL,
- .getReadableSize = NULL,
- .getPrune = NULL,
- .setPrune = NULL,
- .getStats = NULL,
+ .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node },
+ .name = "pmsg",
+ .available = pmsgAvailable,
+ .version = pmsgVersion,
+ .read = pmsgRead,
+ .poll = NULL,
+ .close = pmsgClose,
+ .clear = pmsgClear,
+ .setSize = NULL,
+ .getSize = NULL,
+ .getReadableSize = NULL,
+ .getPrune = NULL,
+ .setPrune = NULL,
+ .getStats = NULL,
};
-static int pmsgAvailable(log_id_t logId)
-{
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
- }
- if (access("/dev/pmsg0", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
+static int pmsgAvailable(log_id_t logId) {
+ if (logId > LOG_ID_SECURITY) {
+ return -EINVAL;
+ }
+ if (access("/dev/pmsg0", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
}
/* Determine the credentials of the caller */
-static bool uid_has_log_permission(uid_t uid)
-{
- return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT) || (uid == AID_LOGD);
+static bool uid_has_log_permission(uid_t uid) {
+ return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT) ||
+ (uid == AID_LOGD);
}
-static uid_t get_best_effective_uid()
-{
- uid_t euid;
- uid_t uid;
- gid_t gid;
- ssize_t i;
- static uid_t last_uid = (uid_t) -1;
+static uid_t get_best_effective_uid() {
+ uid_t euid;
+ uid_t uid;
+ gid_t gid;
+ ssize_t i;
+ static uid_t last_uid = (uid_t)-1;
- if (last_uid != (uid_t) -1) {
- return last_uid;
- }
- uid = __android_log_uid();
- if (uid_has_log_permission(uid)) {
- return last_uid = uid;
- }
- euid = geteuid();
- if (uid_has_log_permission(euid)) {
- return last_uid = euid;
- }
- gid = getgid();
- if (uid_has_log_permission(gid)) {
- return last_uid = gid;
- }
- gid = getegid();
- if (uid_has_log_permission(gid)) {
- return last_uid = gid;
- }
- i = getgroups((size_t) 0, NULL);
- if (i > 0) {
- gid_t list[i];
-
- getgroups(i, list);
- while (--i >= 0) {
- if (uid_has_log_permission(list[i])) {
- return last_uid = list[i];
- }
- }
- }
+ if (last_uid != (uid_t)-1) {
+ return last_uid;
+ }
+ uid = __android_log_uid();
+ if (uid_has_log_permission(uid)) {
return last_uid = uid;
+ }
+ euid = geteuid();
+ if (uid_has_log_permission(euid)) {
+ return last_uid = euid;
+ }
+ gid = getgid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ gid = getegid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ i = getgroups((size_t)0, NULL);
+ if (i > 0) {
+ gid_t list[i];
+
+ getgroups(i, list);
+ while (--i >= 0) {
+ if (uid_has_log_permission(list[i])) {
+ return last_uid = list[i];
+ }
+ }
+ }
+ return last_uid = uid;
}
-static int pmsgClear(struct android_log_logger *logger __unused,
- struct android_log_transport_context *transp __unused)
-{
- if (uid_has_log_permission(get_best_effective_uid())) {
- return unlink("/sys/fs/pstore/pmsg-ramoops-0");
- }
- errno = EPERM;
- return -1;
+static int pmsgClear(struct android_log_logger* logger __unused,
+ struct android_log_transport_context* transp __unused) {
+ if (uid_has_log_permission(get_best_effective_uid())) {
+ return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+ }
+ errno = EPERM;
+ return -1;
}
/*
* returns the logger version
*/
-static int pmsgVersion(struct android_log_logger *logger __unused,
- struct android_log_transport_context *transp __unused)
-{
- return 4;
+static int pmsgVersion(struct android_log_logger* logger __unused,
+ struct android_log_transport_context* transp __unused) {
+ return 4;
}
-static int pmsgRead(struct android_log_logger_list *logger_list,
- struct android_log_transport_context *transp,
- struct log_msg *log_msg)
-{
- ssize_t ret;
- off_t current, next;
- uid_t uid;
- struct android_log_logger *logger;
- struct __attribute__((__packed__)) {
- android_pmsg_log_header_t p;
- android_log_header_t l;
- uint8_t prio;
- } buf;
- static uint8_t preread_count;
- bool is_system;
+static int pmsgRead(struct android_log_logger_list* logger_list,
+ struct android_log_transport_context* transp,
+ struct log_msg* log_msg) {
+ ssize_t ret;
+ off_t current, next;
+ uid_t uid;
+ struct android_log_logger* logger;
+ struct __attribute__((__packed__)) {
+ android_pmsg_log_header_t p;
+ android_log_header_t l;
+ uint8_t prio;
+ } buf;
+ static uint8_t preread_count;
+ bool is_system;
- memset(log_msg, 0, sizeof(*log_msg));
+ memset(log_msg, 0, sizeof(*log_msg));
- if (atomic_load(&transp->context.fd) <= 0) {
- int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
+ if (atomic_load(&transp->context.fd) <= 0) {
+ int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- return -errno;
- }
- if (fd == 0) { /* Argggg */
- fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
- close(0);
- if (fd < 0) {
- return -errno;
- }
- }
- i = atomic_exchange(&transp->context.fd, fd);
- if ((i > 0) && (i != fd)) {
- close(i);
- }
- preread_count = 0;
+ if (fd < 0) {
+ return -errno;
}
+ if (fd == 0) { /* Argggg */
+ fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
+ close(0);
+ if (fd < 0) {
+ return -errno;
+ }
+ }
+ i = atomic_exchange(&transp->context.fd, fd);
+ if ((i > 0) && (i != fd)) {
+ close(i);
+ }
+ preread_count = 0;
+ }
- while(1) {
- int fd;
+ while (1) {
+ int fd;
- if (preread_count < sizeof(buf)) {
- fd = atomic_load(&transp->context.fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd,
- &buf.p.magic + preread_count,
- sizeof(buf) - preread_count));
- if (ret < 0) {
- return -errno;
- }
- preread_count += ret;
- }
- if (preread_count != sizeof(buf)) {
- return preread_count ? -EIO : -EAGAIN;
- }
- if ((buf.p.magic != LOGGER_MAGIC) ||
- (buf.p.len <= sizeof(buf)) ||
- (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) ||
- (buf.l.id >= LOG_ID_MAX) ||
- (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
- ((buf.l.id != LOG_ID_EVENTS) &&
- (buf.l.id != LOG_ID_SECURITY) &&
- ((buf.prio == ANDROID_LOG_UNKNOWN) ||
- (buf.prio == ANDROID_LOG_DEFAULT) ||
- (buf.prio >= ANDROID_LOG_SILENT)))) {
- do {
- memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
- } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
- continue;
- }
- preread_count = 0;
+ if (preread_count < sizeof(buf)) {
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ ret = TEMP_FAILURE_RETRY(
+ read(fd, &buf.p.magic + preread_count, sizeof(buf) - preread_count));
+ if (ret < 0) {
+ return -errno;
+ }
+ preread_count += ret;
+ }
+ if (preread_count != sizeof(buf)) {
+ return preread_count ? -EIO : -EAGAIN;
+ }
+ if ((buf.p.magic != LOGGER_MAGIC) || (buf.p.len <= sizeof(buf)) ||
+ (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) ||
+ (buf.l.id >= LOG_ID_MAX) || (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
+ ((buf.l.id != LOG_ID_EVENTS) && (buf.l.id != LOG_ID_SECURITY) &&
+ ((buf.prio == ANDROID_LOG_UNKNOWN) ||
+ (buf.prio == ANDROID_LOG_DEFAULT) ||
+ (buf.prio >= ANDROID_LOG_SILENT)))) {
+ do {
+ memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+ } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+ continue;
+ }
+ preread_count = 0;
- if ((transp->logMask & (1 << buf.l.id)) &&
- ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
- ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
- ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
- (logger_list->start.tv_nsec <=
- buf.l.realtime.tv_nsec)))) &&
- (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
- uid = get_best_effective_uid();
- is_system = uid_has_log_permission(uid);
- if (is_system || (uid == buf.p.uid)) {
- char *msg = is_system ?
- log_msg->entry_v4.msg :
- log_msg->entry_v3.msg;
- *msg = buf.prio;
- fd = atomic_load(&transp->context.fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd,
- msg + sizeof(buf.prio),
- buf.p.len - sizeof(buf)));
- if (ret < 0) {
- return -errno;
- }
- if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
-
- log_msg->entry_v4.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
- log_msg->entry_v4.hdr_size = is_system ?
- sizeof(log_msg->entry_v4) :
- sizeof(log_msg->entry_v3);
- log_msg->entry_v4.pid = buf.p.pid;
- log_msg->entry_v4.tid = buf.l.tid;
- log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
- log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
- log_msg->entry_v4.lid = buf.l.id;
- if (is_system) {
- log_msg->entry_v4.uid = buf.p.uid;
- }
-
- return ret + sizeof(buf.prio) + log_msg->entry_v4.hdr_size;
- }
- }
-
+ if ((transp->logMask & (1 << buf.l.id)) &&
+ ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
+ ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
+ ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
+ (logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
+ (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
+ uid = get_best_effective_uid();
+ is_system = uid_has_log_permission(uid);
+ if (is_system || (uid == buf.p.uid)) {
+ char* msg = is_system ? log_msg->entry_v4.msg : log_msg->entry_v3.msg;
+ *msg = buf.prio;
fd = atomic_load(&transp->context.fd);
if (fd <= 0) {
- return -EBADF;
+ return -EBADF;
}
- current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
- if (current < 0) {
- return -errno;
+ ret = TEMP_FAILURE_RETRY(
+ read(fd, msg + sizeof(buf.prio), buf.p.len - sizeof(buf)));
+ if (ret < 0) {
+ return -errno;
}
- fd = atomic_load(&transp->context.fd);
- if (fd <= 0) {
- return -EBADF;
+ if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
}
- next = TEMP_FAILURE_RETRY(lseek(fd,
- (off_t)(buf.p.len - sizeof(buf)),
- SEEK_CUR));
- if (next < 0) {
- return -errno;
+
+ log_msg->entry_v4.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
+ log_msg->entry_v4.hdr_size =
+ is_system ? sizeof(log_msg->entry_v4) : sizeof(log_msg->entry_v3);
+ log_msg->entry_v4.pid = buf.p.pid;
+ log_msg->entry_v4.tid = buf.l.tid;
+ log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
+ log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
+ log_msg->entry_v4.lid = buf.l.id;
+ if (is_system) {
+ log_msg->entry_v4.uid = buf.p.uid;
}
- if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
+
+ return ret + sizeof(buf.prio) + log_msg->entry_v4.hdr_size;
+ }
}
+
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
+ if (current < 0) {
+ return -errno;
+ }
+ fd = atomic_load(&transp->context.fd);
+ if (fd <= 0) {
+ return -EBADF;
+ }
+ next = TEMP_FAILURE_RETRY(
+ lseek(fd, (off_t)(buf.p.len - sizeof(buf)), SEEK_CUR));
+ if (next < 0) {
+ return -errno;
+ }
+ if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
+ }
+ }
}
-static void pmsgClose(struct android_log_logger_list *logger_list __unused,
- struct android_log_transport_context *transp) {
- int fd = atomic_exchange(&transp->context.fd, 0);
- if (fd > 0) {
- close (fd);
- }
+static void pmsgClose(struct android_log_logger_list* logger_list __unused,
+ struct android_log_transport_context* transp) {
+ int fd = atomic_exchange(&transp->context.fd, 0);
+ if (fd > 0) {
+ close(fd);
+ }
}
-LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
- log_id_t logId,
- char prio,
- const char *prefix,
- __android_log_pmsg_file_read_fn fn, void *arg) {
- ssize_t ret;
- struct android_log_logger_list logger_list;
- struct android_log_transport_context transp;
- struct content {
- struct listnode node;
- union {
- struct logger_entry_v4 entry;
- struct logger_entry_v4 entry_v4;
- struct logger_entry_v3 entry_v3;
- struct logger_entry_v2 entry_v2;
- struct logger_entry entry_v1;
- };
- } *content;
- struct names {
- struct listnode node;
- struct listnode content;
- log_id_t id;
- char prio;
- char name[];
- } *names;
- struct listnode name_list;
- struct listnode *node, *n;
- size_t len, prefix_len;
+LIBLOG_ABI_PRIVATE ssize_t
+__android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
+ __android_log_pmsg_file_read_fn fn, void* arg) {
+ ssize_t ret;
+ struct android_log_logger_list logger_list;
+ struct android_log_transport_context transp;
+ struct content {
+ struct listnode node;
+ union {
+ struct logger_entry_v4 entry;
+ struct logger_entry_v4 entry_v4;
+ struct logger_entry_v3 entry_v3;
+ struct logger_entry_v2 entry_v2;
+ struct logger_entry entry_v1;
+ };
+ } * content;
+ struct names {
+ struct listnode node;
+ struct listnode content;
+ log_id_t id;
+ char prio;
+ char name[];
+ } * names;
+ struct listnode name_list;
+ struct listnode *node, *n;
+ size_t len, prefix_len;
- if (!fn) {
- return -EINVAL;
+ if (!fn) {
+ return -EINVAL;
+ }
+
+ /* Add just enough clues in logger_list and transp to make API function */
+ memset(&logger_list, 0, sizeof(logger_list));
+ memset(&transp, 0, sizeof(transp));
+
+ logger_list.mode =
+ ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
+ transp.logMask = (unsigned)-1;
+ if (logId != LOG_ID_ANY) {
+ transp.logMask = (1 << logId);
+ }
+ transp.logMask &=
+ ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
+ if (!transp.logMask) {
+ return -EINVAL;
+ }
+
+ /* Initialize name list */
+ list_init(&name_list);
+
+ ret = SSIZE_MAX;
+
+ /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
+ prefix_len = 0;
+ if (prefix) {
+ const char *prev = NULL, *last = NULL, *cp = prefix;
+ while ((cp = strpbrk(cp, "/:"))) {
+ prev = last;
+ last = cp;
+ cp = cp + 1;
+ }
+ if (prev) {
+ prefix = prev + 1;
+ }
+ prefix_len = strlen(prefix);
+ }
+
+ /* Read the file content */
+ while (pmsgRead(&logger_list, &transp, &transp.logMsg) > 0) {
+ char* cp;
+ size_t hdr_size = transp.logMsg.entry.hdr_size
+ ? transp.logMsg.entry.hdr_size
+ : sizeof(transp.logMsg.entry_v1);
+ char* msg = (char*)&transp.logMsg + hdr_size;
+ char* split = NULL;
+
+ if ((hdr_size < sizeof(transp.logMsg.entry_v1)) ||
+ (hdr_size > sizeof(transp.logMsg.entry))) {
+ continue;
+ }
+ /* Check for invalid sequence number */
+ if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
+ ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+ ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE)) {
+ continue;
}
- /* Add just enough clues in logger_list and transp to make API function */
- memset(&logger_list, 0, sizeof(logger_list));
- memset(&transp, 0, sizeof(transp));
-
- logger_list.mode = ANDROID_LOG_PSTORE |
- ANDROID_LOG_NONBLOCK |
- ANDROID_LOG_RDONLY;
- transp.logMask = (unsigned)-1;
- if (logId != LOG_ID_ANY) {
- transp.logMask = (1 << logId);
+ /* Determine if it has <dirbase>:<filebase> format for tag */
+ len = transp.logMsg.entry.len - sizeof(prio);
+ for (cp = msg + sizeof(prio); *cp && isprint(*cp) && !isspace(*cp) && --len;
+ ++cp) {
+ if (*cp == ':') {
+ if (split) {
+ break;
+ }
+ split = cp;
+ }
}
- transp.logMask &= ~((1 << LOG_ID_KERNEL) |
- (1 << LOG_ID_EVENTS) |
- (1 << LOG_ID_SECURITY));
- if (!transp.logMask) {
- return -EINVAL;
+ if (*cp || !split) {
+ continue;
}
- /* Initialize name list */
- list_init(&name_list);
-
- ret = SSIZE_MAX;
-
- /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
- prefix_len = 0;
- if (prefix) {
- const char *prev = NULL, *last = NULL, *cp = prefix;
- while ((cp = strpbrk(cp, "/:"))) {
- prev = last;
- last = cp;
- cp = cp + 1;
- }
- if (prev) {
- prefix = prev + 1;
- }
- prefix_len = strlen(prefix);
+ /* Filters */
+ if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
+ size_t offset;
+ /*
+ * Allow : to be a synonym for /
+ * Things we do dealing with const char * and do not alloc
+ */
+ split = strchr(prefix, ':');
+ if (split) {
+ continue;
+ }
+ split = strchr(prefix, '/');
+ if (!split) {
+ continue;
+ }
+ offset = split - prefix;
+ if ((msg[offset + sizeof(prio)] != ':') ||
+ strncmp(msg + sizeof(prio), prefix, offset)) {
+ continue;
+ }
+ ++offset;
+ if ((prefix_len > offset) && strncmp(&msg[offset + sizeof(prio)],
+ split + 1, prefix_len - offset)) {
+ continue;
+ }
}
- /* Read the file content */
- while (pmsgRead(&logger_list, &transp, &transp.logMsg) > 0) {
- char *cp;
- size_t hdr_size = transp.logMsg.entry.hdr_size ?
- transp.logMsg.entry.hdr_size : sizeof(transp.logMsg.entry_v1);
- char *msg = (char *)&transp.logMsg + hdr_size;
- char *split = NULL;
-
- if ((hdr_size < sizeof(transp.logMsg.entry_v1)) ||
- (hdr_size > sizeof(transp.logMsg.entry))) {
- continue;
- }
- /* Check for invalid sequence number */
- if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
- ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
- ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE)) {
- continue;
- }
-
- /* Determine if it has <dirbase>:<filebase> format for tag */
- len = transp.logMsg.entry.len - sizeof(prio);
- for (cp = msg + sizeof(prio);
- *cp && isprint(*cp) && !isspace(*cp) && --len;
- ++cp) {
- if (*cp == ':') {
- if (split) {
- break;
- }
- split = cp;
- }
- }
- if (*cp || !split) {
- continue;
- }
-
- /* Filters */
- if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
- size_t offset;
- /*
- * Allow : to be a synonym for /
- * Things we do dealing with const char * and do not alloc
- */
- split = strchr(prefix, ':');
- if (split) {
- continue;
- }
- split = strchr(prefix, '/');
- if (!split) {
- continue;
- }
- offset = split - prefix;
- if ((msg[offset + sizeof(prio)] != ':') ||
- strncmp(msg + sizeof(prio), prefix, offset)) {
- continue;
- }
- ++offset;
- if ((prefix_len > offset) &&
- strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
- continue;
- }
- }
-
- if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
- continue;
- }
-
- /* check if there is an existing entry */
- list_for_each(node, &name_list) {
- names = node_to_item(node, struct names, node);
- if (!strcmp(names->name, msg + sizeof(prio)) &&
- (names->id == transp.logMsg.entry.lid) &&
- (names->prio == *msg)) {
- break;
- }
- }
-
- /* We do not have an existing entry, create and add one */
- if (node == &name_list) {
- static const char numbers[] = "0123456789";
- unsigned long long nl;
-
- len = strlen(msg + sizeof(prio)) + 1;
- names = calloc(1, sizeof(*names) + len);
- if (!names) {
- ret = -ENOMEM;
- break;
- }
- strcpy(names->name, msg + sizeof(prio));
- names->id = transp.logMsg.entry.lid;
- names->prio = *msg;
- list_init(&names->content);
- /*
- * Insert in reverse numeric _then_ alpha sorted order as
- * representative of log rotation:
- *
- * log.10
- * klog.10
- * . . .
- * log.2
- * klog.2
- * log.1
- * klog.1
- * log
- * klog
- *
- * thus when we present the content, we are provided the oldest
- * first, which when 'refreshed' could spill off the end of the
- * pmsg FIFO but retaining the newest data for last with best
- * chances to survive.
- */
- nl = 0;
- cp = strpbrk(names->name, numbers);
- if (cp) {
- nl = strtoull(cp, NULL, 10);
- }
- list_for_each_reverse(node, &name_list) {
- struct names *a_name = node_to_item(node, struct names, node);
- const char *r = a_name->name;
- int compare = 0;
-
- unsigned long long nr = 0;
- cp = strpbrk(r, numbers);
- if (cp) {
- nr = strtoull(cp, NULL, 10);
- }
- if (nr != nl) {
- compare = (nl > nr) ? 1 : -1;
- }
- if (compare == 0) {
- compare = strcmp(names->name, r);
- }
- if (compare <= 0) {
- break;
- }
- }
- list_add_head(node, &names->node);
- }
-
- /* Remove any file fragments that match our sequence number */
- list_for_each_safe(node, n, &names->content) {
- content = node_to_item(node, struct content, node);
- if (transp.logMsg.entry.nsec == content->entry.nsec) {
- list_remove(&content->node);
- free(content);
- }
- }
-
- /* Add content */
- content = calloc(1, sizeof(content->node) +
- hdr_size + transp.logMsg.entry.len);
- if (!content) {
- ret = -ENOMEM;
- break;
- }
- memcpy(&content->entry, &transp.logMsg.entry,
- hdr_size + transp.logMsg.entry.len);
-
- /* Insert in sequence number sorted order, to ease reconstruction */
- list_for_each_reverse(node, &names->content) {
- if ((node_to_item(node, struct content, node))->entry.nsec <
- transp.logMsg.entry.nsec) {
- break;
- }
- }
- list_add_head(node, &content->node);
+ if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
+ continue;
}
- pmsgClose(&logger_list, &transp);
- /* Progress through all the collected files */
- list_for_each_safe(node, n, &name_list) {
- struct listnode *content_node, *m;
- char *buf;
- size_t sequence, tag_len;
-
- names = node_to_item(node, struct names, node);
-
- /* Construct content into a linear buffer */
- buf = NULL;
- len = 0;
- sequence = 0;
- tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
- list_for_each_safe(content_node, m, &names->content) {
- ssize_t add_len;
-
- content = node_to_item(content_node, struct content, node);
- add_len = content->entry.len - tag_len - sizeof(prio);
- if (add_len <= 0) {
- list_remove(content_node);
- free(content);
- continue;
- }
-
- if (!buf) {
- buf = malloc(sizeof(char));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- *buf = '\0';
- }
-
- /* Missing sequence numbers */
- while (sequence < content->entry.nsec) {
- /* plus space for enforced nul */
- buf = realloc(buf, len + sizeof(char) + sizeof(char));
- if (!buf) {
- break;
- }
- buf[len] = '\f'; /* Mark missing content with a form feed */
- buf[++len] = '\0';
- sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
- }
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- /* plus space for enforced nul */
- buf = realloc(buf, len + add_len + sizeof(char));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- memcpy(buf + len,
- (char *)&content->entry + content->entry.hdr_size +
- tag_len + sizeof(prio),
- add_len);
- len += add_len;
- buf[len] = '\0'; /* enforce trailing hidden nul */
- sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
-
- list_remove(content_node);
- free(content);
- }
- if (buf) {
- if (len) {
- /* Buffer contains enforced trailing nul just beyond length */
- ssize_t r;
- *strchr(names->name, ':') = '/'; /* Convert back to filename */
- r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
- if ((ret >= 0) && (r > 0)) {
- if (ret == SSIZE_MAX) {
- ret = r;
- } else {
- ret += r;
- }
- } else if (r < ret) {
- ret = r;
- }
- }
- free(buf);
- }
- list_remove(node);
- free(names);
+ /* check if there is an existing entry */
+ list_for_each(node, &name_list) {
+ names = node_to_item(node, struct names, node);
+ if (!strcmp(names->name, msg + sizeof(prio)) &&
+ (names->id == transp.logMsg.entry.lid) && (names->prio == *msg)) {
+ break;
+ }
}
- return (ret == SSIZE_MAX) ? -ENOENT : ret;
+
+ /* We do not have an existing entry, create and add one */
+ if (node == &name_list) {
+ static const char numbers[] = "0123456789";
+ unsigned long long nl;
+
+ len = strlen(msg + sizeof(prio)) + 1;
+ names = calloc(1, sizeof(*names) + len);
+ if (!names) {
+ ret = -ENOMEM;
+ break;
+ }
+ strcpy(names->name, msg + sizeof(prio));
+ names->id = transp.logMsg.entry.lid;
+ names->prio = *msg;
+ list_init(&names->content);
+ /*
+ * Insert in reverse numeric _then_ alpha sorted order as
+ * representative of log rotation:
+ *
+ * log.10
+ * klog.10
+ * . . .
+ * log.2
+ * klog.2
+ * log.1
+ * klog.1
+ * log
+ * klog
+ *
+ * thus when we present the content, we are provided the oldest
+ * first, which when 'refreshed' could spill off the end of the
+ * pmsg FIFO but retaining the newest data for last with best
+ * chances to survive.
+ */
+ nl = 0;
+ cp = strpbrk(names->name, numbers);
+ if (cp) {
+ nl = strtoull(cp, NULL, 10);
+ }
+ list_for_each_reverse(node, &name_list) {
+ struct names* a_name = node_to_item(node, struct names, node);
+ const char* r = a_name->name;
+ int compare = 0;
+
+ unsigned long long nr = 0;
+ cp = strpbrk(r, numbers);
+ if (cp) {
+ nr = strtoull(cp, NULL, 10);
+ }
+ if (nr != nl) {
+ compare = (nl > nr) ? 1 : -1;
+ }
+ if (compare == 0) {
+ compare = strcmp(names->name, r);
+ }
+ if (compare <= 0) {
+ break;
+ }
+ }
+ list_add_head(node, &names->node);
+ }
+
+ /* Remove any file fragments that match our sequence number */
+ list_for_each_safe(node, n, &names->content) {
+ content = node_to_item(node, struct content, node);
+ if (transp.logMsg.entry.nsec == content->entry.nsec) {
+ list_remove(&content->node);
+ free(content);
+ }
+ }
+
+ /* Add content */
+ content =
+ calloc(1, sizeof(content->node) + hdr_size + transp.logMsg.entry.len);
+ if (!content) {
+ ret = -ENOMEM;
+ break;
+ }
+ memcpy(&content->entry, &transp.logMsg.entry,
+ hdr_size + transp.logMsg.entry.len);
+
+ /* Insert in sequence number sorted order, to ease reconstruction */
+ list_for_each_reverse(node, &names->content) {
+ if ((node_to_item(node, struct content, node))->entry.nsec <
+ transp.logMsg.entry.nsec) {
+ break;
+ }
+ }
+ list_add_head(node, &content->node);
+ }
+ pmsgClose(&logger_list, &transp);
+
+ /* Progress through all the collected files */
+ list_for_each_safe(node, n, &name_list) {
+ struct listnode *content_node, *m;
+ char* buf;
+ size_t sequence, tag_len;
+
+ names = node_to_item(node, struct names, node);
+
+ /* Construct content into a linear buffer */
+ buf = NULL;
+ len = 0;
+ sequence = 0;
+ tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
+ list_for_each_safe(content_node, m, &names->content) {
+ ssize_t add_len;
+
+ content = node_to_item(content_node, struct content, node);
+ add_len = content->entry.len - tag_len - sizeof(prio);
+ if (add_len <= 0) {
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+
+ if (!buf) {
+ buf = malloc(sizeof(char));
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ *buf = '\0';
+ }
+
+ /* Missing sequence numbers */
+ while (sequence < content->entry.nsec) {
+ /* plus space for enforced nul */
+ buf = realloc(buf, len + sizeof(char) + sizeof(char));
+ if (!buf) {
+ break;
+ }
+ buf[len] = '\f'; /* Mark missing content with a form feed */
+ buf[++len] = '\0';
+ sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
+ }
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ /* plus space for enforced nul */
+ buf = realloc(buf, len + add_len + sizeof(char));
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ memcpy(buf + len,
+ (char*)&content->entry + content->entry.hdr_size + tag_len +
+ sizeof(prio),
+ add_len);
+ len += add_len;
+ buf[len] = '\0'; /* enforce trailing hidden nul */
+ sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
+
+ list_remove(content_node);
+ free(content);
+ }
+ if (buf) {
+ if (len) {
+ /* Buffer contains enforced trailing nul just beyond length */
+ ssize_t r;
+ *strchr(names->name, ':') = '/'; /* Convert back to filename */
+ r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
+ if ((ret >= 0) && (r > 0)) {
+ if (ret == SSIZE_MAX) {
+ ret = r;
+ } else {
+ ret += r;
+ }
+ } else if (r < ret) {
+ ret = r;
+ }
+ }
+ free(buf);
+ }
+ list_remove(node);
+ free(names);
+ }
+ return (ret == SSIZE_MAX) ? -ENOENT : ret;
}
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index c1c068e..e71c176 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -36,155 +36,149 @@
static int pmsgOpen();
static void pmsgClose();
static int pmsgAvailable(log_id_t logId);
-static int pmsgWrite(log_id_t logId, struct timespec *ts,
- struct iovec *vec, size_t nr);
+static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr);
LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
- .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
- .context.fd = -1,
- .name = "pmsg",
- .available = pmsgAvailable,
- .open = pmsgOpen,
- .close = pmsgClose,
- .write = pmsgWrite,
+ .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
+ .context.fd = -1,
+ .name = "pmsg",
+ .available = pmsgAvailable,
+ .open = pmsgOpen,
+ .close = pmsgClose,
+ .write = pmsgWrite,
};
-static int pmsgOpen()
-{
- int fd = atomic_load(&pmsgLoggerWrite.context.fd);
- if (fd < 0) {
- int i;
+static int pmsgOpen() {
+ int fd = atomic_load(&pmsgLoggerWrite.context.fd);
+ if (fd < 0) {
+ int i;
- fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
- if ((i >= 0) && (i != fd)) {
- close(i);
- }
+ fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+ i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
+ if ((i >= 0) && (i != fd)) {
+ close(i);
}
+ }
- return fd;
+ return fd;
}
-static void pmsgClose()
-{
- int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
- if (fd >= 0) {
- close(fd);
- }
+static void pmsgClose() {
+ int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
+ if (fd >= 0) {
+ close(fd);
+ }
}
-static int pmsgAvailable(log_id_t logId)
-{
- if (logId > LOG_ID_SECURITY) {
- return -EINVAL;
+static int pmsgAvailable(log_id_t logId) {
+ if (logId > LOG_ID_SECURITY) {
+ return -EINVAL;
+ }
+ if ((logId != LOG_ID_SECURITY) && (logId != LOG_ID_EVENTS) &&
+ !__android_log_is_debuggable()) {
+ return -EINVAL;
+ }
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ if (access("/dev/pmsg0", W_OK) == 0) {
+ return 0;
}
- if ((logId != LOG_ID_SECURITY) &&
- (logId != LOG_ID_EVENTS) &&
- !__android_log_is_debuggable()) {
- return -EINVAL;
- }
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (access("/dev/pmsg0", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
+ return -EBADF;
+ }
+ return 1;
}
/*
* Extract a 4-byte value from a byte stream.
*/
-static inline uint32_t get4LE(const uint8_t* src)
-{
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+static inline uint32_t get4LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-static int pmsgWrite(log_id_t logId, struct timespec *ts,
- struct iovec *vec, size_t nr)
-{
- static const unsigned headerLength = 2;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- android_pmsg_log_header_t pmsgHeader;
- size_t i, payloadSize;
- ssize_t ret;
+static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr) {
+ static const unsigned headerLength = 2;
+ struct iovec newVec[nr + headerLength];
+ android_log_header_t header;
+ android_pmsg_log_header_t pmsgHeader;
+ size_t i, payloadSize;
+ ssize_t ret;
- if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- if (SNET_EVENT_LOG_TAG != get4LE(vec[0].iov_base)) {
- return -EPERM;
- }
+ if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
}
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- return -EBADF;
+ if (SNET_EVENT_LOG_TAG != get4LE(vec[0].iov_base)) {
+ return -EPERM;
}
+ }
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsgHeader;
- * // what we provide to file
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ return -EBADF;
+ }
- pmsgHeader.magic = LOGGER_MAGIC;
- pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
- pmsgHeader.uid = __android_log_uid();
- pmsgHeader.pid = getpid();
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsgHeader;
+ * // what we provide to file
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- header.id = logId;
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
+ pmsgHeader.magic = LOGGER_MAGIC;
+ pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
+ pmsgHeader.uid = __android_log_uid();
+ pmsgHeader.pid = getpid();
- newVec[0].iov_base = (unsigned char *)&pmsgHeader;
- newVec[0].iov_len = sizeof(pmsgHeader);
- newVec[1].iov_base = (unsigned char *)&header;
- newVec[1].iov_len = sizeof(header);
+ header.id = logId;
+ header.tid = gettid();
+ header.realtime.tv_sec = ts->tv_sec;
+ header.realtime.tv_nsec = ts->tv_nsec;
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+ newVec[0].iov_base = (unsigned char*)&pmsgHeader;
+ newVec[0].iov_len = sizeof(pmsgHeader);
+ newVec[1].iov_base = (unsigned char*)&header;
+ newVec[1].iov_len = sizeof(header);
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
- break;
- }
+ for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+ newVec[i].iov_base = vec[i - headerLength].iov_base;
+ payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+ if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+ newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+ if (newVec[i].iov_len) {
+ ++i;
+ }
+ payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
+ break;
}
- pmsgHeader.len += payloadSize;
+ }
+ pmsgHeader.len += payloadSize;
- ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd),
- newVec, i));
- if (ret < 0) {
- ret = errno ? -errno : -ENOTCONN;
- }
+ ret = TEMP_FAILURE_RETRY(
+ writev(atomic_load(&pmsgLoggerWrite.context.fd), newVec, i));
+ if (ret < 0) {
+ ret = errno ? -errno : -ENOTCONN;
+ }
- if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
- ret -= sizeof(header) - sizeof(pmsgHeader);
- }
+ if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
+ ret -= sizeof(header) - sizeof(pmsgHeader);
+ }
- return ret;
+ return ret;
}
/*
@@ -197,115 +191,116 @@
* Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
*/
-static inline const char *strnrchr(const char *buf, size_t len, char c) {
- const char *cp = buf + len;
- while ((--cp > buf) && (*cp != c));
- if (cp <= buf) {
- return buf + len;
- }
- return cp;
+static inline const char* strnrchr(const char* buf, size_t len, char c) {
+ const char* cp = buf + len;
+ while ((--cp > buf) && (*cp != c))
+ ;
+ if (cp <= buf) {
+ return buf + len;
+ }
+ return cp;
}
/* Write a buffer as filename references (tag = <basedir>:<basename>) */
-LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(
- log_id_t logId,
- char prio,
- const char *filename,
- const char *buf, size_t len) {
- bool weOpened;
- size_t length, packet_len;
- const char *tag;
- char *cp, *slash;
- struct timespec ts;
- struct iovec vec[3];
+LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(log_id_t logId,
+ char prio,
+ const char* filename,
+ const char* buf,
+ size_t len) {
+ bool weOpened;
+ size_t length, packet_len;
+ const char* tag;
+ char *cp, *slash;
+ struct timespec ts;
+ struct iovec vec[3];
- /* Make sure the logId value is not a bad idea */
- if ((logId == LOG_ID_KERNEL) || /* Verbotten */
- (logId == LOG_ID_EVENTS) || /* Do not support binary content */
- (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
- ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
- return -EINVAL;
- }
+ /* Make sure the logId value is not a bad idea */
+ if ((logId == LOG_ID_KERNEL) || /* Verbotten */
+ (logId == LOG_ID_EVENTS) || /* Do not support binary content */
+ (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
+ ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
+ return -EINVAL;
+ }
- clock_gettime(android_log_clockid(), &ts);
+ clock_gettime(android_log_clockid(), &ts);
- cp = strdup(filename);
- if (!cp) {
- return -ENOMEM;
- }
+ cp = strdup(filename);
+ if (!cp) {
+ return -ENOMEM;
+ }
- tag = cp;
+ tag = cp;
+ slash = strrchr(cp, '/');
+ if (slash) {
+ *slash = ':';
slash = strrchr(cp, '/');
if (slash) {
- *slash = ':';
- slash = strrchr(cp, '/');
- if (slash) {
- tag = slash + 1;
- }
+ tag = slash + 1;
+ }
+ }
+
+ length = strlen(tag) + 1;
+ packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
+
+ vec[0].iov_base = &prio;
+ vec[0].iov_len = sizeof(char);
+ vec[1].iov_base = (unsigned char*)tag;
+ vec[1].iov_len = length;
+
+ weOpened = false;
+ for (ts.tv_nsec = 0, length = len; length;
+ ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
+ ssize_t ret;
+ size_t transfer;
+
+ if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+ ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
+ len -= length;
+ break;
}
- length = strlen(tag) + 1;
- packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
-
- vec[0].iov_base = &prio;
- vec[0].iov_len = sizeof(char);
- vec[1].iov_base = (unsigned char *)tag;
- vec[1].iov_len = length;
-
- weOpened = false;
- for (ts.tv_nsec = 0, length = len;
- length;
- ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
- ssize_t ret;
- size_t transfer;
-
- if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
- ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
- len -= length;
- break;
- }
-
- transfer = length;
- if (transfer > packet_len) {
- transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
- if ((transfer < length) && (buf[transfer] == '\n')) {
- ++transfer;
- }
- }
-
- vec[2].iov_base = (unsigned char *)buf;
- vec[2].iov_len = transfer;
-
- if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
- if (!weOpened) { /* Impossible for weOpened = true here */
- __android_log_lock();
- }
- weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
- if (!weOpened) {
- __android_log_unlock();
- } else if (pmsgOpen() < 0) {
- __android_log_unlock();
- return -EBADF;
- }
- }
-
- ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
-
- if (ret <= 0) {
- if (weOpened) {
- pmsgClose();
- __android_log_unlock();
- }
- free(cp);
- return ret ? ret : (len - length);
- }
- length -= transfer;
- buf += transfer;
+ transfer = length;
+ if (transfer > packet_len) {
+ transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
+ if ((transfer < length) && (buf[transfer] == '\n')) {
+ ++transfer;
+ }
}
- if (weOpened) {
+
+ vec[2].iov_base = (unsigned char*)buf;
+ vec[2].iov_len = transfer;
+
+ if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+ if (!weOpened) { /* Impossible for weOpened = true here */
+ __android_log_lock();
+ }
+ weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
+ if (!weOpened) {
+ __android_log_unlock();
+ } else if (pmsgOpen() < 0) {
+ __android_log_unlock();
+ free(cp);
+ return -EBADF;
+ }
+ }
+
+ ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+
+ if (ret <= 0) {
+ if (weOpened) {
pmsgClose();
__android_log_unlock();
+ }
+ free(cp);
+ return ret ? ret : (len - length);
}
- free(cp);
- return len;
+ length -= transfer;
+ buf += transfer;
+ }
+ if (weOpened) {
+ pmsgClose();
+ __android_log_unlock();
+ }
+ free(cp);
+ return len;
}
diff --git a/liblog/properties.c b/liblog/properties.c
index dda09e0..0b0ef52 100644
--- a/liblog/properties.c
+++ b/liblog/properties.c
@@ -29,179 +29,173 @@
static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
-static int lock()
-{
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- /*
- * Any contention, and we can turn around and use the non-cached method
- * in less time than the system call associated with a mutex to deal with
- * the contention.
- */
- return pthread_mutex_trylock(&lock_loggable);
+static int lock() {
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ /*
+ * Any contention, and we can turn around and use the non-cached method
+ * in less time than the system call associated with a mutex to deal with
+ * the contention.
+ */
+ return pthread_mutex_trylock(&lock_loggable);
}
-static void unlock()
-{
- pthread_mutex_unlock(&lock_loggable);
+static void unlock() {
+ pthread_mutex_unlock(&lock_loggable);
}
struct cache {
- const prop_info* pinfo;
- uint32_t serial;
+ const prop_info* pinfo;
+ uint32_t serial;
};
struct cache_char {
- struct cache cache;
- unsigned char c;
+ struct cache cache;
+ unsigned char c;
};
-static int check_cache(struct cache* cache)
-{
- return cache->pinfo
- && __system_property_serial(cache->pinfo) != cache->serial;
+static int check_cache(struct cache* cache) {
+ return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
}
#define BOOLEAN_TRUE 0xFF
#define BOOLEAN_FALSE 0xFE
-static void refresh_cache(struct cache_char* cache, const char* key)
-{
- char buf[PROP_VALUE_MAX];
+static void refresh_cache(struct cache_char* cache, const char* key) {
+ char buf[PROP_VALUE_MAX];
+ if (!cache->cache.pinfo) {
+ cache->cache.pinfo = __system_property_find(key);
if (!cache->cache.pinfo) {
- cache->cache.pinfo = __system_property_find(key);
- if (!cache->cache.pinfo) {
- return;
- }
+ return;
}
- cache->cache.serial = __system_property_serial(cache->cache.pinfo);
- __system_property_read(cache->cache.pinfo, 0, buf);
- switch(buf[0]) {
- case 't': case 'T':
- cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
- break;
- case 'f': case 'F':
- cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
- break;
+ }
+ cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+ __system_property_read(cache->cache.pinfo, 0, buf);
+ switch (buf[0]) {
+ case 't':
+ case 'T':
+ cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
+ break;
+ case 'f':
+ case 'F':
+ cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
+ break;
default:
- cache->c = buf[0];
- }
+ cache->c = buf[0];
+ }
}
-static int __android_log_level(const char* tag, size_t len, int default_prio)
-{
- /* sizeof() is used on this array below */
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
- /* calculate the size of our key temporary buffer */
- const size_t taglen = tag ? len : 0;
- /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
- char* kp;
- size_t i;
- char c = 0;
+static int __android_log_level(const char* tag, size_t len, int default_prio) {
+ /* sizeof() is used on this array below */
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ /* calculate the size of our key temporary buffer */
+ const size_t taglen = tag ? len : 0;
+ /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
+ char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+ char* kp;
+ size_t i;
+ char c = 0;
+ /*
+ * Single layer cache of four properties. Priorities are:
+ * log.tag.<tag>
+ * persist.log.tag.<tag>
+ * log.tag
+ * persist.log.tag
+ * Where the missing tag matches all tags and becomes the
+ * system global default. We do not support ro.log.tag* .
+ */
+ static char last_tag[PROP_NAME_MAX];
+ static uint32_t global_serial;
+ /* some compilers erroneously see uninitialized use. !not_locked */
+ uint32_t current_global_serial = 0;
+ static struct cache_char tag_cache[2];
+ static struct cache_char global_cache[2];
+ int change_detected;
+ int global_change_detected;
+ int not_locked;
+
+ strcpy(key, log_namespace);
+
+ global_change_detected = change_detected = not_locked = lock();
+
+ if (!not_locked) {
/*
- * Single layer cache of four properties. Priorities are:
- * log.tag.<tag>
- * persist.log.tag.<tag>
- * log.tag
- * persist.log.tag
- * Where the missing tag matches all tags and becomes the
- * system global default. We do not support ro.log.tag* .
+ * check all known serial numbers to changes.
*/
- static char last_tag[PROP_NAME_MAX];
- static uint32_t global_serial;
- /* some compilers erroneously see uninitialized use. !not_locked */
- uint32_t current_global_serial = 0;
- static struct cache_char tag_cache[2];
- static struct cache_char global_cache[2];
- int change_detected;
- int global_change_detected;
- int not_locked;
+ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ if (check_cache(&tag_cache[i].cache)) {
+ change_detected = 1;
+ }
+ }
+ for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+ if (check_cache(&global_cache[i].cache)) {
+ global_change_detected = 1;
+ }
+ }
- strcpy(key, log_namespace);
+ current_global_serial = __system_property_area_serial();
+ if (current_global_serial != global_serial) {
+ change_detected = 1;
+ global_change_detected = 1;
+ }
+ }
- global_change_detected = change_detected = not_locked = lock();
-
+ if (taglen) {
+ int local_change_detected = change_detected;
if (!not_locked) {
- /*
- * check all known serial numbers to changes.
- */
+ if (!last_tag[0] || (last_tag[0] != tag[0]) ||
+ strncmp(
+ last_tag + 1, tag + 1,
+ (len < sizeof(last_tag)) ? (len - 1) : (sizeof(last_tag) - 1)) ||
+ ((len < sizeof(last_tag)) && last_tag[len])) {
+ /* invalidate log.tag.<tag> cache */
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- if (check_cache(&tag_cache[i].cache)) {
- change_detected = 1;
- }
+ tag_cache[i].cache.pinfo = NULL;
+ tag_cache[i].c = '\0';
}
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- if (check_cache(&global_cache[i].cache)) {
- global_change_detected = 1;
- }
+ last_tag[0] = '\0';
+ local_change_detected = 1;
+ }
+ if (!last_tag[0]) {
+ if (len < sizeof(last_tag)) {
+ strncpy(last_tag, tag, len);
+ last_tag[len] = '\0';
+ } else {
+ strncpy(last_tag, tag, sizeof(last_tag));
}
-
- current_global_serial = __system_property_area_serial();
- if (current_global_serial != global_serial) {
- change_detected = 1;
- global_change_detected = 1;
- }
+ }
}
+ strncpy(key + sizeof(log_namespace) - 1, tag, len);
+ key[sizeof(log_namespace) - 1 + len] = '\0';
- if (taglen) {
- int local_change_detected = change_detected;
- if (!not_locked) {
- if (!last_tag[0]
- || (last_tag[0] != tag[0])
- || strncmp(last_tag + 1, tag + 1,
- (len < sizeof(last_tag)) ?
- (len - 1) :
- (sizeof(last_tag) - 1))
- || ((len < sizeof(last_tag)) && last_tag[len])) {
- /* invalidate log.tag.<tag> cache */
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- tag_cache[i].cache.pinfo = NULL;
- tag_cache[i].c = '\0';
- }
- last_tag[0] = '\0';
- local_change_detected = 1;
- }
- if (!last_tag[0]) {
- if (len < sizeof(last_tag)) {
- strncpy(last_tag, tag, len);
- last_tag[len] = '\0';
- } else {
- strncpy(last_tag, tag, sizeof(last_tag));
- }
- }
- }
- strncpy(key + sizeof(log_namespace) - 1, tag, len);
- key[sizeof(log_namespace) - 1 + len] = '\0';
+ kp = key;
+ for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ struct cache_char* cache = &tag_cache[i];
+ struct cache_char temp_cache;
- kp = key;
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- struct cache_char* cache = &tag_cache[i];
- struct cache_char temp_cache;
+ if (not_locked) {
+ temp_cache.cache.pinfo = NULL;
+ temp_cache.c = '\0';
+ cache = &temp_cache;
+ }
+ if (local_change_detected) {
+ refresh_cache(cache, kp);
+ }
- if (not_locked) {
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- cache = &temp_cache;
- }
- if (local_change_detected) {
- refresh_cache(cache, kp);
- }
+ if (cache->c) {
+ c = cache->c;
+ break;
+ }
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
- }
+ kp = key + base_offset;
}
+ }
- switch (toupper(c)) { /* if invalid, resort to global */
+ switch (toupper(c)) { /* if invalid, resort to global */
case 'V':
case 'D':
case 'I':
@@ -211,44 +205,45 @@
case 'A':
case 'S':
case BOOLEAN_FALSE: /* Not officially supported */
- break;
+ break;
default:
- /* clear '.' after log.tag */
- key[sizeof(log_namespace) - 2] = '\0';
+ /* clear '.' after log.tag */
+ key[sizeof(log_namespace) - 2] = '\0';
- kp = key;
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- struct cache_char* cache = &global_cache[i];
- struct cache_char temp_cache;
+ kp = key;
+ for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+ struct cache_char* cache = &global_cache[i];
+ struct cache_char temp_cache;
- if (not_locked) {
- temp_cache = *cache;
- if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- }
- cache = &temp_cache;
- }
- if (global_change_detected) {
- refresh_cache(cache, kp);
- }
-
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
+ if (not_locked) {
+ temp_cache = *cache;
+ if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
+ temp_cache.cache.pinfo = NULL;
+ temp_cache.c = '\0';
+ }
+ cache = &temp_cache;
}
- break;
- }
+ if (global_change_detected) {
+ refresh_cache(cache, kp);
+ }
- if (!not_locked) {
- global_serial = current_global_serial;
- unlock();
- }
+ if (cache->c) {
+ c = cache->c;
+ break;
+ }
- switch (toupper(c)) {
+ kp = key + base_offset;
+ }
+ break;
+ }
+
+ if (!not_locked) {
+ global_serial = current_global_serial;
+ unlock();
+ }
+
+ switch (toupper(c)) {
+ /* clang-format off */
case 'V': return ANDROID_LOG_VERBOSE;
case 'D': return ANDROID_LOG_DEBUG;
case 'I': return ANDROID_LOG_INFO;
@@ -258,57 +253,53 @@
case 'A': return ANDROID_LOG_FATAL;
case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+ /* clang-format on */
+ }
+ return default_prio;
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio, const char* tag,
+ size_t len,
+ int default_prio) {
+ int logLevel = __android_log_level(tag, len, default_prio);
+ return logLevel >= 0 && prio >= logLevel;
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char* tag,
+ int default_prio) {
+ int logLevel =
+ __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
+ return logLevel >= 0 && prio >= logLevel;
+}
+
+LIBLOG_ABI_PRIVATE int __android_log_is_debuggable() {
+ static uint32_t serial;
+ static struct cache_char tag_cache;
+ static const char key[] = "ro.debuggable";
+ int ret;
+
+ if (tag_cache.c) { /* ro property does not change after set */
+ ret = tag_cache.c == '1';
+ } else if (lock()) {
+ struct cache_char temp_cache = { { NULL, -1 }, '\0' };
+ refresh_cache(&temp_cache, key);
+ ret = temp_cache.c == '1';
+ } else {
+ int change_detected = check_cache(&tag_cache.cache);
+ uint32_t current_serial = __system_property_area_serial();
+ if (current_serial != serial) {
+ change_detected = 1;
}
- return default_prio;
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable_len(int prio,
- const char* tag, size_t len,
- int default_prio)
-{
- int logLevel = __android_log_level(tag, len, default_prio);
- return logLevel >= 0 && prio >= logLevel;
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
- const char* tag,
- int default_prio)
-{
- int logLevel = __android_log_level(tag,
- (tag && *tag) ? strlen(tag) : 0,
- default_prio);
- return logLevel >= 0 && prio >= logLevel;
-}
-
-LIBLOG_ABI_PRIVATE int __android_log_is_debuggable()
-{
- static uint32_t serial;
- static struct cache_char tag_cache;
- static const char key[] = "ro.debuggable";
- int ret;
-
- if (tag_cache.c) { /* ro property does not change after set */
- ret = tag_cache.c == '1';
- } else if (lock()) {
- struct cache_char temp_cache = { { NULL, -1 }, '\0' };
- refresh_cache(&temp_cache, key);
- ret = temp_cache.c == '1';
- } else {
- int change_detected = check_cache(&tag_cache.cache);
- uint32_t current_serial = __system_property_area_serial();
- if (current_serial != serial) {
- change_detected = 1;
- }
- if (change_detected) {
- refresh_cache(&tag_cache, key);
- serial = current_serial;
- }
- ret = tag_cache.c == '1';
-
- unlock();
+ if (change_detected) {
+ refresh_cache(&tag_cache, key);
+ serial = current_serial;
}
+ ret = tag_cache.c == '1';
- return ret;
+ unlock();
+ }
+
+ return ret;
}
/*
@@ -317,100 +308,88 @@
* Use a separate lock from is_loggable to keep contention down b/25563384.
*/
struct cache2_char {
- pthread_mutex_t lock;
- uint32_t serial;
- const char* key_persist;
- struct cache_char cache_persist;
- const char* key_ro;
- struct cache_char cache_ro;
- unsigned char (*const evaluate)(const struct cache2_char *self);
+ pthread_mutex_t lock;
+ uint32_t serial;
+ const char* key_persist;
+ struct cache_char cache_persist;
+ const char* key_ro;
+ struct cache_char cache_ro;
+ unsigned char (*const evaluate)(const struct cache2_char* self);
};
-static inline unsigned char do_cache2_char(struct cache2_char *self)
-{
- uint32_t current_serial;
- int change_detected;
- unsigned char c;
+static inline unsigned char do_cache2_char(struct cache2_char* self) {
+ uint32_t current_serial;
+ int change_detected;
+ unsigned char c;
- if (pthread_mutex_trylock(&self->lock)) {
- /* We are willing to accept some race in this context */
- return self->evaluate(self);
- }
+ if (pthread_mutex_trylock(&self->lock)) {
+ /* We are willing to accept some race in this context */
+ return self->evaluate(self);
+ }
- change_detected = check_cache(&self->cache_persist.cache)
- || check_cache(&self->cache_ro.cache);
- current_serial = __system_property_area_serial();
- if (current_serial != self->serial) {
- change_detected = 1;
- }
- if (change_detected) {
- refresh_cache(&self->cache_persist, self->key_persist);
- refresh_cache(&self->cache_ro, self->key_ro);
- self->serial = current_serial;
- }
- c = self->evaluate(self);
+ change_detected = check_cache(&self->cache_persist.cache) ||
+ check_cache(&self->cache_ro.cache);
+ current_serial = __system_property_area_serial();
+ if (current_serial != self->serial) {
+ change_detected = 1;
+ }
+ if (change_detected) {
+ refresh_cache(&self->cache_persist, self->key_persist);
+ refresh_cache(&self->cache_ro, self->key_ro);
+ self->serial = current_serial;
+ }
+ c = self->evaluate(self);
- pthread_mutex_unlock(&self->lock);
+ pthread_mutex_unlock(&self->lock);
- return c;
+ return c;
}
-static unsigned char evaluate_persist_ro(const struct cache2_char *self)
-{
- unsigned char c = self->cache_persist.c;
+static unsigned char evaluate_persist_ro(const struct cache2_char* self) {
+ unsigned char c = self->cache_persist.c;
- if (c) {
- return c;
- }
+ if (c) {
+ return c;
+ }
- return self->cache_ro.c;
+ return self->cache_ro.c;
}
/*
* Timestamp state generally remains constant, but can change at any time
* to handle developer requirements.
*/
-LIBLOG_ABI_PUBLIC clockid_t android_log_clockid()
-{
- static struct cache2_char clockid = {
- PTHREAD_MUTEX_INITIALIZER,
- 0,
- "persist.logd.timestamp",
- { { NULL, -1 }, '\0' },
- "ro.logd.timestamp",
- { { NULL, -1 }, '\0' },
- evaluate_persist_ro
- };
+LIBLOG_ABI_PUBLIC clockid_t android_log_clockid() {
+ static struct cache2_char clockid = {
+ PTHREAD_MUTEX_INITIALIZER, 0,
+ "persist.logd.timestamp", { { NULL, -1 }, '\0' },
+ "ro.logd.timestamp", { { NULL, -1 }, '\0' },
+ evaluate_persist_ro
+ };
- return (tolower(do_cache2_char(&clockid)) == 'm')
- ? CLOCK_MONOTONIC
- : CLOCK_REALTIME;
+ return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC
+ : CLOCK_REALTIME;
}
/*
* Security state generally remains constant, but the DO must be able
* to turn off logging should it become spammy after an attack is detected.
*/
-static unsigned char evaluate_security(const struct cache2_char *self)
-{
- unsigned char c = self->cache_ro.c;
+static unsigned char evaluate_security(const struct cache2_char* self) {
+ unsigned char c = self->cache_ro.c;
- return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
+ return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
}
-LIBLOG_ABI_PUBLIC int __android_log_security()
-{
- static struct cache2_char security = {
- PTHREAD_MUTEX_INITIALIZER,
- 0,
- "persist.logd.security",
- { { NULL, -1 }, BOOLEAN_FALSE },
- "ro.device_owner",
- { { NULL, -1 }, BOOLEAN_FALSE },
- evaluate_security
- };
+LIBLOG_ABI_PUBLIC int __android_log_security() {
+ static struct cache2_char security = {
+ PTHREAD_MUTEX_INITIALIZER, 0,
+ "persist.logd.security", { { NULL, -1 }, BOOLEAN_FALSE },
+ "ro.device_owner", { { NULL, -1 }, BOOLEAN_FALSE },
+ evaluate_security
+ };
- return do_cache2_char(&security);
+ return do_cache2_char(&security);
}
/*
@@ -420,245 +399,240 @@
/* Property helper */
static bool check_flag(const char* prop, const char* flag) {
- const char* cp = strcasestr(prop, flag);
- if (!cp) {
- return false;
- }
- /* We only will document comma (,) */
- static const char sep[] = ",:;|+ \t\f";
- if ((cp != prop) && !strchr(sep, cp[-1])) {
- return false;
- }
- cp += strlen(flag);
- return !*cp || !!strchr(sep, *cp);
+ const char* cp = strcasestr(prop, flag);
+ if (!cp) {
+ return false;
+ }
+ /* We only will document comma (,) */
+ static const char sep[] = ",:;|+ \t\f";
+ if ((cp != prop) && !strchr(sep, cp[-1])) {
+ return false;
+ }
+ cp += strlen(flag);
+ return !*cp || !!strchr(sep, *cp);
}
/* cache structure */
struct cache_property {
- struct cache cache;
- char property[PROP_VALUE_MAX];
+ struct cache cache;
+ char property[PROP_VALUE_MAX];
};
-static void refresh_cache_property(struct cache_property* cache, const char* key)
-{
+static void refresh_cache_property(struct cache_property* cache,
+ const char* key) {
+ if (!cache->cache.pinfo) {
+ cache->cache.pinfo = __system_property_find(key);
if (!cache->cache.pinfo) {
- cache->cache.pinfo = __system_property_find(key);
- if (!cache->cache.pinfo) {
- return;
- }
+ return;
}
- cache->cache.serial = __system_property_serial(cache->cache.pinfo);
- __system_property_read(cache->cache.pinfo, 0, cache->property);
+ }
+ cache->cache.serial = __system_property_serial(cache->cache.pinfo);
+ __system_property_read(cache->cache.pinfo, 0, cache->property);
}
/* get boolean with the logger twist that supports eng adjustments */
LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key,
- int flag)
-{
- struct cache_property property = { { NULL, -1 }, { 0 } };
- if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
- char newkey[PROP_NAME_MAX];
- snprintf(newkey, sizeof(newkey), "ro.%s", key);
- refresh_cache_property(&property, newkey);
- property.cache.pinfo = NULL;
- property.cache.serial = -1;
- snprintf(newkey, sizeof(newkey), "persist.%s", key);
- refresh_cache_property(&property, newkey);
- property.cache.pinfo = NULL;
- property.cache.serial = -1;
- }
+ int flag) {
+ struct cache_property property = { { NULL, -1 }, { 0 } };
+ if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
+ char newkey[PROP_NAME_MAX];
+ snprintf(newkey, sizeof(newkey), "ro.%s", key);
+ refresh_cache_property(&property, newkey);
+ property.cache.pinfo = NULL;
+ property.cache.serial = -1;
+ snprintf(newkey, sizeof(newkey), "persist.%s", key);
+ refresh_cache_property(&property, newkey);
+ property.cache.pinfo = NULL;
+ property.cache.serial = -1;
+ }
- refresh_cache_property(&property, key);
+ refresh_cache_property(&property, key);
- if (check_flag(property.property, "true")) {
- return true;
- }
- if (check_flag(property.property, "false")) {
- return false;
- }
- if (check_flag(property.property, "eng")) {
- flag |= BOOL_DEFAULT_FLAG_ENG;
- }
- /* this is really a "not" flag */
- if (check_flag(property.property, "svelte")) {
- flag |= BOOL_DEFAULT_FLAG_SVELTE;
- }
+ if (check_flag(property.property, "true")) {
+ return true;
+ }
+ if (check_flag(property.property, "false")) {
+ return false;
+ }
+ if (check_flag(property.property, "eng")) {
+ flag |= BOOL_DEFAULT_FLAG_ENG;
+ }
+ /* this is really a "not" flag */
+ if (check_flag(property.property, "svelte")) {
+ flag |= BOOL_DEFAULT_FLAG_SVELTE;
+ }
- /* Sanity Check */
- if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
- flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
- flag |= BOOL_DEFAULT_TRUE;
- }
+ /* Sanity Check */
+ if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
+ flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
+ flag |= BOOL_DEFAULT_TRUE;
+ }
- if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
- && __android_logger_property_get_bool("ro.config.low_ram",
- BOOL_DEFAULT_FALSE)) {
- return false;
- }
- if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
- return false;
- }
+ if ((flag & BOOL_DEFAULT_FLAG_SVELTE) &&
+ __android_logger_property_get_bool("ro.config.low_ram",
+ BOOL_DEFAULT_FALSE)) {
+ return false;
+ }
+ if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
+ return false;
+ }
- return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
+ return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
}
-LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value)
-{
- static long pages, pagesize;
- unsigned long maximum;
+LIBLOG_ABI_PRIVATE bool __android_logger_valid_buffer_size(unsigned long value) {
+ static long pages, pagesize;
+ unsigned long maximum;
- if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
- return false;
+ if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+ return false;
+ }
+
+ if (!pages) {
+ pages = sysconf(_SC_PHYS_PAGES);
+ }
+ if (pages < 1) {
+ return true;
+ }
+
+ if (!pagesize) {
+ pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize <= 1) {
+ pagesize = PAGE_SIZE;
}
+ }
- if (!pages) {
- pages = sysconf(_SC_PHYS_PAGES);
- }
- if (pages < 1) {
- return true;
- }
+ /* maximum memory impact a somewhat arbitrary ~3% */
+ pages = (pages + 31) / 32;
+ maximum = pages * pagesize;
- if (!pagesize) {
- pagesize = sysconf(_SC_PAGESIZE);
- if (pagesize <= 1) {
- pagesize = PAGE_SIZE;
- }
- }
+ if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+ return true;
+ }
- /* maximum memory impact a somewhat arbitrary ~3% */
- pages = (pages + 31) / 32;
- maximum = pages * pagesize;
-
- if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
- return true;
- }
-
- return value <= maximum;
+ return value <= maximum;
}
struct cache2_property_size {
- pthread_mutex_t lock;
- uint32_t serial;
- const char* key_persist;
- struct cache_property cache_persist;
- const char* key_ro;
- struct cache_property cache_ro;
- unsigned long (*const evaluate)(const struct cache2_property_size* self);
+ pthread_mutex_t lock;
+ uint32_t serial;
+ const char* key_persist;
+ struct cache_property cache_persist;
+ const char* key_ro;
+ struct cache_property cache_ro;
+ unsigned long (*const evaluate)(const struct cache2_property_size* self);
};
-static inline unsigned long do_cache2_property_size(struct cache2_property_size* self)
-{
- uint32_t current_serial;
- int change_detected;
- unsigned long v;
+static inline unsigned long do_cache2_property_size(
+ struct cache2_property_size* self) {
+ uint32_t current_serial;
+ int change_detected;
+ unsigned long v;
- if (pthread_mutex_trylock(&self->lock)) {
- /* We are willing to accept some race in this context */
- return self->evaluate(self);
- }
+ if (pthread_mutex_trylock(&self->lock)) {
+ /* We are willing to accept some race in this context */
+ return self->evaluate(self);
+ }
- change_detected = check_cache(&self->cache_persist.cache)
- || check_cache(&self->cache_ro.cache);
- current_serial = __system_property_area_serial();
- if (current_serial != self->serial) {
- change_detected = 1;
- }
- if (change_detected) {
- refresh_cache_property(&self->cache_persist, self->key_persist);
- refresh_cache_property(&self->cache_ro, self->key_ro);
- self->serial = current_serial;
- }
- v = self->evaluate(self);
+ change_detected = check_cache(&self->cache_persist.cache) ||
+ check_cache(&self->cache_ro.cache);
+ current_serial = __system_property_area_serial();
+ if (current_serial != self->serial) {
+ change_detected = 1;
+ }
+ if (change_detected) {
+ refresh_cache_property(&self->cache_persist, self->key_persist);
+ refresh_cache_property(&self->cache_ro, self->key_ro);
+ self->serial = current_serial;
+ }
+ v = self->evaluate(self);
- pthread_mutex_unlock(&self->lock);
+ pthread_mutex_unlock(&self->lock);
- return v;
+ return v;
}
-static unsigned long property_get_size_from_cache(const struct cache_property* cache)
-{
- char* cp;
- unsigned long value = strtoul(cache->property, &cp, 10);
+static unsigned long property_get_size_from_cache(
+ const struct cache_property* cache) {
+ char* cp;
+ unsigned long value = strtoul(cache->property, &cp, 10);
- switch(*cp) {
+ switch (*cp) {
case 'm':
case 'M':
- value *= 1024;
+ value *= 1024;
/* FALLTHRU */
case 'k':
case 'K':
- value *= 1024;
+ value *= 1024;
/* FALLTHRU */
case '\0':
- break;
+ break;
default:
- value = 0;
- }
+ value = 0;
+ }
- if (!__android_logger_valid_buffer_size(value)) {
- value = 0;
- }
+ if (!__android_logger_valid_buffer_size(value)) {
+ value = 0;
+ }
- return value;
+ return value;
}
-static unsigned long evaluate_property_get_size(const struct cache2_property_size* self)
-{
- unsigned long size = property_get_size_from_cache(&self->cache_persist);
- if (size) {
- return size;
- }
- return property_get_size_from_cache(&self->cache_ro);
+static unsigned long evaluate_property_get_size(
+ const struct cache2_property_size* self) {
+ unsigned long size = property_get_size_from_cache(&self->cache_persist);
+ if (size) {
+ return size;
+ }
+ return property_get_size_from_cache(&self->cache_ro);
}
-LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId)
-{
- static const char global_tunable[] = "persist.logd.size"; /* Settings App */
- static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
- static struct cache2_property_size global = {
- PTHREAD_MUTEX_INITIALIZER,
- 0,
- global_tunable,
- { { NULL, -1 }, {} },
- global_default,
- { { NULL, -1 }, {} },
- evaluate_property_get_size
- };
- char key_persist[PROP_NAME_MAX];
- char key_ro[PROP_NAME_MAX];
- struct cache2_property_size local = {
- PTHREAD_MUTEX_INITIALIZER,
- 0,
- key_persist,
- { { NULL, -1 }, {} },
- key_ro,
- { { NULL, -1 }, {} },
- evaluate_property_get_size
- };
- unsigned long property_size, default_size;
+LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId) {
+ static const char global_tunable[] = "persist.logd.size"; /* Settings App */
+ static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
+ static struct cache2_property_size global = {
+ /* clang-format off */
+ PTHREAD_MUTEX_INITIALIZER, 0,
+ global_tunable, { { NULL, -1 }, {} },
+ global_default, { { NULL, -1 }, {} },
+ evaluate_property_get_size
+ /* clang-format on */
+ };
+ char key_persist[PROP_NAME_MAX];
+ char key_ro[PROP_NAME_MAX];
+ struct cache2_property_size local = {
+ /* clang-format off */
+ PTHREAD_MUTEX_INITIALIZER, 0,
+ key_persist, { { NULL, -1 }, {} },
+ key_ro, { { NULL, -1 }, {} },
+ evaluate_property_get_size
+ /* clang-format on */
+ };
+ unsigned long property_size, default_size;
- default_size = do_cache2_property_size(&global);
- if (!default_size) {
- default_size = __android_logger_property_get_bool("ro.config.low_ram",
- BOOL_DEFAULT_FALSE)
- ? LOG_BUFFER_MIN_SIZE /* 64K */
- : LOG_BUFFER_SIZE; /* 256K */
- }
+ default_size = do_cache2_property_size(&global);
+ if (!default_size) {
+ default_size = __android_logger_property_get_bool("ro.config.low_ram",
+ BOOL_DEFAULT_FALSE)
+ ? LOG_BUFFER_MIN_SIZE /* 64K */
+ : LOG_BUFFER_SIZE; /* 256K */
+ }
- snprintf(key_persist, sizeof(key_persist), "%s.%s",
- global_tunable, android_log_id_to_name(logId));
- snprintf(key_ro, sizeof(key_ro), "%s.%s",
- global_default, android_log_id_to_name(logId));
- property_size = do_cache2_property_size(&local);
+ snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable,
+ android_log_id_to_name(logId));
+ snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default,
+ android_log_id_to_name(logId));
+ property_size = do_cache2_property_size(&local);
- if (!property_size) {
- property_size = default_size;
- }
+ if (!property_size) {
+ property_size = default_size;
+ }
- if (!property_size) {
- property_size = LOG_BUFFER_SIZE;
- }
+ if (!property_size) {
+ property_size = LOG_BUFFER_SIZE;
+ }
- return property_size;
+ return property_size;
}
diff --git a/liblog/stderr_write.c b/liblog/stderr_write.c
new file mode 100644
index 0000000..dbe5309
--- /dev/null
+++ b/liblog/stderr_write.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * stderr write handler. Output is logcat-like, and responds to
+ * logcat's environment variables ANDROID_PRINTF_LOG and
+ * ANDROID_LOG_TAGS to filter output.
+ *
+ * This transport only provides a writer, that means that it does not
+ * provide an End-To-End capability as the logs are effectively _lost_
+ * to the stderr file stream. The purpose of this transport is to
+ * supply a means for command line tools to report their logging
+ * to the stderr stream, in line with all other activities.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <log/event_tag_map.h>
+#include <log/log.h>
+#include <log/logprint.h>
+#include <log/uio.h>
+
+#include "log_portability.h"
+#include "logger.h"
+
+static int stderrOpen();
+static void stderrClose();
+static int stderrAvailable(log_id_t logId);
+static int stderrWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr);
+
+struct stderrContext {
+ AndroidLogFormat* logformat;
+#if defined(__ANDROID__)
+ EventTagMap* eventTagMap;
+#endif
+};
+
+LIBLOG_HIDDEN struct android_log_transport_write stderrLoggerWrite = {
+ .node = { &stderrLoggerWrite.node, &stderrLoggerWrite.node },
+ .context.priv = NULL,
+ .name = "stderr",
+ .available = stderrAvailable,
+ .open = stderrOpen,
+ .close = stderrClose,
+ .write = stderrWrite,
+};
+
+static int stderrOpen() {
+ struct stderrContext* ctx;
+ const char* envStr;
+ bool setFormat;
+
+ if (!stderr || (fileno(stderr) < 0)) {
+ return -EBADF;
+ }
+
+ if (stderrLoggerWrite.context.priv) {
+ return fileno(stderr);
+ }
+
+ ctx = calloc(1, sizeof(struct stderrContext));
+ if (!ctx) {
+ return -ENOMEM;
+ }
+
+ ctx->logformat = android_log_format_new();
+ if (!ctx->logformat) {
+ free(ctx);
+ return -ENOMEM;
+ }
+
+ envStr = getenv("ANDROID_PRINTF_LOG");
+ setFormat = false;
+
+ if (envStr) {
+ char* formats = strdup(envStr);
+ char* sv = NULL;
+ char* arg = formats;
+ while (!!(arg = strtok_r(arg, ",:; \t\n\r\f", &sv))) {
+ AndroidLogPrintFormat format = android_log_formatFromString(arg);
+ arg = NULL;
+ if (format == FORMAT_OFF) {
+ continue;
+ }
+ if (android_log_setPrintFormat(ctx->logformat, format) <= 0) {
+ continue;
+ }
+ setFormat = true;
+ }
+ free(formats);
+ }
+ if (!setFormat) {
+ AndroidLogPrintFormat format = android_log_formatFromString("threadtime");
+ android_log_setPrintFormat(ctx->logformat, format);
+ }
+ envStr = getenv("ANDROID_LOG_TAGS");
+ if (envStr) {
+ android_log_addFilterString(ctx->logformat, envStr);
+ }
+ stderrLoggerWrite.context.priv = ctx;
+
+ return fileno(stderr);
+}
+
+static void stderrClose() {
+ struct stderrContext* ctx = stderrLoggerWrite.context.priv;
+
+ if (ctx) {
+ stderrLoggerWrite.context.priv = NULL;
+ if (ctx->logformat) {
+ android_log_format_free(ctx->logformat);
+ ctx->logformat = NULL;
+ }
+#if defined(__ANDROID__)
+ if (ctx->eventTagMap) {
+ android_closeEventTagMap(ctx->eventTagMap);
+ ctx->eventTagMap = NULL;
+ }
+#endif
+ }
+}
+
+static int stderrAvailable(log_id_t logId) {
+ if ((logId >= LOG_ID_MAX) || (logId == LOG_ID_KERNEL)) {
+ return -EINVAL;
+ }
+ return 1;
+}
+
+static int stderrWrite(log_id_t logId, struct timespec* ts, struct iovec* vec,
+ size_t nr) {
+ struct log_msg log_msg;
+ AndroidLogEntry entry;
+ char binaryMsgBuf[1024];
+ int err;
+ size_t i;
+ struct stderrContext* ctx = stderrLoggerWrite.context.priv;
+
+ if (!ctx) return -EBADF;
+ if (!vec || !nr) return -EINVAL;
+
+ log_msg.entry.len = 0;
+ log_msg.entry.hdr_size = sizeof(log_msg.entry);
+ log_msg.entry.pid = getpid();
+#ifdef __BIONIC__
+ log_msg.entry.tid = gettid();
+#else
+ log_msg.entry.tid = getpid();
+#endif
+ log_msg.entry.sec = ts->tv_sec;
+ log_msg.entry.nsec = ts->tv_nsec;
+ log_msg.entry.lid = logId;
+ log_msg.entry.uid = __android_log_uid();
+
+ for (i = 0; i < nr; ++i) {
+ size_t len = vec[i].iov_len;
+ if ((log_msg.entry.len + len) > LOGGER_ENTRY_MAX_PAYLOAD) {
+ len = LOGGER_ENTRY_MAX_PAYLOAD - log_msg.entry.len;
+ }
+ if (!len) continue;
+ memcpy(log_msg.entry.msg + log_msg.entry.len, vec[i].iov_base, len);
+ log_msg.entry.len += len;
+ }
+
+ if ((logId == LOG_ID_EVENTS) || (logId == LOG_ID_SECURITY)) {
+#if defined(__ANDROID__)
+ if (!ctx->eventTagMap) {
+ ctx->eventTagMap = android_openEventTagMap(NULL);
+ }
+#endif
+ err = android_log_processBinaryLogBuffer(&log_msg.entry_v1, &entry,
+#if defined(__ANDROID__)
+ ctx->eventTagMap,
+#else
+ NULL,
+#endif
+ binaryMsgBuf, sizeof(binaryMsgBuf));
+ } else {
+ err = android_log_processLogBuffer(&log_msg.entry_v1, &entry);
+ }
+
+ /* print known truncated data, in essence logcat --debug */
+ if ((err < 0) && !entry.message) return -EINVAL;
+
+ if (!android_log_shouldPrintLine(ctx->logformat, entry.tag, entry.priority)) {
+ return log_msg.entry.len;
+ }
+
+ err = android_log_printLogLine(ctx->logformat, fileno(stderr), &entry);
+ if (err < 0) return errno ? -errno : -EINVAL;
+ return log_msg.entry.len;
+}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 097befc..0e6432c 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -55,7 +55,10 @@
-fno-builtin \
test_src_files := \
- liblog_test.cpp \
+ liblog_test_default.cpp \
+ liblog_test_local.cpp \
+ liblog_test_stderr.cpp \
+ liblog_test_stderr_local.cpp \
log_id_test.cpp \
log_radio_test.cpp \
log_read_test.cpp \
@@ -111,6 +114,7 @@
LOCAL_CXX_STL := libc++
LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_LDLIBS_linux := -lrt
include $(BUILD_HOST_NATIVE_TEST)
endif # ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp
index e5ef970..7367f1b 100644
--- a/liblog/tests/benchmark_main.cpp
+++ b/liblog/tests/benchmark_main.cpp
@@ -22,8 +22,8 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string>
#include <map>
+#include <string>
#include <vector>
static uint64_t gBytesProcessed;
@@ -32,21 +32,21 @@
static uint64_t gBenchmarkNum;
static uint64_t gBenchmarkStartTimeNs;
-typedef std::vector< ::testing::Benchmark* > BenchmarkList;
+typedef std::vector< ::testing::Benchmark*> BenchmarkList;
static BenchmarkList* gBenchmarks;
static int Round(int n) {
int base = 1;
- while (base*10 < n) {
+ while (base * 10 < n) {
base *= 10;
}
- if (n < 2*base) {
- return 2*base;
+ if (n < 2 * base) {
+ return 2 * base;
}
- if (n < 5*base) {
- return 5*base;
+ if (n < 5 * base) {
+ return 5 * base;
}
- return 10*base;
+ return 10 * base;
}
static uint64_t NanoTime() {
@@ -58,20 +58,19 @@
namespace testing {
-int PrettyPrintInt(char* str, int len, unsigned int arg)
-{
- if (arg >= (1<<30) && arg % (1<<30) == 0) {
- return snprintf(str, len, "%uGi", arg/(1<<30));
- } else if (arg >= (1<<20) && arg % (1<<20) == 0) {
- return snprintf(str, len, "%uMi", arg/(1<<20));
- } else if (arg >= (1<<10) && arg % (1<<10) == 0) {
- return snprintf(str, len, "%uKi", arg/(1<<10));
+int PrettyPrintInt(char* str, int len, unsigned int arg) {
+ if (arg >= (1 << 30) && arg % (1 << 30) == 0) {
+ return snprintf(str, len, "%uGi", arg / (1 << 30));
+ } else if (arg >= (1 << 20) && arg % (1 << 20) == 0) {
+ return snprintf(str, len, "%uMi", arg / (1 << 20));
+ } else if (arg >= (1 << 10) && arg % (1 << 10) == 0) {
+ return snprintf(str, len, "%uKi", arg / (1 << 10));
} else if (arg >= 1000000000 && arg % 1000000000 == 0) {
- return snprintf(str, len, "%uG", arg/1000000000);
+ return snprintf(str, len, "%uG", arg / 1000000000);
} else if (arg >= 1000000 && arg % 1000000 == 0) {
- return snprintf(str, len, "%uM", arg/1000000);
+ return snprintf(str, len, "%uM", arg / 1000000);
} else if (arg >= 1000 && arg % 1000 == 0) {
- return snprintf(str, len, "%uK", arg/1000);
+ return snprintf(str, len, "%uK", arg / 1000);
} else {
return snprintf(str, len, "%u", arg);
}
@@ -86,7 +85,8 @@
for (int i = 1; i < argc; i++) {
regex_t re;
if (regcomp(&re, argv[i], 0) != 0) {
- fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n", argv[i]);
+ fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n",
+ argv[i]);
exit(EXIT_FAILURE);
}
int match = regexec(&re, b->Name(), 0, NULL, 0);
@@ -111,9 +111,8 @@
uint64_t StartTimeNs = NanoTime();
b->RunFn(iterations);
// Catch us if we fail to log anything.
- if ((gBenchmarkTotalTimeNs == 0)
- && (StartTimeNs != 0)
- && (gBenchmarkStartTimeNs == 0)) {
+ if ((gBenchmarkTotalTimeNs == 0) && (StartTimeNs != 0) &&
+ (gBenchmarkStartTimeNs == 0)) {
gBenchmarkTotalTimeNs = NanoTime() - StartTimeNs;
}
}
@@ -126,12 +125,13 @@
s = NanoTime() - s;
while (s < 2e9 && gBenchmarkTotalTimeNs < 1e9 && iterations < 1e9) {
unsigned last = iterations;
- if (gBenchmarkTotalTimeNs/iterations == 0) {
+ if (gBenchmarkTotalTimeNs / iterations == 0) {
iterations = 1e9;
} else {
- iterations = 1e9 / (gBenchmarkTotalTimeNs/iterations);
+ iterations = 1e9 / (gBenchmarkTotalTimeNs / iterations);
}
- iterations = std::max(last + 1, std::min(iterations + iterations/2, 100*last));
+ iterations =
+ std::max(last + 1, std::min(iterations + iterations / 2, 100 * last));
iterations = Round(iterations);
s = NanoTime();
RunRepeatedly(b, iterations);
@@ -141,30 +141,30 @@
char throughput[100];
throughput[0] = '\0';
if (gBenchmarkTotalTimeNs > 0 && gBytesProcessed > 0) {
- double mib_processed = static_cast<double>(gBytesProcessed)/1e6;
- double seconds = static_cast<double>(gBenchmarkTotalTimeNs)/1e9;
- snprintf(throughput, sizeof(throughput), " %8.2f MiB/s", mib_processed/seconds);
+ double mib_processed = static_cast<double>(gBytesProcessed) / 1e6;
+ double seconds = static_cast<double>(gBenchmarkTotalTimeNs) / 1e9;
+ snprintf(throughput, sizeof(throughput), " %8.2f MiB/s",
+ mib_processed / seconds);
}
char full_name[100];
snprintf(full_name, sizeof(full_name), "%s%s%s", b->Name(),
- b->ArgName() ? "/" : "",
- b->ArgName() ? b->ArgName() : "");
+ b->ArgName() ? "/" : "", b->ArgName() ? b->ArgName() : "");
uint64_t mean = gBenchmarkTotalTimeNs / iterations;
uint64_t sdev = 0;
if (gBenchmarkNum == iterations) {
mean = gBenchmarkTotalTimeNs / gBenchmarkNum;
- uint64_t nXvariance = gBenchmarkTotalTimeNsSquared * gBenchmarkNum
- - (gBenchmarkTotalTimeNs * gBenchmarkTotalTimeNs);
+ uint64_t nXvariance = gBenchmarkTotalTimeNsSquared * gBenchmarkNum -
+ (gBenchmarkTotalTimeNs * gBenchmarkTotalTimeNs);
sdev = (sqrt((double)nXvariance) / gBenchmarkNum / gBenchmarkNum) + 0.5;
}
if (mean > (10000 * sdev)) {
printf("%-25s %10" PRIu64 " %10" PRIu64 "%s\n", full_name,
- static_cast<uint64_t>(iterations), mean, throughput);
+ static_cast<uint64_t>(iterations), mean, throughput);
} else {
- printf("%-25s %10" PRIu64 " %10" PRIu64 "(\317\203%" PRIu64 ")%s\n", full_name,
- static_cast<uint64_t>(iterations), mean, sdev, throughput);
+ printf("%-25s %10" PRIu64 " %10" PRIu64 "(\317\203%" PRIu64 ")%s\n",
+ full_name, static_cast<uint64_t>(iterations), mean, sdev, throughput);
}
fflush(stdout);
}
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 8cea7dc..329ba85 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -21,29 +21,29 @@
TEST(libc, __pstore_append) {
#ifdef __ANDROID__
- FILE *fp;
- ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
- static const char message[] = "libc.__pstore_append\n";
- ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
- int fflushReturn = fflush(fp);
- int fflushErrno = fflushReturn ? errno : 0;
- ASSERT_EQ(0, fflushReturn);
- ASSERT_EQ(0, fflushErrno);
- int fcloseReturn = fclose(fp);
- int fcloseErrno = fcloseReturn ? errno : 0;
- ASSERT_EQ(0, fcloseReturn);
- ASSERT_EQ(0, fcloseErrno);
- if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver configured\n"
- );
- }
- if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
- fprintf(stderr,
- "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n"
- );
- }
+ FILE* fp;
+ ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
+ static const char message[] = "libc.__pstore_append\n";
+ ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
+ int fflushReturn = fflush(fp);
+ int fflushErrno = fflushReturn ? errno : 0;
+ ASSERT_EQ(0, fflushReturn);
+ ASSERT_EQ(0, fflushErrno);
+ int fcloseReturn = fclose(fp);
+ int fcloseErrno = fcloseReturn ? errno : 0;
+ ASSERT_EQ(0, fcloseReturn);
+ ASSERT_EQ(0, fcloseErrno);
+ if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver "
+ "configured\n");
+ }
+ if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
+ fprintf(stderr,
+ "Reboot, ensure string libc.__pstore_append is in "
+ "/sys/fs/pstore/pmsg-ramoops-0\n");
+ }
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index dc411c3..3f79552 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
+#include <log/log_transport.h>
#include <private/android_logger.h>
#include "benchmark.h"
@@ -35,16 +36,15 @@
// non-syscall libs. Since we are benchmarking, or using this in the emergency
// signal to stuff a terminating code, we do NOT want to introduce
// a syscall or usleep on EAGAIN retry.
-#define LOG_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) \
- && ((errno == EINTR) \
- || (errno == EAGAIN))) \
- || (_rc == -EINTR) \
- || (_rc == -EAGAIN)); \
- _rc; })
+#define LOG_FAILURE_RETRY(exp) \
+ ({ \
+ typeof(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
+ (_rc == -EINTR) || (_rc == -EAGAIN)); \
+ _rc; \
+ })
/*
* Measure the fastest rate we can reliabley stuff print messages into
@@ -52,15 +52,14 @@
* wakeup time (2ms?)
*/
static void BM_log_maximum_retry(int iters) {
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_INFO,
- "BM_log_maximum_retry", "%d", i));
- }
+ for (int i = 0; i < iters; ++i) {
+ LOG_FAILURE_RETRY(
+ __android_log_print(ANDROID_LOG_INFO, "BM_log_maximum_retry", "%d", i));
+ }
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_log_maximum_retry);
@@ -70,26 +69,45 @@
* time (2ms?)
*/
static void BM_log_maximum(int iters) {
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- __android_log_print(ANDROID_LOG_INFO, "BM_log_maximum", "%d", i);
- }
+ for (int i = 0; i < iters; ++i) {
+ __android_log_print(ANDROID_LOG_INFO, "BM_log_maximum", "%d", i);
+ }
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_log_maximum);
+static void set_log_null() {
+ android_set_log_transport(LOGGER_NULL);
+}
+
+static void set_log_default() {
+ android_set_log_transport(LOGGER_DEFAULT);
+}
+
+static void BM_log_maximum_null(int iters) {
+ set_log_null();
+ BM_log_maximum(iters);
+ set_log_default();
+}
+BENCHMARK(BM_log_maximum_null);
+
/*
- * Measure the time it takes to submit the android logging call using
- * discrete acquisition under light load. Expect this to be a pair of
- * syscall periods (2us).
+ * Measure the time it takes to collect the time using
+ * discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a syscall period (2us) or
+ * data read time if zero-syscall.
+ *
+ * vdso support in the kernel and the library can allow
+ * clock_gettime to be zero-syscall.
*/
static void BM_clock_overhead(int iters) {
- for (int i = 0; i < iters; ++i) {
- StartBenchmarkTiming();
- StopBenchmarkTiming();
- }
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ StopBenchmarkTiming();
+ }
}
BENCHMARK(BM_clock_overhead);
@@ -97,75 +115,74 @@
* Measure the time it takes to submit the android logging data to pstore
*/
static void BM_pmsg_short(int iters) {
+ int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ if (pstore_fd < 0) {
+ return;
+ }
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- if (pstore_fd < 0) {
- return;
- }
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ struct timespec ts;
+ clock_gettime(android_log_clockid(), &ts);
- struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ android_pmsg_log_header_t pmsg_header;
+ pmsg_header.magic = LOGGER_MAGIC;
+ pmsg_header.len =
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
+ pmsg_header.uid = getuid();
+ pmsg_header.pid = getpid();
- android_pmsg_log_header_t pmsg_header;
- pmsg_header.magic = LOGGER_MAGIC;
- pmsg_header.len = sizeof(android_pmsg_log_header_t)
- + sizeof(android_log_header_t);
- pmsg_header.uid = getuid();
- pmsg_header.pid = getpid();
+ android_log_header_t header;
+ header.tid = gettid();
+ header.realtime.tv_sec = ts.tv_sec;
+ header.realtime.tv_nsec = ts.tv_nsec;
- android_log_header_t header;
- header.tid = gettid();
- header.realtime.tv_sec = ts.tv_sec;
- header.realtime.tv_nsec = ts.tv_nsec;
+ static const unsigned nr = 1;
+ static const unsigned header_length = 2;
+ struct iovec newVec[nr + header_length];
- static const unsigned nr = 1;
- static const unsigned header_length = 2;
- struct iovec newVec[nr + header_length];
+ newVec[0].iov_base = (unsigned char*)&pmsg_header;
+ newVec[0].iov_len = sizeof(pmsg_header);
+ newVec[1].iov_base = (unsigned char*)&header;
+ newVec[1].iov_len = sizeof(header);
- newVec[0].iov_base = (unsigned char *) &pmsg_header;
- newVec[0].iov_len = sizeof(pmsg_header);
- newVec[1].iov_base = (unsigned char *) &header;
- newVec[1].iov_len = sizeof(header);
+ android_log_event_int_t buffer;
- android_log_event_int_t buffer;
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = 0;
+ buffer.payload.type = EVENT_TYPE_INT;
+ uint32_t snapshot = 0;
+ buffer.payload.data = htole32(snapshot);
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = 0;
- buffer.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
+ newVec[2].iov_base = &buffer;
+ newVec[2].iov_len = sizeof(buffer);
+
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ ++snapshot;
buffer.payload.data = htole32(snapshot);
-
- newVec[2].iov_base = &buffer;
- newVec[2].iov_len = sizeof(buffer);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- ++snapshot;
- buffer.payload.data = htole32(snapshot);
- writev(pstore_fd, newVec, nr);
- }
- StopBenchmarkTiming();
- close(pstore_fd);
+ writev(pstore_fd, newVec, nr);
+ }
+ StopBenchmarkTiming();
+ close(pstore_fd);
}
BENCHMARK(BM_pmsg_short);
@@ -174,74 +191,72 @@
* best case aligned single block.
*/
static void BM_pmsg_short_aligned(int iters) {
+ int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ if (pstore_fd < 0) {
+ return;
+ }
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- if (pstore_fd < 0) {
- return;
- }
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ struct timespec ts;
+ clock_gettime(android_log_clockid(), &ts);
- struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ struct packet {
+ android_pmsg_log_header_t pmsg_header;
+ android_log_header_t header;
+ android_log_event_int_t payload;
+ };
+ alignas(8) char buf[sizeof(struct packet) + 8];
+ memset(buf, 0, sizeof(buf));
+ struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
+ if (((uintptr_t)&buffer->pmsg_header) & 7) {
+ fprintf(stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+ }
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
- }
+ buffer->pmsg_header.magic = LOGGER_MAGIC;
+ buffer->pmsg_header.len =
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
+ buffer->pmsg_header.uid = getuid();
+ buffer->pmsg_header.pid = getpid();
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
- + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
+ buffer->header.tid = gettid();
+ buffer->header.realtime.tv_sec = ts.tv_sec;
+ buffer->header.realtime.tv_nsec = ts.tv_nsec;
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
+ buffer->header.id = LOG_ID_EVENTS;
+ buffer->payload.header.tag = 0;
+ buffer->payload.payload.type = EVENT_TYPE_INT;
+ uint32_t snapshot = 0;
+ buffer->payload.payload.data = htole32(snapshot);
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ ++snapshot;
buffer->payload.payload.data = htole32(snapshot);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- ++snapshot;
- buffer->payload.payload.data = htole32(snapshot);
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) +
- sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- StopBenchmarkTiming();
- close(pstore_fd);
+ write(pstore_fd, &buffer->pmsg_header,
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
+ sizeof(android_log_event_int_t));
+ }
+ StopBenchmarkTiming();
+ close(pstore_fd);
}
BENCHMARK(BM_pmsg_short_aligned);
@@ -250,74 +265,72 @@
* best case aligned single block.
*/
static void BM_pmsg_short_unaligned1(int iters) {
+ int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ if (pstore_fd < 0) {
+ return;
+ }
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- if (pstore_fd < 0) {
- return;
- }
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ struct timespec ts;
+ clock_gettime(android_log_clockid(), &ts);
- struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ struct packet {
+ android_pmsg_log_header_t pmsg_header;
+ android_log_header_t header;
+ android_log_event_int_t payload;
+ };
+ alignas(8) char buf[sizeof(struct packet) + 8];
+ memset(buf, 0, sizeof(buf));
+ struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
+ if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
+ fprintf(stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+ }
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
- }
+ buffer->pmsg_header.magic = LOGGER_MAGIC;
+ buffer->pmsg_header.len =
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
+ buffer->pmsg_header.uid = getuid();
+ buffer->pmsg_header.pid = getpid();
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
- + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
+ buffer->header.tid = gettid();
+ buffer->header.realtime.tv_sec = ts.tv_sec;
+ buffer->header.realtime.tv_nsec = ts.tv_nsec;
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
+ buffer->header.id = LOG_ID_EVENTS;
+ buffer->payload.header.tag = 0;
+ buffer->payload.payload.type = EVENT_TYPE_INT;
+ uint32_t snapshot = 0;
+ buffer->payload.payload.data = htole32(snapshot);
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ ++snapshot;
buffer->payload.payload.data = htole32(snapshot);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- ++snapshot;
- buffer->payload.payload.data = htole32(snapshot);
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) +
- sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- StopBenchmarkTiming();
- close(pstore_fd);
+ write(pstore_fd, &buffer->pmsg_header,
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
+ sizeof(android_log_event_int_t));
+ }
+ StopBenchmarkTiming();
+ close(pstore_fd);
}
BENCHMARK(BM_pmsg_short_unaligned1);
@@ -326,71 +339,70 @@
* best case aligned single block.
*/
static void BM_pmsg_long_aligned(int iters) {
+ int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ if (pstore_fd < 0) {
+ return;
+ }
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- if (pstore_fd < 0) {
- return;
- }
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ struct timespec ts;
+ clock_gettime(android_log_clockid(), &ts);
- struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ struct packet {
+ android_pmsg_log_header_t pmsg_header;
+ android_log_header_t header;
+ android_log_event_int_t payload;
+ };
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
+ memset(buf, 0, sizeof(buf));
+ struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
+ if (((uintptr_t)&buffer->pmsg_header) & 7) {
+ fprintf(stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+ }
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
- }
+ buffer->pmsg_header.magic = LOGGER_MAGIC;
+ buffer->pmsg_header.len =
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
+ buffer->pmsg_header.uid = getuid();
+ buffer->pmsg_header.pid = getpid();
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
- + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
+ buffer->header.tid = gettid();
+ buffer->header.realtime.tv_sec = ts.tv_sec;
+ buffer->header.realtime.tv_nsec = ts.tv_nsec;
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
+ buffer->header.id = LOG_ID_EVENTS;
+ buffer->payload.header.tag = 0;
+ buffer->payload.payload.type = EVENT_TYPE_INT;
+ uint32_t snapshot = 0;
+ buffer->payload.payload.data = htole32(snapshot);
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ ++snapshot;
buffer->payload.payload.data = htole32(snapshot);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- ++snapshot;
- buffer->payload.payload.data = htole32(snapshot);
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- StopBenchmarkTiming();
- close(pstore_fd);
+ write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
+ }
+ StopBenchmarkTiming();
+ close(pstore_fd);
}
BENCHMARK(BM_pmsg_long_aligned);
@@ -399,107 +411,179 @@
* best case aligned single block.
*/
static void BM_pmsg_long_unaligned1(int iters) {
+ int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ if (pstore_fd < 0) {
+ return;
+ }
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- if (pstore_fd < 0) {
- return;
- }
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsg_header;
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
+ struct timespec ts;
+ clock_gettime(android_log_clockid(), &ts);
- struct timespec ts;
- clock_gettime(android_log_clockid(), &ts);
+ struct packet {
+ android_pmsg_log_header_t pmsg_header;
+ android_log_header_t header;
+ android_log_event_int_t payload;
+ };
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
+ memset(buf, 0, sizeof(buf));
+ struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
+ if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
+ fprintf(stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+ }
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
- }
+ buffer->pmsg_header.magic = LOGGER_MAGIC;
+ buffer->pmsg_header.len =
+ sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
+ buffer->pmsg_header.uid = getuid();
+ buffer->pmsg_header.pid = getpid();
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
- + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
+ buffer->header.tid = gettid();
+ buffer->header.realtime.tv_sec = ts.tv_sec;
+ buffer->header.realtime.tv_nsec = ts.tv_nsec;
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
+ buffer->header.id = LOG_ID_EVENTS;
+ buffer->payload.header.tag = 0;
+ buffer->payload.payload.type = EVENT_TYPE_INT;
+ uint32_t snapshot = 0;
+ buffer->payload.payload.data = htole32(snapshot);
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ ++snapshot;
buffer->payload.payload.data = htole32(snapshot);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- ++snapshot;
- buffer->payload.payload.data = htole32(snapshot);
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- StopBenchmarkTiming();
- close(pstore_fd);
+ write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
+ }
+ StopBenchmarkTiming();
+ close(pstore_fd);
}
BENCHMARK(BM_pmsg_long_unaligned1);
/*
- * Measure the time it takes to submit the android logging call using
- * discrete acquisition under light load. Expect this to be a dozen or so
- * syscall periods (40us).
+ * Measure the time it takes to form sprintf plus time using
+ * discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a syscall period (2us) or sprintf
+ * time if zero-syscall time.
*/
-static void BM_log_overhead(int iters) {
- for (int i = 0; i < iters; ++i) {
- StartBenchmarkTiming();
- __android_log_print(ANDROID_LOG_INFO, "BM_log_overhead", "%d", i);
- StopBenchmarkTiming();
- usleep(1000);
- }
-}
-BENCHMARK(BM_log_overhead);
+/* helper function */
+static void test_print(const char* fmt, ...) {
+ va_list ap;
+ char buf[1024];
-static void caught_latency(int /*signum*/)
-{
- unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
}
-static unsigned long long caught_convert(char *cp)
-{
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long) (cp[1] & 0xFF) << 8;
- l |= (unsigned long long) (cp[2] & 0xFF) << 16;
- l |= (unsigned long long) (cp[3] & 0xFF) << 24;
- l |= (unsigned long long) (cp[4] & 0xFF) << 32;
- l |= (unsigned long long) (cp[5] & 0xFF) << 40;
- l |= (unsigned long long) (cp[6] & 0xFF) << 48;
- l |= (unsigned long long) (cp[7] & 0xFF) << 56;
- return l;
+#define logd_yield() sched_yield() // allow logd to catch up
+#define logd_sleep() usleep(50) // really allow logd to catch up
+
+/* performance test */
+static void BM_sprintf_overhead(int iters) {
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ test_print("BM_sprintf_overhead:%d", i);
+ StopBenchmarkTiming();
+ logd_yield();
+ }
+}
+BENCHMARK(BM_sprintf_overhead);
+
+/*
+ * Measure the time it takes to submit the android printing logging call
+ * using discrete acquisition discrete acquisition (StartBenchmarkTiming() ->
+ * StopBenchmarkTiming()) under light load. Expect this to be a dozen or so
+ * syscall periods (40us) plus time to run *printf
+ */
+static void BM_log_print_overhead(int iters) {
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ __android_log_print(ANDROID_LOG_INFO, "BM_log_overhead", "%d", i);
+ StopBenchmarkTiming();
+ logd_yield();
+ }
+}
+BENCHMARK(BM_log_print_overhead);
+
+/*
+ * Measure the time it takes to submit the android event logging call
+ * using discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a dozen or so syscall periods (40us)
+ */
+static void BM_log_event_overhead(int iters) {
+ for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
+ StartBenchmarkTiming();
+ __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
+ StopBenchmarkTiming();
+ logd_yield();
+ }
+}
+BENCHMARK(BM_log_event_overhead);
+
+static void BM_log_event_overhead_null(int iters) {
+ set_log_null();
+ BM_log_event_overhead(iters);
+ set_log_default();
+}
+BENCHMARK(BM_log_event_overhead_null);
+
+/*
+ * Measure the time it takes to submit the android event logging call
+ * using discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under very-light load (<1% CPU utilization).
+ */
+static void BM_log_light_overhead(int iters) {
+ for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
+ StartBenchmarkTiming();
+ __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
+ StopBenchmarkTiming();
+ usleep(10000);
+ }
+}
+BENCHMARK(BM_log_light_overhead);
+
+static void BM_log_light_overhead_null(int iters) {
+ set_log_null();
+ BM_log_light_overhead(iters);
+ set_log_default();
+}
+BENCHMARK(BM_log_light_overhead_null);
+
+static void caught_latency(int /*signum*/) {
+ unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
+
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+}
+
+static unsigned long long caught_convert(char* cp) {
+ unsigned long long l = cp[0] & 0xFF;
+ l |= (unsigned long long)(cp[1] & 0xFF) << 8;
+ l |= (unsigned long long)(cp[2] & 0xFF) << 16;
+ l |= (unsigned long long)(cp[3] & 0xFF) << 24;
+ l |= (unsigned long long)(cp[4] & 0xFF) << 32;
+ l |= (unsigned long long)(cp[5] & 0xFF) << 40;
+ l |= (unsigned long long)(cp[6] & 0xFF) << 48;
+ l |= (unsigned long long)(cp[7] & 0xFF) << 56;
+ return l;
}
static const int alarm_time = 3;
@@ -510,77 +594,75 @@
* 4 syscalls (3us).
*/
static void BM_log_latency(int iters) {
- pid_t pid = getpid();
+ pid_t pid = getpid();
- struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
- ANDROID_LOG_RDONLY, 0, pid);
+ struct logger_list* logger_list =
+ android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 0, pid);
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
+ if (!logger_list) {
+ fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
- signal(SIGALRM, caught_latency);
- alarm(alarm_time);
+ signal(SIGALRM, caught_latency);
+ alarm(alarm_time);
- for (int j = 0, i = 0; i < iters && j < 10*iters; ++i, ++j) {
- log_time ts;
- LOG_FAILURE_RETRY((
- ts = log_time(CLOCK_REALTIME),
- android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
+ for (int j = 0, i = 0; i < iters && j < 10 * iters; ++i, ++j) {
+ log_time ts;
+ LOG_FAILURE_RETRY((ts = log_time(CLOCK_REALTIME),
+ android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
+ for (;;) {
+ log_msg log_msg;
+ int ret = android_logger_list_read(logger_list, &log_msg);
+ alarm(alarm_time);
- if (ret <= 0) {
- iters = i;
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
+ if (ret <= 0) {
+ iters = i;
+ break;
+ }
+ if ((log_msg.entry.len != (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
- char* eventData = log_msg.msg();
+ char* eventData = log_msg.msg();
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time tx(eventData + 4 + 1);
- if (ts != tx) {
- if (0xDEADBEEFA55A5AA5ULL == caught_convert(eventData + 4 + 1)) {
- iters = i;
- break;
- }
- continue;
- }
-
- uint64_t start = ts.nsec();
- uint64_t end = log_msg.nsec();
- if (end >= start) {
- StartBenchmarkTiming(start);
- StopBenchmarkTiming(end);
- } else {
- --i;
- }
- break;
+ if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+ continue;
+ }
+ log_time tx(eventData + 4 + 1);
+ if (ts != tx) {
+ if (0xDEADBEEFA55A5AA5ULL == caught_convert(eventData + 4 + 1)) {
+ iters = i;
+ break;
}
+ continue;
+ }
+
+ uint64_t start = ts.nsec();
+ uint64_t end = log_msg.nsec();
+ if (end >= start) {
+ StartBenchmarkTiming(start);
+ StopBenchmarkTiming(end);
+ } else {
+ --i;
+ }
+ break;
}
+ }
- signal(SIGALRM, SIG_DFL);
- alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
- android_logger_list_free(logger_list);
+ android_logger_list_free(logger_list);
}
BENCHMARK(BM_log_latency);
-static void caught_delay(int /*signum*/)
-{
- unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
+static void caught_delay(int /*signum*/) {
+ unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
}
/*
@@ -588,65 +670,64 @@
* the logs. Expect this to be less than double the process wakeup time (2ms).
*/
static void BM_log_delay(int iters) {
- pid_t pid = getpid();
+ pid_t pid = getpid();
- struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
- ANDROID_LOG_RDONLY, 0, pid);
+ struct logger_list* logger_list =
+ android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 0, pid);
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
+ if (!logger_list) {
+ fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
- signal(SIGALRM, caught_delay);
- alarm(alarm_time);
+ signal(SIGALRM, caught_delay);
+ alarm(alarm_time);
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- log_time ts(CLOCK_REALTIME);
+ for (int i = 0; i < iters; ++i) {
+ log_time ts(CLOCK_REALTIME);
- LOG_FAILURE_RETRY(
- android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ LOG_FAILURE_RETRY(android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
+ for (;;) {
+ log_msg log_msg;
+ int ret = android_logger_list_read(logger_list, &log_msg);
+ alarm(alarm_time);
- if (ret <= 0) {
- iters = i;
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
+ if (ret <= 0) {
+ iters = i;
+ break;
+ }
+ if ((log_msg.entry.len != (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
- char* eventData = log_msg.msg();
+ char* eventData = log_msg.msg();
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time tx(eventData + 4 + 1);
- if (ts != tx) {
- if (0xDEADBEEFA55A5AA6ULL == caught_convert(eventData + 4 + 1)) {
- iters = i;
- break;
- }
- continue;
- }
-
- break;
+ if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+ continue;
+ }
+ log_time tx(eventData + 4 + 1);
+ if (ts != tx) {
+ if (0xDEADBEEFA55A5AA6ULL == caught_convert(eventData + 4 + 1)) {
+ iters = i;
+ break;
}
+ continue;
+ }
+
+ break;
}
+ }
- signal(SIGALRM, SIG_DFL);
- alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
- android_logger_list_free(logger_list);
+ android_logger_list_free(logger_list);
}
BENCHMARK(BM_log_delay);
@@ -654,17 +735,16 @@
* Measure the time it takes for __android_log_is_loggable.
*/
static void BM_is_loggable(int iters) {
- static const char logd[] = "logd";
+ static const char logd[] = "logd";
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- __android_log_is_loggable_len(ANDROID_LOG_WARN,
- logd, strlen(logd),
- ANDROID_LOG_VERBOSE);
- }
+ for (int i = 0; i < iters; ++i) {
+ __android_log_is_loggable_len(ANDROID_LOG_WARN, logd, strlen(logd),
+ ANDROID_LOG_VERBOSE);
+ }
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_is_loggable);
@@ -672,13 +752,13 @@
* Measure the time it takes for android_log_clockid.
*/
static void BM_clockid(int iters) {
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- android_log_clockid();
- }
+ for (int i = 0; i < iters; ++i) {
+ android_log_clockid();
+ }
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_clockid);
@@ -686,13 +766,13 @@
* Measure the time it takes for __android_log_security.
*/
static void BM_security(int iters) {
- StartBenchmarkTiming();
+ StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- __android_log_security();
- }
+ for (int i = 0; i < iters; ++i) {
+ __android_log_security();
+ }
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_security);
@@ -701,41 +781,40 @@
static EventTagMap* map;
static bool prechargeEventMap() {
- if (map) return true;
+ if (map) return true;
- fprintf(stderr, "Precharge: start\n");
+ fprintf(stderr, "Precharge: start\n");
- map = android_openEventTagMap(NULL);
- for (uint32_t tag = 1; tag < USHRT_MAX; ++tag) {
- size_t len;
- if (android_lookupEventTag_len(map, &len, tag) == NULL) continue;
- set.insert(tag);
- }
+ map = android_openEventTagMap(NULL);
+ for (uint32_t tag = 1; tag < USHRT_MAX; ++tag) {
+ size_t len;
+ if (android_lookupEventTag_len(map, &len, tag) == NULL) continue;
+ set.insert(tag);
+ }
- fprintf(stderr, "Precharge: stop %zu\n", set.size());
+ fprintf(stderr, "Precharge: stop %zu\n", set.size());
- return true;
+ return true;
}
/*
* Measure the time it takes for android_lookupEventTag_len
*/
static void BM_lookupEventTag(int iters) {
+ prechargeEventMap();
- prechargeEventMap();
+ std::unordered_set<uint32_t>::const_iterator it = set.begin();
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
+ StartBenchmarkTiming();
- StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ size_t len;
+ android_lookupEventTag_len(map, &len, (*it));
+ ++it;
+ if (it == set.end()) it = set.begin();
+ }
- for (int i = 0; i < iters; ++i) {
- size_t len;
- android_lookupEventTag_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_lookupEventTag);
@@ -745,25 +824,24 @@
static uint32_t notTag = 1;
static void BM_lookupEventTag_NOT(int iters) {
+ prechargeEventMap();
- prechargeEventMap();
-
- while (set.find(notTag) != set.end()) {
- ++notTag;
- if (notTag >= USHRT_MAX) notTag = 1;
- }
-
- StartBenchmarkTiming();
-
- for (int i = 0; i < iters; ++i) {
- size_t len;
- android_lookupEventTag_len(map, &len, notTag);
- }
-
- StopBenchmarkTiming();
-
+ while (set.find(notTag) != set.end()) {
++notTag;
if (notTag >= USHRT_MAX) notTag = 1;
+ }
+
+ StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; ++i) {
+ size_t len;
+ android_lookupEventTag_len(map, &len, notTag);
+ }
+
+ StopBenchmarkTiming();
+
+ ++notTag;
+ if (notTag >= USHRT_MAX) notTag = 1;
}
BENCHMARK(BM_lookupEventTag_NOT);
@@ -771,21 +849,20 @@
* Measure the time it takes for android_lookupEventFormat_len
*/
static void BM_lookupEventFormat(int iters) {
+ prechargeEventMap();
- prechargeEventMap();
+ std::unordered_set<uint32_t>::const_iterator it = set.begin();
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
+ StartBenchmarkTiming();
- StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ size_t len;
+ android_lookupEventFormat_len(map, &len, (*it));
+ ++it;
+ if (it == set.end()) it = set.begin();
+ }
- for (int i = 0; i < iters; ++i) {
- size_t len;
- android_lookupEventFormat_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-
- StopBenchmarkTiming();
+ StopBenchmarkTiming();
}
BENCHMARK(BM_lookupEventFormat);
@@ -793,137 +870,135 @@
* Measure the time it takes for android_lookupEventTagNum plus above
*/
static void BM_lookupEventTagNum(int iters) {
+ prechargeEventMap();
- prechargeEventMap();
+ std::unordered_set<uint32_t>::const_iterator it = set.begin();
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- for (int i = 0; i < iters; ++i) {
- size_t len;
- const char* name = android_lookupEventTag_len(map, &len, (*it));
- std::string Name(name, len);
- const char* format = android_lookupEventFormat_len(map, &len, (*it));
- std::string Format(format, len);
- StartBenchmarkTiming();
- android_lookupEventTagNum(map, Name.c_str(), Format.c_str(),
- ANDROID_LOG_UNKNOWN);
- StopBenchmarkTiming();
- ++it;
- if (it == set.end()) it = set.begin();
- }
-
+ for (int i = 0; i < iters; ++i) {
+ size_t len;
+ const char* name = android_lookupEventTag_len(map, &len, (*it));
+ std::string Name(name, len);
+ const char* format = android_lookupEventFormat_len(map, &len, (*it));
+ std::string Format(format, len);
+ StartBenchmarkTiming();
+ android_lookupEventTagNum(map, Name.c_str(), Format.c_str(),
+ ANDROID_LOG_UNKNOWN);
+ StopBenchmarkTiming();
+ ++it;
+ if (it == set.end()) it = set.begin();
+ }
}
BENCHMARK(BM_lookupEventTagNum);
// Must be functionally identical to liblog internal __send_log_msg.
-static void send_to_control(char *buf, size_t len)
-{
- int sock = socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock < 0) return;
- size_t writeLen = strlen(buf) + 1;
+static void send_to_control(char* buf, size_t len) {
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock < 0) return;
+ size_t writeLen = strlen(buf) + 1;
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, buf, writeLen));
- if (ret <= 0) {
- close(sock);
- return;
- }
- while ((ret = read(sock, buf, len)) > 0) {
- if (((size_t)ret == len) || (len < PAGE_SIZE)) {
- break;
- }
- len -= ret;
- buf += ret;
-
- struct pollfd p = {
- .fd = sock,
- .events = POLLIN,
- .revents = 0
- };
-
- ret = poll(&p, 1, 20);
- if ((ret <= 0) || !(p.revents & POLLIN)) {
- break;
- }
- }
+ ssize_t ret = TEMP_FAILURE_RETRY(write(sock, buf, writeLen));
+ if (ret <= 0) {
close(sock);
+ return;
+ }
+ while ((ret = read(sock, buf, len)) > 0) {
+ if (((size_t)ret == len) || (len < PAGE_SIZE)) {
+ break;
+ }
+ len -= ret;
+ buf += ret;
+
+ struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
+
+ ret = poll(&p, 1, 20);
+ if ((ret <= 0) || !(p.revents & POLLIN)) {
+ break;
+ }
+ }
+ close(sock);
}
static void BM_lookupEventTagNum_logd_new(int iters) {
- fprintf(stderr, "WARNING: "
- "This test can cause logd to grow in size and hit DOS limiter\n");
- // Make copies
- static const char empty_event_log_tags[] = "# content owned by logd\n";
- static const char dev_event_log_tags_path[] = "/dev/event-log-tags";
- std::string dev_event_log_tags;
- if (android::base::ReadFileToString(dev_event_log_tags_path,
- &dev_event_log_tags) &&
- (dev_event_log_tags.length() == 0)) {
- dev_event_log_tags = empty_event_log_tags;
- }
- static const char data_event_log_tags_path[] = "/data/misc/logd/event-log-tags";
- std::string data_event_log_tags;
- if (android::base::ReadFileToString(data_event_log_tags_path,
- &data_event_log_tags) &&
- (data_event_log_tags.length() == 0)) {
- data_event_log_tags = empty_event_log_tags;
- }
+ fprintf(stderr,
+ "WARNING: "
+ "This test can cause logd to grow in size and hit DOS limiter\n");
+ // Make copies
+ static const char empty_event_log_tags[] = "# content owned by logd\n";
+ static const char dev_event_log_tags_path[] = "/dev/event-log-tags";
+ std::string dev_event_log_tags;
+ if (android::base::ReadFileToString(dev_event_log_tags_path,
+ &dev_event_log_tags) &&
+ (dev_event_log_tags.length() == 0)) {
+ dev_event_log_tags = empty_event_log_tags;
+ }
+ static const char data_event_log_tags_path[] =
+ "/data/misc/logd/event-log-tags";
+ std::string data_event_log_tags;
+ if (android::base::ReadFileToString(data_event_log_tags_path,
+ &data_event_log_tags) &&
+ (data_event_log_tags.length() == 0)) {
+ data_event_log_tags = empty_event_log_tags;
+ }
- for (int i = 0; i < iters; ++i) {
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- log_time now(CLOCK_MONOTONIC);
- char name[64];
- snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer),
- "getEventTag name=%s format=\"(new|1)\"", name);
- StartBenchmarkTiming();
- send_to_control(buffer, sizeof(buffer));
- StopBenchmarkTiming();
- }
+ for (int i = 0; i < iters; ++i) {
+ char buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ log_time now(CLOCK_MONOTONIC);
+ char name[64];
+ snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
+ snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
+ name);
+ StartBenchmarkTiming();
+ send_to_control(buffer, sizeof(buffer));
+ StopBenchmarkTiming();
+ }
- // Restore copies (logd still know about them, until crash or reboot)
- if (dev_event_log_tags.length() &&
- !android::base::WriteStringToFile(dev_event_log_tags,
- dev_event_log_tags_path)) {
- fprintf(stderr, "WARNING: "
- "failed to restore %s\n", dev_event_log_tags_path);
- }
- if (data_event_log_tags.length() &&
- !android::base::WriteStringToFile(data_event_log_tags,
- data_event_log_tags_path)) {
- fprintf(stderr, "WARNING: "
- "failed to restore %s\n", data_event_log_tags_path);
- }
- fprintf(stderr, "WARNING: "
- "Restarting logd to make it forget what we just did\n");
- system("stop logd ; start logd");
+ // Restore copies (logd still know about them, until crash or reboot)
+ if (dev_event_log_tags.length() &&
+ !android::base::WriteStringToFile(dev_event_log_tags,
+ dev_event_log_tags_path)) {
+ fprintf(stderr,
+ "WARNING: "
+ "failed to restore %s\n",
+ dev_event_log_tags_path);
+ }
+ if (data_event_log_tags.length() &&
+ !android::base::WriteStringToFile(data_event_log_tags,
+ data_event_log_tags_path)) {
+ fprintf(stderr,
+ "WARNING: "
+ "failed to restore %s\n",
+ data_event_log_tags_path);
+ }
+ fprintf(stderr,
+ "WARNING: "
+ "Restarting logd to make it forget what we just did\n");
+ system("stop logd ; start logd");
}
BENCHMARK(BM_lookupEventTagNum_logd_new);
static void BM_lookupEventTagNum_logd_existing(int iters) {
- prechargeEventMap();
+ prechargeEventMap();
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
+ std::unordered_set<uint32_t>::const_iterator it = set.begin();
- for (int i = 0; i < iters; ++i) {
- size_t len;
- const char* name = android_lookupEventTag_len(map, &len, (*it));
- std::string Name(name, len);
- const char* format = android_lookupEventFormat_len(map, &len, (*it));
- std::string Format(format, len);
+ for (int i = 0; i < iters; ++i) {
+ size_t len;
+ const char* name = android_lookupEventTag_len(map, &len, (*it));
+ std::string Name(name, len);
+ const char* format = android_lookupEventFormat_len(map, &len, (*it));
+ std::string Format(format, len);
- char buffer[256];
- snprintf(buffer, sizeof(buffer),
- "getEventTag name=%s format=\"%s\"",
- Name.c_str(), Format.c_str());
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"%s\"",
+ Name.c_str(), Format.c_str());
- StartBenchmarkTiming();
- send_to_control(buffer, sizeof(buffer));
- StopBenchmarkTiming();
- ++it;
- if (it == set.end()) it = set.begin();
- }
+ StartBenchmarkTiming();
+ send_to_control(buffer, sizeof(buffer));
+ StopBenchmarkTiming();
+ ++it;
+ if (it == set.end()) it = set.begin();
+ }
}
BENCHMARK(BM_lookupEventTagNum_logd_existing);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 5faf8e1..5a52377 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -31,406 +31,597 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#ifdef __ANDROID__ // includes sys/properties.h which does not exist outside
+#ifdef __ANDROID__ // includes sys/properties.h which does not exist outside
#include <cutils/properties.h>
#endif
#include <gtest/gtest.h>
-#include <log/logprint.h>
#include <log/log_event_list.h>
+#include <log/log_transport.h>
+#include <log/logprint.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#ifndef TEST_PREFIX
+#ifdef __ANDROID__ // make sure we always run code if compiled for android
+#define TEST_PREFIX
+#endif
+#endif
+
+#if (!defined(USING_LOGGER_DEFAULT) || !defined(USING_LOGGER_LOCAL) || \
+ !defined(USING_LOGGER_STDERR))
+#ifdef liblog // a binary clue that we are overriding the test names
+// Does not support log reading blocking feature yet
+// Does not support LOG_ID_SECURITY (unless we set LOGGER_LOCAL | LOGGER_LOGD)
+// Assume some common aspects are tested by USING_LOGGER_DEFAULT:
+// Does not need to _retest_ pmsg functionality
+// Does not need to _retest_ property handling as it is a higher function
+// Does not need to _retest_ event mapping functionality
+// Does not need to _retest_ ratelimit
+// Does not need to _retest_ logprint
+#define USING_LOGGER_LOCAL
+#else
+#define USING_LOGGER_DEFAULT
+#endif
+#endif
+#ifdef USING_LOGGER_STDERR
+#define SUPPORTS_END_TO_END 0
+#else
+#define SUPPORTS_END_TO_END 1
+#endif
+
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) \
- && ((errno == EINTR) \
- || (errno == EAGAIN))) \
- || (_rc == -EINTR) \
- || (_rc == -EAGAIN)); \
- _rc; })
+#define LOG_FAILURE_RETRY(exp) \
+ ({ \
+ typeof(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
+ (_rc == -EINTR) || (_rc == -EAGAIN)); \
+ _rc; \
+ })
TEST(liblog, __android_log_btwrite) {
-#ifdef __ANDROID__
- int intBuf = 0xDEADBEEF;
- EXPECT_LT(0, __android_log_btwrite(0,
- EVENT_TYPE_INT,
- &intBuf, sizeof(intBuf)));
- long long longBuf = 0xDEADBEEFA55A5AA5;
- EXPECT_LT(0, __android_log_btwrite(0,
- EVENT_TYPE_LONG,
- &longBuf, sizeof(longBuf)));
- usleep(1000);
- char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
- EXPECT_LT(0, __android_log_btwrite(0,
- EVENT_TYPE_STRING,
- Buf, sizeof(Buf) - 1));
- usleep(1000);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+#ifdef TEST_PREFIX
+ TEST_PREFIX
#endif
+ int intBuf = 0xDEADBEEF;
+ EXPECT_LT(0,
+ __android_log_btwrite(0, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)));
+ long long longBuf = 0xDEADBEEFA55A5AA5;
+ EXPECT_LT(
+ 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)));
+ usleep(1000);
+ char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
+ EXPECT_LT(0,
+ __android_log_btwrite(0, EVENT_TYPE_STRING, Buf, sizeof(Buf) - 1));
+ usleep(1000);
}
-#ifdef __ANDROID__
-std::string popenToString(std::string command) {
- std::string ret;
+#if (defined(__ANDROID__) && defined(USING_LOGGER_DEFAULT))
+static std::string popenToString(std::string command) {
+ std::string ret;
- FILE* fp = popen(command.c_str(), "r");
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
- pclose(fp);
- }
- return ret;
+ FILE* fp = popen(command.c_str(), "r");
+ if (fp) {
+ if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
+ pclose(fp);
+ }
+ return ret;
}
static bool isPmsgActive() {
- pid_t pid = getpid();
+ pid_t pid = getpid();
- std::string myPidFds = popenToString(android::base::StringPrintf(
- "ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true; // guess it is?
+ std::string myPidFds =
+ popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
+ if (myPidFds.length() == 0) return true; // guess it is?
- return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
+ return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
}
static bool isLogdwActive() {
- std::string logdwSignature = popenToString(
- "grep /dev/socket/logdw /proc/net/unix");
- size_t beginning = logdwSignature.find(" ");
- if (beginning == std::string::npos) return true;
- beginning = logdwSignature.find(" ", beginning + 1);
- if (beginning == std::string::npos) return true;
- size_t end = logdwSignature.find(" ", beginning + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(" ", end + 1);
- if (end == std::string::npos) return true;
- std::string allLogdwEndpoints = popenToString(
- "grep ' 00000002" +
- logdwSignature.substr(beginning, end - beginning) +
- " ' /proc/net/unix | " +
- "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
- if (allLogdwEndpoints.length() == 0) return true;
+ std::string logdwSignature =
+ popenToString("grep /dev/socket/logdw /proc/net/unix");
+ size_t beginning = logdwSignature.find(" ");
+ if (beginning == std::string::npos) return true;
+ beginning = logdwSignature.find(" ", beginning + 1);
+ if (beginning == std::string::npos) return true;
+ size_t end = logdwSignature.find(" ", beginning + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ end = logdwSignature.find(" ", end + 1);
+ if (end == std::string::npos) return true;
+ std::string allLogdwEndpoints = popenToString(
+ "grep ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
+ " ' /proc/net/unix | " +
+ "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
+ if (allLogdwEndpoints.length() == 0) return true;
- // NB: allLogdwEndpoints has some false positives in it, but those
- // strangers do not overlap with the simplistic activities inside this
- // test suite.
+ // NB: allLogdwEndpoints has some false positives in it, but those
+ // strangers do not overlap with the simplistic activities inside this
+ // test suite.
- pid_t pid = getpid();
+ pid_t pid = getpid();
- std::string myPidFds = popenToString(android::base::StringPrintf(
- "ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true;
+ std::string myPidFds =
+ popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
+ if (myPidFds.length() == 0) return true;
- // NB: fgrep with multiple strings is broken in Android
- for (beginning = 0;
- (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
- beginning = end + 1) {
- if (myPidFds.find(allLogdwEndpoints.substr(beginning,
- end - beginning)) !=
- std::string::npos) return true;
- }
- return false;
+ // NB: fgrep with multiple strings is broken in Android
+ for (beginning = 0;
+ (end = allLogdwEndpoints.find("\n", beginning)) != std::string::npos;
+ beginning = end + 1) {
+ if (myPidFds.find(allLogdwEndpoints.substr(beginning, end - beginning)) !=
+ std::string::npos)
+ return true;
+ }
+ return false;
}
-bool tested__android_log_close;
+static bool tested__android_log_close;
#endif
TEST(liblog, __android_log_btwrite__android_logger_list_read) {
-#ifdef __ANDROID__
- struct logger_list *logger_list;
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+#endif
+ struct logger_list* logger_list;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
- // Check that we can close and reopen the logger
- log_time ts(CLOCK_MONOTONIC);
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- bool pmsgActiveAfter__android_log_btwrite;
- bool logdwActiveAfter__android_log_btwrite;
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- __android_log_close();
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ log_time ts(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+#ifdef USING_LOGGER_DEFAULT
+ // Check that we can close and reopen the logger
+ bool pmsgActiveAfter__android_log_btwrite;
+ bool logdwActiveAfter__android_log_btwrite;
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+ logdwActiveAfter__android_log_btwrite = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+ EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
+ __android_log_close();
+ if (getuid() == AID_ROOT) {
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ }
+#endif
+
+ log_time ts1(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+#ifdef USING_LOGGER_DEFAULT
+ if (getuid() == AID_ROOT) {
+ pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+ logdwActiveAfter__android_log_btwrite = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+ EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+ }
+#endif
+ usleep(1000000);
+
+ int count = 0;
+ int second_count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- log_time ts1(CLOCK_MONOTONIC);
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- }
- usleep(1000000);
+ EXPECT_EQ(log_msg.entry.pid, pid);
- int count = 0;
- int second_count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts == tx) {
- ++count;
- } else if (ts1 == tx) {
- ++second_count;
- }
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
}
- EXPECT_EQ(1, count);
- EXPECT_EQ(1, second_count);
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- android_logger_list_close(logger_list);
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+ continue;
+ }
+
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts == tx) {
+ ++count;
+ } else if (ts1 == tx) {
+ ++second_count;
+ }
+ }
+
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, second_count);
+
+ android_logger_list_close(logger_list);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-#ifdef __ANDROID__
-static inline int32_t get4LE(const char* src)
-{
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
+static void print_transport(const char* prefix, int logger) {
+ static const char orstr[] = " | ";
+
+ if (!prefix) {
+ prefix = "";
+ }
+ if (logger < 0) {
+ fprintf(stderr, "%s%s\n", prefix, strerror(-logger));
+ return;
+ }
+
+ if (logger == LOGGER_DEFAULT) {
+ fprintf(stderr, "%sLOGGER_DEFAULT", prefix);
+ prefix = orstr;
+ }
+ if (logger & LOGGER_LOGD) {
+ fprintf(stderr, "%sLOGGER_LOGD", prefix);
+ prefix = orstr;
+ }
+ if (logger & LOGGER_KERNEL) {
+ fprintf(stderr, "%sLOGGER_KERNEL", prefix);
+ prefix = orstr;
+ }
+ if (logger & LOGGER_NULL) {
+ fprintf(stderr, "%sLOGGER_NULL", prefix);
+ prefix = orstr;
+ }
+ if (logger & LOGGER_LOCAL) {
+ fprintf(stderr, "%sLOGGER_LOCAL", prefix);
+ prefix = orstr;
+ }
+ if (logger & LOGGER_STDERR) {
+ fprintf(stderr, "%sLOGGER_STDERR", prefix);
+ prefix = orstr;
+ }
+ logger &= ~(LOGGER_LOGD | LOGGER_KERNEL | LOGGER_NULL | LOGGER_LOCAL |
+ LOGGER_STDERR);
+ if (logger) {
+ fprintf(stderr, "%s0x%x", prefix, logger);
+ prefix = orstr;
+ }
+ if (prefix == orstr) {
+ fprintf(stderr, "\n");
+ }
}
#endif
-static void bswrite_test(const char *message) {
+// This test makes little sense standalone, and requires the tests ahead
+// and behind us, to make us whole. We could incorporate a prefix and
+// suffix test to make this standalone, but opted to not complicate this.
+TEST(liblog, android_set_log_transport) {
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+#endif
+
+ int logger = android_get_log_transport();
+ print_transport("android_get_log_transport = ", logger);
+ EXPECT_NE(LOGGER_NULL, logger);
+
+ int ret;
+ EXPECT_EQ(LOGGER_NULL, ret = android_set_log_transport(LOGGER_NULL));
+ print_transport("android_set_log_transport = ", ret);
+ EXPECT_EQ(LOGGER_NULL, ret = android_get_log_transport());
+ print_transport("android_get_log_transport = ", ret);
+
+ pid_t pid = getpid();
+
+ struct logger_list* logger_list;
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
+
+ log_time ts(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ EXPECT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
+
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+ continue;
+ }
+
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts == tx) {
+ ++count;
+ }
+ }
+
+ android_logger_list_close(logger_list);
+
+ EXPECT_EQ(logger, ret = android_set_log_transport(logger));
+ print_transport("android_set_log_transport = ", ret);
+ EXPECT_EQ(logger, ret = android_get_log_transport());
+ print_transport("android_get_log_transport = ", ret);
+
+ // False negative if liblog.__android_log_btwrite__android_logger_list_read
+ // fails above, so we will likely succeed. But we will have so many
+ // failures elsewhere that it is probably not worthwhile for us to
+ // highlight yet another disappointment.
+ //
+ // We also expect failures in the following tests if the set does not
+ // react in an appropriate manner internally, yet passes, so we depend
+ // on this test being in the middle of a series of tests performed in
+ // the same process.
+ EXPECT_EQ(0, count);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#ifdef TEST_PREFIX
+static inline uint32_t get4LE(const uint8_t* src) {
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+static inline uint32_t get4LE(const char* src) {
+ return get4LE(reinterpret_cast<const uint8_t*>(src));
+}
+#endif
+
+static void bswrite_test(const char* message) {
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ struct logger_list* logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
+
#ifdef __ANDROID__
- struct logger_list *logger_list;
+ log_time ts(android_log_clockid());
+#else
+ log_time ts(CLOCK_REALTIME);
+#endif
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- log_time ts(android_log_clockid());
-
- ASSERT_LT(0, __android_log_bswrite(0, message));
- size_t num_lines = 1, size = 0, length = 0, total = 0;
- const char *cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++cp;
- ++total;
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
- break;
- }
+ EXPECT_LT(0, __android_log_bswrite(0, message));
+ size_t num_lines = 1, size = 0, length = 0, total = 0;
+ const char* cp = message;
+ while (*cp) {
+ if (*cp == '\n') {
+ if (cp[1]) {
+ ++num_lines;
+ }
+ } else {
+ ++size;
}
- while (*cp) {
- ++cp;
- ++total;
+ ++cp;
+ ++total;
+ ++length;
+ if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
+ break;
}
- usleep(1000000);
+ }
+ while (*cp) {
+ ++cp;
+ ++total;
+ }
+ usleep(1000000);
- int count = 0;
+ int count = 0;
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
- ASSERT_EQ(log_msg.entry.pid, pid);
+ EXPECT_EQ(log_msg.entry.pid, pid);
- if ((log_msg.entry.sec < (ts.tv_sec - 1))
- || ((ts.tv_sec + 1) < log_msg.entry.sec)
- || ((size_t)log_msg.entry.len != (sizeof(android_log_event_string_t) +
- length))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
+ if ((log_msg.entry.sec < (ts.tv_sec - 1)) ||
+ ((ts.tv_sec + 1) < log_msg.entry.sec) ||
+ ((size_t)log_msg.entry.len !=
+ (sizeof(android_log_event_string_t) + length)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
- android_log_event_string_t* eventData;
- eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
+ android_log_event_string_t* eventData;
+ eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
- if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
- continue;
- }
+ if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
+ continue;
+ }
- size_t len = get4LE(reinterpret_cast<char*>(&eventData->length));
- if (len == total) {
- ++count;
+ size_t len = get4LE(reinterpret_cast<char*>(&eventData->length));
+ if (len == total) {
+ ++count;
- AndroidLogFormat *logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- if (length != total) {
- fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
- }
- int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
- &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
- EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
- if (processBinaryLogBuffer == 0) {
- fflush(stderr);
- EXPECT_EQ((int)((20 * num_lines) + size),
+ AndroidLogFormat* logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ char msgBuf[1024];
+ if (length != total) {
+ fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
+ }
+ int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+ &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+ EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
+ if ((processBinaryLogBuffer == 0) || entry.message) {
+ size_t line_overhead = 20;
+ if (pid > 99999) ++line_overhead;
+ if (pid > 999999) ++line_overhead;
+ fflush(stderr);
+ if (processBinaryLogBuffer) {
+ EXPECT_GT((int)((line_overhead * num_lines) + size),
android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- android_log_format_free(logformat);
+ } else {
+ EXPECT_EQ((int)((line_overhead * num_lines) + size),
+ android_log_printLogLine(logformat, fileno(stderr), &entry));
}
+ }
+ android_log_format_free(logformat);
}
+ }
- EXPECT_EQ(1, count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
- android_logger_list_close(logger_list);
+ android_logger_list_close(logger_list);
#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ message = NULL;
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, __android_log_bswrite_and_print) {
- bswrite_test("Hello World");
+ bswrite_test("Hello World");
}
TEST(liblog, __android_log_bswrite_and_print__empty_string) {
- bswrite_test("");
+ bswrite_test("");
}
TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
- bswrite_test("\nHello World\n");
+ bswrite_test("\nHello World\n");
}
TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
- bswrite_test("\n Hello World \n");
+ bswrite_test("\n Hello World \n");
}
TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
- bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
+ bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
}
-static void buf_write_test(const char *message) {
+static void buf_write_test(const char* message) {
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ struct logger_list* logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(
+ NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ static const char tag[] = "TEST__android_log_buf_write";
#ifdef __ANDROID__
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- static const char tag[] = "TEST__android_log_buf_write";
- log_time ts(android_log_clockid());
-
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- tag, message));
- size_t num_lines = 1, size = 0, length = 0;
- const char *cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
- break;
- }
- ++cp;
- }
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.sec < (ts.tv_sec - 1))
- || ((ts.tv_sec + 1) < log_msg.entry.sec)
- || ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2))
- || (log_msg.id() != LOG_ID_MAIN)) {
- continue;
- }
-
- ++count;
-
- AndroidLogFormat *logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
- &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- fflush(stderr);
- EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- android_log_format_free(logformat);
- }
-
- EXPECT_EQ(1, count);
-
- android_logger_list_close(logger_list);
+ log_time ts(android_log_clockid());
#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ log_time ts(CLOCK_REALTIME);
+#endif
+
+ EXPECT_LT(
+ 0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO, tag, message));
+ size_t num_lines = 1, size = 0, length = 0;
+ const char* cp = message;
+ while (*cp) {
+ if (*cp == '\n') {
+ if (cp[1]) {
+ ++num_lines;
+ }
+ } else {
+ ++size;
+ }
+ ++length;
+ if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
+ break;
+ }
+ ++cp;
+ }
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.sec < (ts.tv_sec - 1)) ||
+ ((ts.tv_sec + 1) < log_msg.entry.sec) ||
+ ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2)) ||
+ (log_msg.id() != LOG_ID_MAIN)) {
+ continue;
+ }
+
+ ++count;
+
+ AndroidLogFormat* logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ int processLogBuffer =
+ android_log_processLogBuffer(&log_msg.entry_v1, &entry);
+ EXPECT_EQ(0, processLogBuffer);
+ if (processLogBuffer == 0) {
+ size_t line_overhead = 11;
+ if (pid > 99999) ++line_overhead;
+ if (pid > 999999) ++line_overhead;
+ fflush(stderr);
+ EXPECT_EQ((int)(((line_overhead + sizeof(tag)) * num_lines) + size),
+ android_log_printLogLine(logformat, fileno(stderr), &entry));
+ }
+ android_log_format_free(logformat);
+ }
+
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
+
+ android_logger_list_close(logger_list);
+#else
+ message = NULL;
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, __android_log_buf_write_and_print__empty) {
- buf_write_test("");
+ buf_write_test("");
}
TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
- buf_write_test("\nHello World\n");
+ buf_write_test("\nHello World\n");
}
TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
- buf_write_test("\n Hello World \n");
+ buf_write_test("\n Hello World \n");
}
-#ifdef __ANDROID__
+#ifndef USING_LOGGER_LOCAL // requires blocking reader functionality
+#ifdef TEST_PREFIX
static unsigned signaled;
static log_time signal_time;
@@ -440,151 +631,151 @@
* should catch any regressions in that effort. The odds of a logged message
* in a signal handler causing a lockup problem should be _very_ small.
*/
-static void caught_blocking_signal(int /*signum*/)
-{
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
+static void caught_blocking_signal(int /*signum*/) {
+ unsigned long long v = 0xDEADBEEFA55A0000ULL;
- v += getpid() & 0xFFFF;
+ v += getpid() & 0xFFFF;
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
+ ++signaled;
+ if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
+ signal_time = log_time(CLOCK_MONOTONIC);
+ signal_time.tv_sec += 2;
+ }
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
}
// Fill in current process user and system time in 10ms increments
-static void get_ticks(unsigned long long *uticks, unsigned long long *sticks)
-{
+static void get_ticks(unsigned long long* uticks, unsigned long long* sticks) {
+ *uticks = *sticks = 0;
+
+ pid_t pid = getpid();
+
+ char buffer[512];
+ snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
+
+ FILE* fp = fopen(buffer, "r");
+ if (!fp) {
+ return;
+ }
+
+ char* cp = fgets(buffer, sizeof(buffer), fp);
+ fclose(fp);
+ if (!cp) {
+ return;
+ }
+
+ pid_t d;
+ char s[sizeof(buffer)];
+ char c;
+ long long ll;
+ unsigned long long ull;
+
+ if (15 != sscanf(buffer,
+ "%d %s %c %lld %lld %lld %lld %lld %llu %llu %llu %llu %llu "
+ "%llu %llu ",
+ &d, s, &c, &ll, &ll, &ll, &ll, &ll, &ull, &ull, &ull, &ull,
+ &ull, uticks, sticks)) {
*uticks = *sticks = 0;
-
- pid_t pid = getpid();
-
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
-
- FILE *fp = fopen(buffer, "r");
- if (!fp) {
- return;
- }
-
- char *cp = fgets(buffer, sizeof(buffer), fp);
- fclose(fp);
- if (!cp) {
- return;
- }
-
- pid_t d;
- char s[sizeof(buffer)];
- char c;
- long long ll;
- unsigned long long ull;
-
- if (15 != sscanf(buffer,
- "%d %s %c %lld %lld %lld %lld %lld %llu %llu %llu %llu %llu %llu %llu ",
- &d, s, &c, &ll, &ll, &ll, &ll, &ll, &ull, &ull, &ull, &ull, &ull,
- uticks, sticks)) {
- *uticks = *sticks = 0;
- }
+ }
}
#endif
TEST(liblog, android_logger_list_read__cpu_signal) {
-#ifdef __ANDROID__
- struct logger_list *logger_list;
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ struct logger_list* logger_list;
+ unsigned long long v = 0xDEADBEEFA55A0000ULL;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- v += pid & 0xFFFF;
+ v += pid & 0xFFFF;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
- int count = 0;
+ int count = 0;
- int signals = 0;
+ int signals = 0;
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
+ unsigned long long uticks_start;
+ unsigned long long sticks_start;
+ get_ticks(&uticks_start, &sticks_start);
- const unsigned alarm_time = 10;
+ const unsigned alarm_time = 10;
- memset(&signal_time, 0, sizeof(signal_time));
+ memset(&signal_time, 0, sizeof(signal_time));
- signal(SIGALRM, caught_blocking_signal);
+ signal(SIGALRM, caught_blocking_signal);
+ alarm(alarm_time);
+
+ signaled = 0;
+
+ do {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
alarm(alarm_time);
- signaled = 0;
+ ++count;
- do {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
+ ASSERT_EQ(log_msg.entry.pid, pid);
- alarm(alarm_time);
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
- ++count;
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- ASSERT_EQ(log_msg.entry.pid, pid);
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+ continue;
+ }
- if ((log_msg.entry.len != sizeof(android_log_event_long_t))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
+ char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+ unsigned long long l = cp[0] & 0xFF;
+ l |= (unsigned long long)(cp[1] & 0xFF) << 8;
+ l |= (unsigned long long)(cp[2] & 0xFF) << 16;
+ l |= (unsigned long long)(cp[3] & 0xFF) << 24;
+ l |= (unsigned long long)(cp[4] & 0xFF) << 32;
+ l |= (unsigned long long)(cp[5] & 0xFF) << 40;
+ l |= (unsigned long long)(cp[6] & 0xFF) << 48;
+ l |= (unsigned long long)(cp[7] & 0xFF) << 56;
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+ if (l == v) {
+ ++signals;
+ break;
+ }
+ } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
+ EXPECT_LE(1, count);
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long) (cp[1] & 0xFF) << 8;
- l |= (unsigned long long) (cp[2] & 0xFF) << 16;
- l |= (unsigned long long) (cp[3] & 0xFF) << 24;
- l |= (unsigned long long) (cp[4] & 0xFF) << 32;
- l |= (unsigned long long) (cp[5] & 0xFF) << 40;
- l |= (unsigned long long) (cp[6] & 0xFF) << 48;
- l |= (unsigned long long) (cp[7] & 0xFF) << 56;
+ EXPECT_EQ(1, signals);
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
+ android_logger_list_close(logger_list);
- EXPECT_LE(1, count);
+ unsigned long long uticks_end;
+ unsigned long long sticks_end;
+ get_ticks(&uticks_end, &sticks_end);
- EXPECT_EQ(1, signals);
-
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+ // Less than 1% in either user or system time, or both
+ const unsigned long long one_percent_ticks = alarm_time;
+ unsigned long long user_ticks = uticks_end - uticks_start;
+ unsigned long long system_ticks = sticks_end - sticks_start;
+ EXPECT_GT(one_percent_ticks, user_ticks);
+ EXPECT_GT(one_percent_ticks, system_ticks);
+ EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
/*
* Strictly, we are not allowed to log messages in a signal context, the
* correct way to handle this is to ensure the messages are constructed in
@@ -592,163 +783,164 @@
*/
static sem_t thread_trigger;
-static void caught_blocking_thread(int /*signum*/)
-{
- sem_post(&thread_trigger);
+static void caught_blocking_thread(int /*signum*/) {
+ sem_post(&thread_trigger);
}
-static void *running_thread(void *) {
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
+static void* running_thread(void*) {
+ unsigned long long v = 0xDEADBEAFA55A0000ULL;
- v += getpid() & 0xFFFF;
+ v += getpid() & 0xFFFF;
- struct timespec timeout;
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_sec += 55;
- sem_timedwait(&thread_trigger, &timeout);
+ struct timespec timeout;
+ clock_gettime(CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 55;
+ sem_timedwait(&thread_trigger, &timeout);
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
+ ++signaled;
+ if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
+ signal_time = log_time(CLOCK_MONOTONIC);
+ signal_time.tv_sec += 2;
+ }
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
- return NULL;
+ return NULL;
}
-int start_thread()
-{
- sem_init(&thread_trigger, 0, 0);
+static int start_thread() {
+ sem_init(&thread_trigger, 0, 0);
- pthread_attr_t attr;
- if (pthread_attr_init(&attr)) {
- return -1;
- }
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr)) {
+ return -1;
+ }
- struct sched_param param;
+ struct sched_param param;
- memset(¶m, 0, sizeof(param));
- pthread_attr_setschedparam(&attr, ¶m);
- pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+ memset(¶m, 0, sizeof(param));
+ pthread_attr_setschedparam(&attr, ¶m);
+ pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
- if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
- pthread_t thread;
- if (pthread_create(&thread, &attr, running_thread, NULL)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
pthread_attr_destroy(&attr);
- return 0;
+ return -1;
+ }
+
+ pthread_t thread;
+ if (pthread_create(&thread, &attr, running_thread, NULL)) {
+ pthread_attr_destroy(&attr);
+ return -1;
+ }
+
+ pthread_attr_destroy(&attr);
+ return 0;
}
#endif
TEST(liblog, android_logger_list_read__cpu_thread) {
-#ifdef __ANDROID__
- struct logger_list *logger_list;
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ struct logger_list* logger_list;
+ unsigned long long v = 0xDEADBEAFA55A0000ULL;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- v += pid & 0xFFFF;
+ v += pid & 0xFFFF;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
- int count = 0;
+ int count = 0;
- int signals = 0;
+ int signals = 0;
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
+ unsigned long long uticks_start;
+ unsigned long long sticks_start;
+ get_ticks(&uticks_start, &sticks_start);
- const unsigned alarm_time = 10;
+ const unsigned alarm_time = 10;
- memset(&signal_time, 0, sizeof(signal_time));
+ memset(&signal_time, 0, sizeof(signal_time));
- signaled = 0;
- EXPECT_EQ(0, start_thread());
+ signaled = 0;
+ EXPECT_EQ(0, start_thread());
- signal(SIGALRM, caught_blocking_thread);
+ signal(SIGALRM, caught_blocking_thread);
+ alarm(alarm_time);
+
+ do {
+ log_msg log_msg;
+ if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
+ break;
+ }
+
alarm(alarm_time);
- do {
- log_msg log_msg;
- if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
- break;
- }
+ ++count;
- alarm(alarm_time);
+ ASSERT_EQ(log_msg.entry.pid, pid);
- ++count;
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
- ASSERT_EQ(log_msg.entry.pid, pid);
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if ((log_msg.entry.len != sizeof(android_log_event_long_t))
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+ continue;
+ }
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+ char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+ unsigned long long l = cp[0] & 0xFF;
+ l |= (unsigned long long)(cp[1] & 0xFF) << 8;
+ l |= (unsigned long long)(cp[2] & 0xFF) << 16;
+ l |= (unsigned long long)(cp[3] & 0xFF) << 24;
+ l |= (unsigned long long)(cp[4] & 0xFF) << 32;
+ l |= (unsigned long long)(cp[5] & 0xFF) << 40;
+ l |= (unsigned long long)(cp[6] & 0xFF) << 48;
+ l |= (unsigned long long)(cp[7] & 0xFF) << 56;
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
+ if (l == v) {
+ ++signals;
+ break;
+ }
+ } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long) (cp[1] & 0xFF) << 8;
- l |= (unsigned long long) (cp[2] & 0xFF) << 16;
- l |= (unsigned long long) (cp[3] & 0xFF) << 24;
- l |= (unsigned long long) (cp[4] & 0xFF) << 32;
- l |= (unsigned long long) (cp[5] & 0xFF) << 40;
- l |= (unsigned long long) (cp[6] & 0xFF) << 48;
- l |= (unsigned long long) (cp[7] & 0xFF) << 56;
+ EXPECT_LE(1, count);
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
+ EXPECT_EQ(1, signals);
- EXPECT_LE(1, count);
+ android_logger_list_close(logger_list);
- EXPECT_EQ(1, signals);
+ unsigned long long uticks_end;
+ unsigned long long sticks_end;
+ get_ticks(&uticks_end, &sticks_end);
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+ // Less than 1% in either user or system time, or both
+ const unsigned long long one_percent_ticks = alarm_time;
+ unsigned long long user_ticks = uticks_end - uticks_start;
+ unsigned long long system_ticks = sticks_end - sticks_start;
+ EXPECT_GT(one_percent_ticks, user_ticks);
+ EXPECT_GT(one_percent_ticks, system_ticks);
+ EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // !USING_LOGGER_LOCAL
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
-#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
- sizeof(max_payload_tag) - 1)
+#define SIZEOF_MAX_PAYLOAD_BUF \
+ (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(max_payload_tag) - 1)
#endif
-static const char max_payload_buf[] = "LEONATO\n\
+static const char max_payload_buf[] =
+ "LEONATO\n\
I learn in this letter that Don Peter of Arragon\n\
comes this night to Messina\n\
MESSENGER\n\
@@ -880,301 +1072,343 @@
takes his leave.";
TEST(liblog, max_payload) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
- char tag[sizeof(max_payload_tag)];
- memcpy(tag, max_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ pid_t pid = getpid();
+ char tag[sizeof(max_payload_tag)];
+ memcpy(tag, max_payload_tag, sizeof(tag));
+ snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
- LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- tag, max_payload_buf));
- sleep(2);
+ LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+ tag, max_payload_buf));
+ sleep(2);
- struct logger_list *logger_list;
+ struct logger_list* logger_list;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
- bool matches = false;
- ssize_t max_len = 0;
+ bool matches = false;
+ ssize_t max_len = 0;
- for(;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
- continue;
- }
-
- char *data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- continue;
- }
-
- data += strlen(data) + 1;
-
- const char *left = data;
- const char *right = max_payload_buf;
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- if (max_len <= (left - data)) {
- max_len = left - data + 1;
- }
-
- if (max_len > 512) {
- matches = true;
- break;
- }
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- android_logger_list_close(logger_list);
+ if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+ continue;
+ }
- EXPECT_EQ(true, matches);
+ char* data = log_msg.msg();
- EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
+ if (!data || strcmp(++data, tag)) {
+ continue;
+ }
+
+ data += strlen(data) + 1;
+
+ const char* left = data;
+ const char* right = max_payload_buf;
+ while (*left && *right && (*left == *right)) {
+ ++left;
+ ++right;
+ }
+
+ if (max_len <= (left - data)) {
+ max_len = left - data + 1;
+ }
+
+ if (max_len > 512) {
+ matches = true;
+ break;
+ }
+ }
+
+ android_logger_list_close(logger_list);
+
+#if SUPPORTS_END_TO_END
+ EXPECT_EQ(true, matches);
+
+ EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ EXPECT_EQ(false, matches);
+#endif
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, __android_log_buf_print__maxtag) {
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ struct logger_list* logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(
+ NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
#ifdef __ANDROID__
- struct logger_list *logger_list;
+ log_time ts(android_log_clockid());
+#else
+ log_time ts(CLOCK_REALTIME);
+#endif
- pid_t pid = getpid();
+ EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ max_payload_buf, max_payload_buf));
+ usleep(1000000);
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ int count = 0;
- log_time ts(android_log_clockid());
-
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- max_payload_buf, max_payload_buf));
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.sec < (ts.tv_sec - 1))
- || ((ts.tv_sec + 1) < log_msg.entry.sec)
- || ((size_t)log_msg.entry.len < LOGGER_ENTRY_MAX_PAYLOAD)
- || (log_msg.id() != LOG_ID_MAIN)) {
- continue;
- }
-
- ++count;
-
- AndroidLogFormat *logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
- &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- fflush(stderr);
- int printLogLine =
- android_log_printLogLine(logformat, fileno(stderr), &entry);
- // Legacy tag truncation
- EXPECT_LE(128, printLogLine);
- // Measured maximum if we try to print part of the tag as message
- EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
- }
- android_log_format_free(logformat);
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- EXPECT_EQ(1, count);
+ ASSERT_EQ(log_msg.entry.pid, pid);
- android_logger_list_close(logger_list);
+ if ((log_msg.entry.sec < (ts.tv_sec - 1)) ||
+ ((ts.tv_sec + 1) < log_msg.entry.sec) ||
+ ((size_t)log_msg.entry.len < LOGGER_ENTRY_MAX_PAYLOAD) ||
+ (log_msg.id() != LOG_ID_MAIN)) {
+ continue;
+ }
+
+ ++count;
+
+ AndroidLogFormat* logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ int processLogBuffer =
+ android_log_processLogBuffer(&log_msg.entry_v1, &entry);
+ EXPECT_EQ(0, processLogBuffer);
+ if (processLogBuffer == 0) {
+ fflush(stderr);
+ int printLogLine =
+ android_log_printLogLine(logformat, fileno(stderr), &entry);
+ // Legacy tag truncation
+ EXPECT_LE(128, printLogLine);
+ // Measured maximum if we try to print part of the tag as message
+ EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
+ }
+ android_log_format_free(logformat);
+ }
+
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
+
+ android_logger_list_close(logger_list);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, too_big_payload) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
- static const char big_payload_tag[] = "TEST_big_payload_XXXX";
- char tag[sizeof(big_payload_tag)];
- memcpy(tag, big_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ pid_t pid = getpid();
+ static const char big_payload_tag[] = "TEST_big_payload_XXXX";
+ char tag[sizeof(big_payload_tag)];
+ memcpy(tag, big_payload_tag, sizeof(tag));
+ snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
- std::string longString(3266519, 'x');
+ std::string longString(3266519, 'x');
- ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM,
- ANDROID_LOG_INFO, tag, longString.c_str()));
+ ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(
+ LOG_ID_SYSTEM, ANDROID_LOG_INFO, tag, longString.c_str()));
- struct logger_list *logger_list;
+ struct logger_list* logger_list;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_SYSTEM,
+ ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
- ssize_t max_len = 0;
+ ssize_t max_len = 0;
- for(;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
- continue;
- }
-
- char *data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- continue;
- }
-
- data += strlen(data) + 1;
-
- const char *left = data;
- const char *right = longString.c_str();
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- if (max_len <= (left - data)) {
- max_len = left - data + 1;
- }
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- android_logger_list_close(logger_list);
+ if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+ continue;
+ }
- EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
- static_cast<size_t>(max_len));
+ char* data = log_msg.msg();
- EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
+ if (!data || strcmp(++data, tag)) {
+ continue;
+ }
+
+ data += strlen(data) + 1;
+
+ const char* left = data;
+ const char* right = longString.c_str();
+ while (*left && *right && (*left == *right)) {
+ ++left;
+ ++right;
+ }
+
+ if (max_len <= (left - data)) {
+ max_len = left - data + 1;
+ }
+ }
+
+ android_logger_list_close(logger_list);
+
+#if !SUPPORTS_END_TO_END
+ max_len =
+ max_len ? max_len : LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag);
+#endif
+ EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
+ static_cast<size_t>(max_len));
+
+ // SLOP: Allow the underlying interface to optionally place a
+ // terminating nul at the LOGGER_ENTRY_MAX_PAYLOAD's last byte
+ // or not.
+ if (ret == (max_len + static_cast<ssize_t>(sizeof(big_payload_tag)) - 1)) {
+ --max_len;
+ }
+ EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, dual_reader) {
-#ifdef __ANDROID__
- struct logger_list *logger_list1;
+#ifdef TEST_PREFIX
+ TEST_PREFIX
- // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
- ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
- LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
+ static const int num = 25;
- struct logger_list *logger_list2;
+ for (int i = 25; i > 0; --i) {
+ static const char fmt[] = "dual_reader %02d";
+ char buffer[sizeof(fmt) + 8];
+ snprintf(buffer, sizeof(buffer), fmt, i);
+ LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ "liblog", buffer));
+ }
+ usleep(1000000);
- if (NULL == (logger_list2 = android_logger_list_open(
- LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
- android_logger_list_close(logger_list1);
- ASSERT_TRUE(NULL != logger_list2);
+ struct logger_list* logger_list1;
+ ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
+ LOG_ID_MAIN,
+ ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, num, 0)));
+
+ struct logger_list* logger_list2;
+
+ if (NULL == (logger_list2 = android_logger_list_open(
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ num - 10, 0))) {
+ android_logger_list_close(logger_list1);
+ ASSERT_TRUE(NULL != logger_list2);
+ }
+
+ int count1 = 0;
+ bool done1 = false;
+ int count2 = 0;
+ bool done2 = false;
+
+ do {
+ log_msg log_msg;
+
+ if (!done1) {
+ if (android_logger_list_read(logger_list1, &log_msg) <= 0) {
+ done1 = true;
+ } else {
+ ++count1;
+ }
}
- int count1 = 0;
- bool done1 = false;
- int count2 = 0;
- bool done2 = false;
+ if (!done2) {
+ if (android_logger_list_read(logger_list2, &log_msg) <= 0) {
+ done2 = true;
+ } else {
+ ++count2;
+ }
+ }
+ } while ((!done1) || (!done2));
- do {
- log_msg log_msg;
+ android_logger_list_close(logger_list1);
+ android_logger_list_close(logger_list2);
- if (!done1) {
- if (android_logger_list_read(logger_list1, &log_msg) <= 0) {
- done1 = true;
- } else {
- ++count1;
- }
- }
-
- if (!done2) {
- if (android_logger_list_read(logger_list2, &log_msg) <= 0) {
- done2 = true;
- } else {
- ++count2;
- }
- }
- } while ((!done1) || (!done2));
-
- android_logger_list_close(logger_list1);
- android_logger_list_close(logger_list2);
-
- EXPECT_EQ(25, count1);
- EXPECT_EQ(15, count2);
+ EXPECT_EQ(num * SUPPORTS_END_TO_END, count1);
+ EXPECT_EQ((num - 10) * SUPPORTS_END_TO_END, count2);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-#ifdef __ANDROID__
-static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
- return android_log_shouldPrintLine(p_format, tag, pri)
- && !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
+#ifdef USING_LOGGER_DEFAULT // Do not retest logprint
+static bool checkPriForTag(AndroidLogFormat* p_format, const char* tag,
+ android_LogPriority pri) {
+ return android_log_shouldPrintLine(p_format, tag, pri) &&
+ !android_log_shouldPrintLine(p_format, tag,
+ (android_LogPriority)(pri - 1));
}
-#endif
TEST(liblog, filterRule) {
-#ifdef __ANDROID__
- static const char tag[] = "random";
+ static const char tag[] = "random";
- AndroidLogFormat *p_format = android_log_format_new();
+ AndroidLogFormat* p_format = android_log_format_new();
- android_log_addFilterRule(p_format,"*:i");
+ android_log_addFilterRule(p_format, "*:i");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
- android_log_addFilterRule(p_format, "*");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:v");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:i");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
+ 0);
+ android_log_addFilterRule(p_format, "*");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "*:v");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "*:i");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
+ 0);
- android_log_addFilterRule(p_format, tag);
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:v");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:d");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:w");
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+ android_log_addFilterRule(p_format, tag);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:v");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:d");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:w");
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
+ 0);
- android_log_addFilterRule(p_format, "crap:*");
- EXPECT_TRUE (checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
+ android_log_addFilterRule(p_format, "crap:*");
+ EXPECT_TRUE(checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(
+ android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
- // invalid expression
- EXPECT_TRUE (android_log_addFilterRule(p_format, "random:z") < 0);
- EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+ // invalid expression
+ EXPECT_TRUE(android_log_addFilterRule(p_format, "random:z") < 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
+ 0);
- // Issue #550946
- EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+ // Issue #550946
+ EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- // note trailing space
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+ // note trailing space
+ EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
+ EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
-#if 0 // bitrot, seek update
+#if 0 // bitrot, seek update
char defaultBuffer[512];
android_log_formatLogLine(p_format,
@@ -1184,1764 +1418,1811 @@
fprintf(stderr, "%s\n", defaultBuffer);
#endif
- android_log_format_free(p_format);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ android_log_format_free(p_format);
}
+#endif // USING_LOGGER_DEFAULT
+#ifdef USING_LOGGER_DEFAULT // Do not retest property handling
TEST(liblog, is_loggable) {
#ifdef __ANDROID__
- static const char tag[] = "is_loggable";
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
- // sizeof("string") = strlen("string") + 1
- char key[sizeof(log_namespace) + sizeof(tag) - 1];
- char hold[4][PROP_VALUE_MAX];
- static const struct {
- int level;
- char type;
- } levels[] = {
- { ANDROID_LOG_VERBOSE, 'v' },
- { ANDROID_LOG_DEBUG , 'd' },
- { ANDROID_LOG_INFO , 'i' },
- { ANDROID_LOG_WARN , 'w' },
- { ANDROID_LOG_ERROR , 'e' },
- { ANDROID_LOG_FATAL , 'a' },
- { -1 , 's' },
- { -2 , 'g' }, // Illegal value, resort to default
- };
+ static const char tag[] = "is_loggable";
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ // sizeof("string") = strlen("string") + 1
+ char key[sizeof(log_namespace) + sizeof(tag) - 1];
+ char hold[4][PROP_VALUE_MAX];
+ static const struct {
+ int level;
+ char type;
+ } levels[] = {
+ { ANDROID_LOG_VERBOSE, 'v' },
+ { ANDROID_LOG_DEBUG, 'd' },
+ { ANDROID_LOG_INFO, 'i' },
+ { ANDROID_LOG_WARN, 'w' },
+ { ANDROID_LOG_ERROR, 'e' },
+ { ANDROID_LOG_FATAL, 'a' },
+ { -1, 's' },
+ { -2, 'g' }, // Illegal value, resort to default
+ };
- // Set up initial test condition
- memset(hold, 0, sizeof(hold));
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- property_get(key, hold[0], "");
- property_set(key, "");
- property_get(key + base_offset, hold[1], "");
- property_set(key + base_offset, "");
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_get(key, hold[2], "");
- property_set(key, "");
- property_get(key, hold[3], "");
- property_set(key + base_offset, "");
+ // Set up initial test condition
+ memset(hold, 0, sizeof(hold));
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ property_get(key, hold[0], "");
+ property_set(key, "");
+ property_get(key + base_offset, hold[1], "");
+ property_set(key + base_offset, "");
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_get(key, hold[2], "");
+ property_set(key, "");
+ property_get(key, hold[3], "");
+ property_set(key + base_offset, "");
- // All combinations of level and defaults
- for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- if (levels[j].level == -2) {
- continue;
- }
- fprintf(stderr, "i=%zu j=%zu\r", i, j);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- }
- }
+ // All combinations of level and defaults
+ for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
}
-
- // All combinations of level and tag and global properties
- for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
+ for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ if (levels[j].level == -2) {
+ continue;
+ }
+ fprintf(stderr, "i=%zu j=%zu\r", i, j);
+ bool android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), levels[j].level);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1)) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
}
- for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key, buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_DEBUG)
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_DEBUG)
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
-
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key, buf);
- property_set(key, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_DEBUG)
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_DEBUG)
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), levels[j].level));
}
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), levels[j].level));
+ }
+ }
}
+ }
- // All combinations of level and tag properties, but with global set to INFO
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- usleep(20000);
- property_set(key, "I");
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key, buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
- i, j, key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level)
- || (levels[j].level == -1)
- || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
- }
+ // All combinations of level and tag and global properties
+ for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
}
+ for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
- // reset parms
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- usleep(20000);
- property_set(key, hold[0]);
- property_set(key + base_offset, hold[1]);
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_set(key, hold[2]);
- property_set(key + base_offset, hold[3]);
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
+ buf);
+ usleep(20000);
+ property_set(key, buf);
+ bool android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
+ key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key + base_offset, "");
+
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
+ buf);
+ property_set(key, buf);
+ android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
+ key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // All combinations of level and tag properties, but with global set to INFO
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ usleep(20000);
+ property_set(key, "I");
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
+ buf);
+ usleep(20000);
+ property_set(key, buf);
+ bool android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
+ key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ android_log_is_loggable = __android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
+ if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
+ ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ if (android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_FALSE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_FALSE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ } else {
+ if (!android_log_is_loggable) {
+ fprintf(stderr, "\n");
+ }
+ EXPECT_TRUE(android_log_is_loggable);
+ for (size_t k = 10; k; --k) {
+ EXPECT_TRUE(__android_log_is_loggable_len(
+ levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
+ }
+ }
+ usleep(20000);
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // reset parms
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ usleep(20000);
+ property_set(key, hold[0]);
+ property_set(key + base_offset, hold[1]);
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_set(key, hold[2]);
+ property_set(key + base_offset, hold[3]);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOGGER_DEFAULT
-#ifdef __ANDROID__
+// Following tests the specific issues surrounding error handling wrt logd.
+// Kills logd and toss all collected data, equivalent to logcat -b all -c,
+// except we also return errors to the logging callers.
+#ifdef USING_LOGGER_DEFAULT
+#ifdef TEST_PREFIX
// helper to liblog.enoent to count end-to-end matching logging messages.
static int count_matching_ts(log_time ts) {
- usleep(1000000);
+ usleep(1000000);
- pid_t pid = getpid();
+ pid_t pid = getpid();
- struct logger_list* logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
+ struct logger_list* logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
- int count = 0;
- if (logger_list == NULL) return count;
+ int count = 0;
+ if (logger_list == NULL) return count;
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
- if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
- if (log_msg.id() != LOG_ID_EVENTS) continue;
+ if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
+ if (log_msg.id() != LOG_ID_EVENTS) continue;
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData) continue;
- if (eventData->payload.type != EVENT_TYPE_LONG) continue;
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+ if (!eventData) continue;
+ if (eventData->payload.type != EVENT_TYPE_LONG) continue;
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts != tx) continue;
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts != tx) continue;
- // found event message with matching timestamp signature in payload
- ++count;
- }
- android_logger_list_close(logger_list);
+ // found event message with matching timestamp signature in payload
+ ++count;
+ }
+ android_logger_list_close(logger_list);
- return count;
+ return count;
}
// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
-static testing::AssertionResult IsOk(bool ok, std::string &message) {
- return ok ?
- testing::AssertionSuccess() :
- (testing::AssertionFailure() << message);
+static testing::AssertionResult IsOk(bool ok, std::string& message) {
+ return ok ? testing::AssertionSuccess()
+ : (testing::AssertionFailure() << message);
}
-#endif
+#endif // TEST_PREFIX
TEST(liblog, enoent) {
-#ifdef __ANDROID__
- log_time ts(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
+#ifdef TEST_PREFIX
+ TEST_PREFIX
+ log_time ts(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ EXPECT_EQ(SUPPORTS_END_TO_END, count_matching_ts(ts));
- // This call will fail if we are setuid(AID_SYSTEM), beware of any
- // test prior to this one playing with setuid and causing interference.
- // We need to run before these tests so that they do not interfere with
- // this test.
- //
- // Stopping the logger can affect some other test's expectations as they
- // count on the log buffers filled with existing content, and this
- // effectively does a logcat -c emptying it. So we want this test to be
- // as near as possible to the bottom of the file. For example
- // liblog.android_logger_get_ is one of those tests that has no recourse
- // and that would be adversely affected by emptying the log if it was run
- // right after this test.
- system("stop logd");
- usleep(1000000);
+ // This call will fail if we are setuid(AID_SYSTEM), beware of any
+ // test prior to this one playing with setuid and causing interference.
+ // We need to run before these tests so that they do not interfere with
+ // this test.
+ //
+ // Stopping the logger can affect some other test's expectations as they
+ // count on the log buffers filled with existing content, and this
+ // effectively does a logcat -c emptying it. So we want this test to be
+ // as near as possible to the bottom of the file. For example
+ // liblog.android_logger_get_ is one of those tests that has no recourse
+ // and that would be adversely affected by emptying the log if it was run
+ // right after this test.
+ system("stop logd");
+ usleep(1000000);
- // A clean stop like we are testing returns -ENOENT, but in the _real_
- // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
- // Alas we can not test these other return values; accept that they
- // are treated equally within the open-retry logic in liblog.
- ts = log_time(CLOCK_MONOTONIC);
- int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- std::string content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, strerror(-ret));
- EXPECT_TRUE(IsOk((ret == -ENOENT) ||
- (ret == -ENOTCONN) ||
- (ret == -ECONNREFUSED), content));
- ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, strerror(-ret));
- EXPECT_TRUE(IsOk((ret == -ENOENT) ||
- (ret == -ENOTCONN) ||
- (ret == -ECONNREFUSED), content));
- EXPECT_EQ(0, count_matching_ts(ts));
+ // A clean stop like we are testing returns -ENOENT, but in the _real_
+ // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
+ // Alas we can not test these other return values; accept that they
+ // are treated equally within the open-retry logic in liblog.
+ ts = log_time(CLOCK_MONOTONIC);
+ int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+ std::string content = android::base::StringPrintf(
+ "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+ ret, strerror(-ret));
+ EXPECT_TRUE(
+ IsOk((ret == -ENOENT) || (ret == -ENOTCONN) || (ret == -ECONNREFUSED),
+ content));
+ ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+ content = android::base::StringPrintf(
+ "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+ ret, strerror(-ret));
+ EXPECT_TRUE(
+ IsOk((ret == -ENOENT) || (ret == -ENOTCONN) || (ret == -ECONNREFUSED),
+ content));
+ EXPECT_EQ(0, count_matching_ts(ts));
- system("start logd");
- usleep(1000000);
+ system("start logd");
+ usleep(1000000);
- EXPECT_EQ(0, count_matching_ts(ts));
+ EXPECT_EQ(0, count_matching_ts(ts));
- ts = log_time(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
+ ts = log_time(CLOCK_MONOTONIC);
+ EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ EXPECT_EQ(SUPPORTS_END_TO_END, count_matching_ts(ts));
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOCAL_LOGD
// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
+// Do not retest properties, and cannot log into LOG_ID_SECURITY
+#ifdef USING_LOGGER_DEFAULT
TEST(liblog, __security) {
#ifdef __ANDROID__
- static const char persist_key[] = "persist.logd.security";
- static const char readonly_key[] = "ro.device_owner";
- // A silly default value that can never be in readonly_key so
- // that it can be determined the property is not set.
- static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
- char persist[PROP_VALUE_MAX];
- char readonly[PROP_VALUE_MAX];
+ static const char persist_key[] = "persist.logd.security";
+ static const char readonly_key[] = "ro.device_owner";
+ // A silly default value that can never be in readonly_key so
+ // that it can be determined the property is not set.
+ static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
+ char persist[PROP_VALUE_MAX];
+ char readonly[PROP_VALUE_MAX];
- property_get(persist_key, persist, "");
- property_get(readonly_key, readonly, nothing_val);
+ property_get(persist_key, persist, "");
+ property_get(readonly_key, readonly, nothing_val);
- if (!strcmp(readonly, nothing_val)) {
- EXPECT_FALSE(__android_log_security());
- fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
- property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
- } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
- EXPECT_FALSE(__android_log_security());
- return;
- }
+ if (!strcmp(readonly, nothing_val)) {
+ EXPECT_FALSE(__android_log_security());
+ fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
+ property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
+ } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
+ EXPECT_FALSE(__android_log_security());
+ return;
+ }
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "TRUE");
+ if (!strcasecmp(persist, "true")) {
EXPECT_TRUE(__android_log_security());
- property_set(persist_key, "FALSE");
+ } else {
EXPECT_FALSE(__android_log_security());
- property_set(persist_key, "true");
- EXPECT_TRUE(__android_log_security());
- property_set(persist_key, "false");
- EXPECT_FALSE(__android_log_security());
- property_set(persist_key, "");
- EXPECT_FALSE(__android_log_security());
- property_set(persist_key, persist);
+ }
+ property_set(persist_key, "TRUE");
+ EXPECT_TRUE(__android_log_security());
+ property_set(persist_key, "FALSE");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, "true");
+ EXPECT_TRUE(__android_log_security());
+ property_set(persist_key, "false");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, "");
+ EXPECT_FALSE(__android_log_security());
+ property_set(persist_key, persist);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, __security_buffer) {
#ifdef __ANDROID__
- struct logger_list *logger_list;
- android_event_long_t buffer;
+ struct logger_list* logger_list;
+ android_event_long_t buffer;
- static const char persist_key[] = "persist.logd.security";
- char persist[PROP_VALUE_MAX];
- bool set_persist = false;
- bool allow_security = false;
+ static const char persist_key[] = "persist.logd.security";
+ char persist[PROP_VALUE_MAX];
+ bool set_persist = false;
+ bool allow_security = false;
- if (__android_log_security()) {
+ if (__android_log_security()) {
+ allow_security = true;
+ } else {
+ property_get(persist_key, persist, "");
+ if (strcasecmp(persist, "true")) {
+ property_set(persist_key, "TRUE");
+ if (__android_log_security()) {
allow_security = true;
- } else {
- property_get(persist_key, persist, "");
- if (strcasecmp(persist, "true")) {
- property_set(persist_key, "TRUE");
- if (__android_log_security()) {
- allow_security = true;
- set_persist = true;
- } else {
- property_set(persist_key, persist);
- }
- }
+ set_persist = true;
+ } else {
+ property_set(persist_key, persist);
+ }
}
+ }
- if (!allow_security) {
- fprintf(stderr, "WARNING: "
- "security buffer disabled, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- /* Matches clientHasLogCredentials() in logd */
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool clientHasLogCredentials = true;
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
- && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- uid_t euid = geteuid();
- if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
- gid_t egid = getegid();
- if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
- int num_groups = getgroups(0, NULL);
- if (num_groups > 0) {
- gid_t groups[num_groups];
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- }
- if (num_groups <= 0) {
- clientHasLogCredentials = false;
- }
- }
- }
- }
- if (!clientHasLogCredentials) {
- fprintf(stderr, "WARNING: "
- "not in system context, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- EXPECT_EQ(0, setuid(AID_SYSTEM)); // only one that can read security buffer
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- 1000, pid)));
+ if (!allow_security) {
+ fprintf(stderr,
+ "WARNING: "
+ "security buffer disabled, bypassing end-to-end test\n");
log_time ts(CLOCK_MONOTONIC);
buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+ buffer.data = *(static_cast<uint64_t*>((void*)&ts));
- ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
- usleep(1000000);
+ // expect failure!
+ ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
- int count = 0;
+ return;
+ }
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
+ /* Matches clientHasLogCredentials() in logd */
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+ bool clientHasLogCredentials = true;
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG) &&
+ (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+ uid_t euid = geteuid();
+ if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
+ gid_t egid = getegid();
+ if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
+ int num_groups = getgroups(0, NULL);
+ if (num_groups > 0) {
+ gid_t groups[num_groups];
+ num_groups = getgroups(num_groups, groups);
+ while (num_groups > 0) {
+ if (groups[num_groups - 1] == AID_LOG) {
+ break;
+ }
+ --num_groups;
+ }
}
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t))
- || (log_msg.id() != LOG_ID_SECURITY)) {
- continue;
+ if (num_groups <= 0) {
+ clientHasLogCredentials = false;
}
+ }
+ }
+ }
+ if (!clientHasLogCredentials) {
+ fprintf(stderr,
+ "WARNING: "
+ "not in system context, bypassing end-to-end test\n");
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+ log_time ts(CLOCK_MONOTONIC);
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
+ buffer.type = EVENT_TYPE_LONG;
+ buffer.data = *(static_cast<uint64_t*>((void*)&ts));
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts == tx) {
- ++count;
- }
+ // expect failure!
+ ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+ return;
+ }
+
+ EXPECT_EQ(0, setuid(AID_SYSTEM)); // only one that can read security buffer
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
+
+ log_time ts(CLOCK_MONOTONIC);
+
+ buffer.type = EVENT_TYPE_LONG;
+ buffer.data = *(static_cast<uint64_t*>((void*)&ts));
+
+ ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- if (set_persist) {
- property_set(persist_key, persist);
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
+ (log_msg.id() != LOG_ID_SECURITY)) {
+ continue;
}
- android_logger_list_close(logger_list);
+ android_log_event_long_t* eventData;
+ eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
- if (!clientHasSecurityCredentials) {
- fprintf(stderr, "WARNING: "
- "not system, content submitted but can not check end-to-end\n");
+ if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+ continue;
}
- EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
+
+ log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+ if (ts == tx) {
+ ++count;
+ }
+ }
+
+ if (set_persist) {
+ property_set(persist_key, persist);
+ }
+
+ android_logger_list_close(logger_list);
+
+ bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
+ if (!clientHasSecurityCredentials) {
+ fprintf(stderr,
+ "WARNING: "
+ "not system, content submitted but can not check end-to-end\n");
+ }
+ EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOGGER_DEFAULT
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
int UID, const char* payload,
int DATA_LEN, int& count) {
- struct logger_list *logger_list;
+ TEST_PREFIX
+ struct logger_list* logger_list;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ count = 0;
- int retval_android_errorWriteWithinInfoLog = android_errorWriteWithInfoLog(
- TAG, SUBTAG, UID, payload, DATA_LEN);
- if (payload) {
- ASSERT_LT(0, retval_android_errorWriteWithinInfoLog);
- } else {
- ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
+
+ int retval_android_errorWriteWithinInfoLog =
+ android_errorWriteWithInfoLog(TAG, SUBTAG, UID, payload, DATA_LEN);
+ if (payload) {
+ ASSERT_LT(0, retval_android_errorWriteWithinInfoLog);
+ } else {
+ ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
+ }
+
+ sleep(2);
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- sleep(2);
-
- count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- char *eventData = log_msg.msg();
- if (!eventData) {
- continue;
- }
-
- char *original = eventData;
-
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
-
- if (tag != TAG) {
- continue;
- }
-
- if (!payload) {
- // This tag should not have been written because the data was null
- ++count;
- break;
- }
-
- // List type
- ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
- eventData++;
-
- // Number of elements in list
- ASSERT_EQ(3, eventData[0]);
- eventData++;
-
- // Element #1: string type for subtag
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- int subtag_len = strlen(SUBTAG);
- if (subtag_len > 32) subtag_len = 32;
- ASSERT_EQ(subtag_len, get4LE(eventData));
- eventData += 4;
-
- if (memcmp(SUBTAG, eventData, subtag_len)) {
- continue;
- }
- eventData += subtag_len;
-
- // Element #2: int type for uid
- ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
- eventData++;
-
- ASSERT_EQ(UID, get4LE(eventData));
- eventData += 4;
-
- // Element #3: string type for data
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- size_t dataLen = get4LE(eventData);
- eventData += 4;
- if (DATA_LEN < 512) ASSERT_EQ(DATA_LEN, (int)dataLen);
-
- if (memcmp(payload, eventData, dataLen)) {
- continue;
- }
-
- if (DATA_LEN >= 512) {
- eventData += dataLen;
- // 4 bytes for the tag, and max_payload_buf should be truncated.
- ASSERT_LE(4 + 512, eventData - original); // worst expectations
- ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
- }
-
- ++count;
+ char* eventData = log_msg.msg();
+ if (!eventData) {
+ continue;
}
- android_logger_list_close(logger_list);
+ char* original = eventData;
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ if (!payload) {
+ // This tag should not have been written because the data was null
+ ++count;
+ break;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ unsigned subtag_len = strlen(SUBTAG);
+ if (subtag_len > 32) subtag_len = 32;
+ ASSERT_EQ(subtag_len, get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(SUBTAG, eventData, subtag_len)) {
+ continue;
+ }
+ eventData += subtag_len;
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, (int)get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ size_t dataLen = get4LE(eventData);
+ eventData += 4;
+ if (DATA_LEN < 512) ASSERT_EQ(DATA_LEN, (int)dataLen);
+
+ if (memcmp(payload, eventData, dataLen)) {
+ continue;
+ }
+
+ if (DATA_LEN >= 512) {
+ eventData += dataLen;
+ // 4 bytes for the tag, and max_payload_buf should be truncated.
+ ASSERT_LE(4 + 512, eventData - original); // worst expectations
+ ASSERT_GT(4 + DATA_LEN, eventData - original); // must be truncated
+ }
+
+ ++count;
+ }
+
+ android_logger_list_close(logger_list);
}
#endif
TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteWithInfoLog_helper(
- 123456781,
- "test-subtag",
- -1,
- max_payload_buf,
- 200,
- count);
- EXPECT_EQ(1, count);
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteWithInfoLog_helper(123456781, "test-subtag", -1,
+ max_payload_buf, 200, count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteWithInfoLog_helper(
- 123456782,
- "test-subtag",
- -1,
- max_payload_buf,
- sizeof(max_payload_buf),
- count);
- EXPECT_EQ(1, count);
+TEST(liblog,
+ android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteWithInfoLog_helper(123456782, "test-subtag", -1,
+ max_payload_buf, sizeof(max_payload_buf),
+ count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteWithInfoLog_helper(
- 123456783,
- "test-subtag",
- -1,
- NULL,
- 200,
- count);
- EXPECT_EQ(0, count);
+TEST(liblog,
+ android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteWithInfoLog_helper(123456783, "test-subtag", -1, NULL, 200,
+ count);
+ EXPECT_EQ(0, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteWithInfoLog_helper(
- 123456784,
- "abcdefghijklmnopqrstuvwxyz now i know my abc",
- -1,
- max_payload_buf,
- 200,
- count);
- EXPECT_EQ(1, count);
+TEST(liblog,
+ android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteWithInfoLog_helper(
+ 123456784, "abcdefghijklmnopqrstuvwxyz now i know my abc", -1,
+ max_payload_buf, 200, count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, __android_log_bswrite_and_print___max) {
- bswrite_test(max_payload_buf);
+ bswrite_test(max_payload_buf);
}
TEST(liblog, __android_log_buf_write_and_print__max) {
- buf_write_test(max_payload_buf);
+ buf_write_test(max_payload_buf);
}
-#ifdef __ANDROID__
-static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count) {
- struct logger_list *logger_list;
+#ifdef TEST_PREFIX
+static void android_errorWriteLog_helper(int TAG, const char* SUBTAG,
+ int& count) {
+ TEST_PREFIX
+ struct logger_list* logger_list;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ count = 0;
- int retval_android_errorWriteLog = android_errorWriteLog(TAG, SUBTAG);
- if (SUBTAG) {
- ASSERT_LT(0, retval_android_errorWriteLog);
- } else {
- ASSERT_GT(0, retval_android_errorWriteLog);
+ // Do a Before and After on the count to measure the effect. Decrement
+ // what we find in Before to set the stage.
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+ char* eventData = log_msg.msg();
+ if (!eventData) continue;
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) continue;
+
+ if (!SUBTAG) {
+ // This tag should not have been written because the data was null
+ --count;
+ break;
}
- sleep(2);
+ // List type
+ eventData++;
+ // Number of elements in list
+ eventData++;
+ // Element #1: string type for subtag
+ eventData++;
- count = 0;
+ eventData += 4;
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) continue;
+ --count;
+ }
- char *eventData = log_msg.msg();
- if (!eventData) {
- continue;
- }
+ android_logger_list_close(logger_list);
- // Tag
- int tag = get4LE(eventData);
- eventData += 4;
+ // Do an After on the count to measure the effect.
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
- if (tag != TAG) {
- continue;
- }
+ int retval_android_errorWriteLog = android_errorWriteLog(TAG, SUBTAG);
+ if (SUBTAG) {
+ ASSERT_LT(0, retval_android_errorWriteLog);
+ } else {
+ ASSERT_GT(0, retval_android_errorWriteLog);
+ }
- if (!SUBTAG) {
- // This tag should not have been written because the data was null
- ++count;
- break;
- }
+ sleep(2);
- // List type
- ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
- eventData++;
-
- // Number of elements in list
- ASSERT_EQ(3, eventData[0]);
- eventData++;
-
- // Element #1: string type for subtag
- ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
- eventData++;
-
- ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
- eventData +=4;
-
- if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
- continue;
- }
- ++count;
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
}
- android_logger_list_close(logger_list);
+ char* eventData = log_msg.msg();
+ if (!eventData) {
+ continue;
+ }
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ if (!SUBTAG) {
+ // This tag should not have been written because the data was null
+ ++count;
+ break;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(strlen(SUBTAG), get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ ++count;
+ }
+
+ android_logger_list_close(logger_list);
}
#endif
TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteLog_helper(123456785, "test-subtag", count);
- EXPECT_EQ(1, count);
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteLog_helper(123456785, "test-subtag", count);
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-#ifdef __ANDROID__
- int count;
- android_errorWriteLog_helper(123456786, NULL, count);
- EXPECT_EQ(0, count);
+#ifdef TEST_PREFIX
+ int count;
+ android_errorWriteLog_helper(123456786, NULL, count);
+ EXPECT_EQ(0, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-#ifdef __ANDROID__
+// Do not retest logger list handling
+#if (defined(TEST_PREFIX) || !defined(USING_LOGGER_LOCAL))
static int is_real_element(int type) {
- return ((type == EVENT_TYPE_INT) ||
- (type == EVENT_TYPE_LONG) ||
- (type == EVENT_TYPE_STRING) ||
- (type == EVENT_TYPE_FLOAT));
+ return ((type == EVENT_TYPE_INT) || (type == EVENT_TYPE_LONG) ||
+ (type == EVENT_TYPE_STRING) || (type == EVENT_TYPE_FLOAT));
}
-int android_log_buffer_to_string(const char *msg, size_t len,
- char *strOut, size_t strOutLen) {
- android_log_context context = create_android_log_parser(msg, len);
- android_log_list_element elem;
- bool overflow = false;
- /* Reserve 1 byte for null terminator. */
- size_t origStrOutLen = strOutLen--;
+static int android_log_buffer_to_string(const char* msg, size_t len,
+ char* strOut, size_t strOutLen) {
+ android_log_context context = create_android_log_parser(msg, len);
+ android_log_list_element elem;
+ bool overflow = false;
+ /* Reserve 1 byte for null terminator. */
+ size_t origStrOutLen = strOutLen--;
- if (!context) {
- return -EBADF;
- }
+ if (!context) {
+ return -EBADF;
+ }
- memset(&elem, 0, sizeof(elem));
+ memset(&elem, 0, sizeof(elem));
- size_t outCount;
+ size_t outCount;
- do {
- elem = android_log_read_next(context);
- switch ((int)elem.type) {
- case EVENT_TYPE_LIST:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = '[';
- strOutLen--;
- }
- break;
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_LIST:
+ if (strOutLen == 0) {
+ overflow = true;
+ } else {
+ *strOut++ = '[';
+ strOutLen--;
+ }
+ break;
- case EVENT_TYPE_LIST_STOP:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ']';
- strOutLen--;
- }
- break;
+ case EVENT_TYPE_LIST_STOP:
+ if (strOutLen == 0) {
+ overflow = true;
+ } else {
+ *strOut++ = ']';
+ strOutLen--;
+ }
+ break;
- case EVENT_TYPE_INT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1,
- "%" PRId32, elem.data.int32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
+ case EVENT_TYPE_INT:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1, "%" PRId32, elem.data.int32);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
- case EVENT_TYPE_LONG:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1,
- "%" PRId64, elem.data.int64);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
+ case EVENT_TYPE_LONG:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1, "%" PRId64, elem.data.int64);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
- case EVENT_TYPE_FLOAT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
+ case EVENT_TYPE_FLOAT:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
- default:
- elem.complete = true;
- break;
+ default:
+ elem.complete = true;
+ break;
- case EVENT_TYPE_UNKNOWN:
-#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
+ case EVENT_TYPE_UNKNOWN:
+#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
if (elem.complete) {
break;
}
#endif
- elem.data.string = const_cast<char *>("<unknown>");
- elem.len = strlen(elem.data.string);
- /* FALLTHRU */
- case EVENT_TYPE_STRING:
- if (elem.len <= strOutLen) {
- memcpy(strOut, elem.data.string, elem.len);
- strOut += elem.len;
- strOutLen -= elem.len;
- } else if (strOutLen > 0) {
- /* copy what we can */
- memcpy(strOut, elem.data.string, strOutLen);
- strOut += strOutLen;
- strOutLen = 0;
- overflow = true;
- }
- break;
+ elem.data.string = const_cast<char*>("<unknown>");
+ elem.len = strlen(elem.data.string);
+ /* FALLTHRU */
+ case EVENT_TYPE_STRING:
+ if (elem.len <= strOutLen) {
+ memcpy(strOut, elem.data.string, elem.len);
+ strOut += elem.len;
+ strOutLen -= elem.len;
+ } else if (strOutLen > 0) {
+ /* copy what we can */
+ memcpy(strOut, elem.data.string, strOutLen);
+ strOut += strOutLen;
+ strOutLen = 0;
+ overflow = true;
}
+ break;
+ }
- if (elem.complete) {
- break;
- }
- /* Determine whether to put a comma or not. */
- if (!overflow && (is_real_element(elem.type) ||
- (elem.type == EVENT_TYPE_LIST_STOP))) {
- android_log_list_element next = android_log_peek_next(context);
- if (!next.complete && (is_real_element(next.type) ||
- (next.type == EVENT_TYPE_LIST))) {
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ',';
- strOutLen--;
- }
- }
- }
- } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
-
- android_log_destroy(&context);
-
- if (overflow) {
- if (strOutLen < origStrOutLen) {
- /* leave an indicator */
- *(strOut-1) = '!';
+ if (elem.complete) {
+ break;
+ }
+ /* Determine whether to put a comma or not. */
+ if (!overflow &&
+ (is_real_element(elem.type) || (elem.type == EVENT_TYPE_LIST_STOP))) {
+ android_log_list_element next = android_log_peek_next(context);
+ if (!next.complete &&
+ (is_real_element(next.type) || (next.type == EVENT_TYPE_LIST))) {
+ if (strOutLen == 0) {
+ overflow = true;
} else {
- /* nothing was written at all */
- *strOut++ = '!';
+ *strOut++ = ',';
+ strOutLen--;
}
+ }
}
- *strOut++ = '\0';
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
- if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- return -EINVAL;
+ android_log_destroy(&context);
+
+ if (overflow) {
+ if (strOutLen < origStrOutLen) {
+ /* leave an indicator */
+ *(strOut - 1) = '!';
+ } else {
+ /* nothing was written at all */
+ *strOut++ = '!';
}
+ }
+ *strOut++ = '\0';
- return 0;
+ if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
+ fprintf(stderr, "Binary log entry conversion failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif // TEST_PREFIX || !USING_LOGGER_LOCAL
+
+#ifdef TEST_PREFIX
+static const char* event_test_int32(uint32_t tag, size_t& expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+
+ return "1076895760";
}
-static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_int64(uint32_t tag, size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint32_t);
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t);
- return "1076895760";
+ return "-9191740941672636400";
}
-static const char *event_test_int64(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_list_int64(uint32_t tag, size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint64_t);
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint64_t);
- return "-9191740941672636400";
+ return "[-9191740941672636400]";
}
-static const char *event_test_list_int64(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_simple_automagic_list(uint32_t tag,
+ size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ // The convenience API where we allow a simple list to be
+ // created without explicit begin or end calls.
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint64_t);
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
+ sizeof(uint64_t);
- return "[-9191740941672636400]";
+ return "[1076895760,-9191740941672636400]";
}
-static const char *event_test_simple_automagic_list(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_list_empty(uint32_t tag, size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- // The convenience API where we allow a simple list to be
- // created without explicit begin or end calls.
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint64_t);
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t);
- return "[1076895760,-9191740941672636400]";
+ return "[]";
}
-static const char *event_test_list_empty(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_complex_nested_list(uint32_t tag,
+ size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t);
+ EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
+ EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
+ EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
+ EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
+ EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
- return "[]";
+ //
+ // This one checks for the automagic list creation because a list
+ // begin and end was missing for it! This is actually an <oops> corner
+ // case, and not the behavior we morally support. The automagic API is to
+ // allow for a simple case of a series of objects in a single list. e.g.
+ // int32,int32,int32,string -> [int32,int32,int32,string]
+ //
+ EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
+
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
+ 1 + sizeof(uint8_t) + sizeof(uint8_t) +
+ 4 * (sizeof(uint8_t) + sizeof(uint32_t)) + sizeof(uint8_t) +
+ sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof("dlroW olleH") - 1;
+
+ return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW "
+ "olleH]";
}
-static const char *event_test_complex_nested_list(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_7_level_prefix(uint32_t tag,
+ size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 5));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 6));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 7));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
- EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
- EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
+ expected_len = sizeof(uint32_t) + 7 * (sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t));
- //
- // This one checks for the automagic list creation because a list
- // begin and end was missing for it! This is actually an <oops> corner
- // case, and not the behavior we morally support. The automagic API is to
- // allow for a simple case of a series of objects in a single list. e.g.
- // int32,int32,int32,string -> [int32,int32,int32,string]
- //
- EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
-
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint64_t) +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof("Hello World") - 1 +
- sizeof(uint8_t) + sizeof(uint8_t) +
- 4 * (sizeof(uint8_t) + sizeof(uint32_t)) +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof("dlroW olleH") - 1;
-
- return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW olleH]";
+ return "[[[[[[[1],2],3],4],5],6],7]";
}
-static const char *event_test_7_level_prefix(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_7_level_suffix(uint32_t tag,
+ size_t& expected_len) {
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 7));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 5));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 6));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
- expected_len = sizeof(uint32_t) + 7 *
- (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
+ expected_len = sizeof(uint32_t) + 6 * (sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t));
- return "[[[[[[[1],2],3],4],5],6],7]";
+ return "[1,[2,[3,[4,[5,[6]]]]]]";
}
-static const char *event_test_7_level_suffix(uint32_t tag, size_t &expected_len) {
- android_log_context ctx;
+static const char* event_test_android_log_error_write(uint32_t tag,
+ size_t& expected_len) {
+ EXPECT_LE(
+ 0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
+ 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
+ sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
- expected_len = sizeof(uint32_t) + 6 *
- (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
-
- return "[1,[2,[3,[4,[5,[6]]]]]]";
+ return "[Hello World,42,dlroW olleH]";
}
-static const char *event_test_android_log_error_write(uint32_t tag, size_t &expected_len) {
- EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
+static const char* event_test_android_log_error_write_null(uint32_t tag,
+ size_t& expected_len) {
+ EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
+ expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
+ 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
+ sizeof(uint32_t) + sizeof("") - 1;
- return "[Hello World,42,dlroW olleH]";
-}
-
-static const char *event_test_android_log_error_write_null(uint32_t tag, size_t &expected_len) {
- EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
-
- expected_len = sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") - 1 +
- sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("") - 1;
-
- return "[Hello World,42,]";
+ return "[Hello World,42,]";
}
// make sure all user buffers are flushed
static void print_barrier() {
- std::cout.flush();
- fflush(stdout);
- std::cerr.flush();
- fflush(stderr); // everything else is paranoia ...
+ std::cout.flush();
+ fflush(stdout);
+ std::cerr.flush();
+ fflush(stderr); // everything else is paranoia ...
}
-static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
- struct logger_list *logger_list;
+static void create_android_logger(const char* (*fn)(uint32_t tag,
+ size_t& expected_len)) {
+ TEST_PREFIX
+ struct logger_list* logger_list;
- pid_t pid = getpid();
+ pid_t pid = getpid();
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 1000, pid)));
- log_time ts(android_log_clockid());
+#ifdef __ANDROID__
+ log_time ts(android_log_clockid());
+#else
+ log_time ts(CLOCK_REALTIME);
+#endif
- size_t expected_len;
- const char *expected_string = (*fn)(1005, expected_len);
+ size_t expected_len;
+ const char* expected_string = (*fn)(1005, expected_len);
- if (!expected_string) {
- android_logger_list_close(logger_list);
- return;
- }
-
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.sec < (ts.tv_sec - 1))
- || ((ts.tv_sec + 1) < log_msg.entry.sec)
- || ((size_t)log_msg.entry.len != expected_len)
- || (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char *eventData = log_msg.msg();
-
- ++count;
-
- AndroidLogFormat *logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
- &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
- EXPECT_EQ(0, processBinaryLogBuffer);
- if (processBinaryLogBuffer == 0) {
- print_barrier();
- int printLogLine = android_log_printLogLine(
- logformat, fileno(stderr), &entry);
- print_barrier();
- EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
- }
- android_log_format_free(logformat);
-
- // test buffer reading API
- int buffer_to_string = -1;
- if (eventData) {
- snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
- print_barrier();
- fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
- memset(msgBuf, 0, sizeof(msgBuf));
- buffer_to_string = android_log_buffer_to_string(
- eventData + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t),
- msgBuf, sizeof(msgBuf));
- fprintf(stderr, "%s\n", msgBuf);
- print_barrier();
- }
- EXPECT_EQ(0, buffer_to_string);
- EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
- EXPECT_EQ(0, strcmp(expected_string, msgBuf));
- }
-
- EXPECT_EQ(1, count);
-
+ if (!expected_string) {
android_logger_list_close(logger_list);
+ return;
+ }
+
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.sec < (ts.tv_sec - 1)) ||
+ ((ts.tv_sec + 1) < log_msg.entry.sec) ||
+ ((size_t)log_msg.entry.len != expected_len) ||
+ (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
+
+ char* eventData = log_msg.msg();
+
+ ++count;
+
+ AndroidLogFormat* logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ char msgBuf[1024];
+ int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+ &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+ EXPECT_EQ(0, processBinaryLogBuffer);
+ if (processBinaryLogBuffer == 0) {
+ int line_overhead = 20;
+ if (pid > 99999) ++line_overhead;
+ if (pid > 999999) ++line_overhead;
+ print_barrier();
+ int printLogLine =
+ android_log_printLogLine(logformat, fileno(stderr), &entry);
+ print_barrier();
+ EXPECT_EQ(line_overhead + (int)strlen(expected_string), printLogLine);
+ }
+ android_log_format_free(logformat);
+
+ // test buffer reading API
+ int buffer_to_string = -1;
+ if (eventData) {
+ snprintf(msgBuf, sizeof(msgBuf), "I/[%" PRIu32 "]", get4LE(eventData));
+ print_barrier();
+ fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
+ memset(msgBuf, 0, sizeof(msgBuf));
+ buffer_to_string = android_log_buffer_to_string(
+ eventData + sizeof(uint32_t), log_msg.entry.len - sizeof(uint32_t),
+ msgBuf, sizeof(msgBuf));
+ fprintf(stderr, "%s\n", msgBuf);
+ print_barrier();
+ }
+ EXPECT_EQ(0, buffer_to_string);
+ EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
+ EXPECT_EQ(0, strcmp(expected_string, msgBuf));
+ }
+
+ EXPECT_EQ(SUPPORTS_END_TO_END, count);
+
+ android_logger_list_close(logger_list);
}
#endif
TEST(liblog, create_android_logger_int32) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int32);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_int32);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int64);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_int64);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_list_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_int64);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_list_int64);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_simple_automagic_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_simple_automagic_list);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_simple_automagic_list);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_list_empty) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_empty);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_list_empty);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_complex_nested_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_complex_nested_list);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_complex_nested_list);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_7_level_prefix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_prefix);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_7_level_prefix);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_7_level_suffix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_suffix);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_7_level_suffix);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_android_log_error_write) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_android_log_error_write);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, create_android_logger_android_log_error_write_null) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write_null);
+#ifdef TEST_PREFIX
+ create_android_logger(event_test_android_log_error_write_null);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#ifdef USING_LOGGER_DEFAULT // Do not retest logger list handling
TEST(liblog, create_android_logger_overflow) {
-#ifdef __ANDROID__
- android_log_context ctx;
+ android_log_context ctx;
- EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
- if (ctx) {
- for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- }
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- /* One more for good measure, must be permanently unhappy */
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
- }
-
- ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
+ if (ctx) {
for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, i));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
}
EXPECT_GT(0, android_log_write_list_begin(ctx));
/* One more for good measure, must be permanently unhappy */
EXPECT_GT(0, android_log_write_list_begin(ctx));
EXPECT_LE(0, android_log_destroy(&ctx));
- ASSERT_TRUE(NULL == ctx);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ EXPECT_TRUE(NULL == ctx);
+ }
+
+ ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
+ for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, i));
+ }
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ /* One more for good measure, must be permanently unhappy */
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ ASSERT_TRUE(NULL == ctx);
}
TEST(liblog, android_log_write_list_buffer) {
-#ifdef __ANDROID__
- __android_log_event_list ctx(1005);
- ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
- std::string buffer(ctx);
- ctx.close();
+ __android_log_event_list ctx(1005);
+ ctx << 1005 << "tag_def"
+ << "(tag|1),(name|3),(format|3)";
+ std::string buffer(ctx);
+ ctx.close();
- char msgBuf[1024];
- memset(msgBuf, 0, sizeof(msgBuf));
- EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
- msgBuf, sizeof(msgBuf)), 0);
- EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ char msgBuf[1024];
+ memset(msgBuf, 0, sizeof(msgBuf));
+ EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(), msgBuf,
+ sizeof(msgBuf)),
+ 0);
+ EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
}
+#endif // USING_LOGGER_DEFAULT
+#ifdef USING_LOGGER_DEFAULT // Do not retest pmsg functionality
#ifdef __ANDROID__
static const char __pmsg_file[] =
- "/data/william-shakespeare/MuchAdoAboutNothing.txt";
+ "/data/william-shakespeare/MuchAdoAboutNothing.txt";
#endif
TEST(liblog, __android_log_pmsg_file_write) {
#ifdef __ANDROID__
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
- LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
- EXPECT_LT(0, return__android_log_pmsg_file_write);
- if (return__android_log_pmsg_file_write == -ENOMEM) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver configured\n"
- );
- } else if (!return__android_log_pmsg_file_write) {
- fprintf(stderr, "Reboot, ensure file %s matches\n"
- "with liblog.__android_log_msg_file_read test\n",
- __pmsg_file);
- }
- bool pmsgActiveAfter__android_pmsg_file_write;
- bool logdwActiveAfter__android_pmsg_file_write;
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
- }
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_pmsg_file_write",
- "main"));
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
- bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
- EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
- }
- EXPECT_LT(0, __android_log_pmsg_file_write(
- LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
- }
+ __android_log_close();
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
+ int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
+ LOG_ID_CRASH, ANDROID_LOG_VERBOSE, __pmsg_file, max_payload_buf,
+ sizeof(max_payload_buf));
+ EXPECT_LT(0, return__android_log_pmsg_file_write);
+ if (return__android_log_pmsg_file_write == -ENOMEM) {
+ fprintf(stderr,
+ "Kernel does not have space allocated to pmsg pstore driver "
+ "configured\n");
+ } else if (!return__android_log_pmsg_file_write) {
+ fprintf(stderr,
+ "Reboot, ensure file %s matches\n"
+ "with liblog.__android_log_msg_file_read test\n",
+ __pmsg_file);
+ }
+ bool pmsgActiveAfter__android_pmsg_file_write;
+ bool logdwActiveAfter__android_pmsg_file_write;
+ if (getuid() == AID_ROOT) {
+ pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+ logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
+ EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+ }
+ EXPECT_LT(
+ 0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ "TEST__android_log_pmsg_file_write", "main"));
+ if (getuid() == AID_ROOT) {
+ bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
+ bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
+ EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
+ }
+ EXPECT_LT(0, __android_log_pmsg_file_write(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+ __pmsg_file, max_payload_buf,
+ sizeof(max_payload_buf)));
+ if (getuid() == AID_ROOT) {
+ pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+ logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+ EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
+ EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
+ }
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
#ifdef __ANDROID__
-ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
- const char *buf, size_t len, void *arg) {
- EXPECT_TRUE(NULL == arg);
- EXPECT_EQ(LOG_ID_CRASH, logId);
- EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
- EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
- EXPECT_EQ(len, sizeof(max_payload_buf));
- EXPECT_EQ(0, strcmp(max_payload_buf, buf));
+static ssize_t __pmsg_fn(log_id_t logId, char prio, const char* filename,
+ const char* buf, size_t len, void* arg) {
+ EXPECT_TRUE(NULL == arg);
+ EXPECT_EQ(LOG_ID_CRASH, logId);
+ EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
+ EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
+ EXPECT_EQ(len, sizeof(max_payload_buf));
+ EXPECT_EQ(0, strcmp(max_payload_buf, buf));
- ++signaled;
- if ((len != sizeof(max_payload_buf)) ||
- strcmp(max_payload_buf, buf)) {
- fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
- }
- return arg ||
- (LOG_ID_CRASH != logId) ||
- (ANDROID_LOG_VERBOSE != prio) ||
- !strstr(__pmsg_file, filename) ||
- (len != sizeof(max_payload_buf)) ||
- !!strcmp(max_payload_buf, buf) ? -ENOEXEC : 1;
+ ++signaled;
+ if ((len != sizeof(max_payload_buf)) || strcmp(max_payload_buf, buf)) {
+ fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
+ }
+ return arg || (LOG_ID_CRASH != logId) || (ANDROID_LOG_VERBOSE != prio) ||
+ !strstr(__pmsg_file, filename) ||
+ (len != sizeof(max_payload_buf)) ||
+ !!strcmp(max_payload_buf, buf)
+ ? -ENOEXEC
+ : 1;
}
#endif
TEST(liblog, __android_log_pmsg_file_read) {
#ifdef __ANDROID__
- signaled = 0;
+ signaled = 0;
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
+ __android_log_close();
+ if (getuid() == AID_ROOT) {
+ tested__android_log_close = true;
+ bool pmsgActiveAfter__android_log_close = isPmsgActive();
+ bool logdwActiveAfter__android_log_close = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+ EXPECT_FALSE(logdwActiveAfter__android_log_close);
+ } else if (!tested__android_log_close) {
+ fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+ }
- ssize_t ret = __android_log_pmsg_file_read(
- LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, __pmsg_fn, NULL);
+ ssize_t ret = __android_log_pmsg_file_read(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+ __pmsg_file, __pmsg_fn, NULL);
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
- bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
- EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
- }
+ if (getuid() == AID_ROOT) {
+ bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
+ bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
+ EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
+ EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+ }
- if (ret == -ENOENT) {
- fprintf(stderr,
+ if (ret == -ENOENT) {
+ fprintf(stderr,
"No pre-boot results of liblog.__android_log_mesg_file_write to "
"compare with,\n"
"false positive test result.\n");
- return;
- }
+ return;
+ }
- EXPECT_LT(0, ret);
- EXPECT_EQ(1U, signaled);
+ EXPECT_LT(0, ret);
+ EXPECT_EQ(1U, signaled);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOGGER_DEFAULT
+#ifdef USING_LOGGER_DEFAULT // Do not retest event mapping functionality
#ifdef __ANDROID__
// must be: '<needle:> 0 kB'
-static bool isZero(const std::string &content, std::string::size_type pos,
+static bool isZero(const std::string& content, std::string::size_type pos,
const char* needle) {
- std::string::size_type offset = content.find(needle, pos);
- return (offset != std::string::npos) &&
- ((offset = content.find_first_not_of(" \t", offset +
- strlen(needle))) != std::string::npos) &&
- (content.find_first_not_of("0", offset) != offset);
+ std::string::size_type offset = content.find(needle, pos);
+ return (offset != std::string::npos) &&
+ ((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
+ std::string::npos) &&
+ (content.find_first_not_of("0", offset) != offset);
}
// must not be: '<needle:> 0 kB'
-static bool isNotZero(const std::string &content, std::string::size_type pos,
+static bool isNotZero(const std::string& content, std::string::size_type pos,
const char* needle) {
- std::string::size_type offset = content.find(needle, pos);
- return (offset != std::string::npos) &&
- ((offset = content.find_first_not_of(" \t", offset +
- strlen(needle))) != std::string::npos) &&
- (content.find_first_not_of("123456789", offset) != offset);
+ std::string::size_type offset = content.find(needle, pos);
+ return (offset != std::string::npos) &&
+ ((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
+ std::string::npos) &&
+ (content.find_first_not_of("123456789", offset) != offset);
}
static void event_log_tags_test_smap(pid_t pid) {
- std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
+ std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
- std::string content;
- if (!android::base::ReadFileToString(filename, &content)) return;
+ std::string content;
+ if (!android::base::ReadFileToString(filename, &content)) return;
- bool shared_ok = false;
- bool private_ok = false;
- bool anonymous_ok = false;
- bool pass_ok = false;
+ bool shared_ok = false;
+ bool private_ok = false;
+ bool anonymous_ok = false;
+ bool pass_ok = false;
- static const char event_log_tags[] = "event-log-tags";
- std::string::size_type pos = 0;
- while ((pos = content.find(event_log_tags, pos)) != std::string::npos) {
- pos += strlen(event_log_tags);
+ static const char event_log_tags[] = "event-log-tags";
+ std::string::size_type pos = 0;
+ while ((pos = content.find(event_log_tags, pos)) != std::string::npos) {
+ pos += strlen(event_log_tags);
- // must not be: 'Shared_Clean: 0 kB'
- bool ok = isNotZero(content, pos, "Shared_Clean:") ||
- // If not /etc/event-log-tags, thus r/w, then half points
- // back for not 'Shared_Dirty: 0 kB'
- ((content.substr(pos - 5 - strlen(event_log_tags), 5) != "/etc/") &&
- isNotZero(content, pos, "Shared_Dirty:"));
- if (ok && !pass_ok) {
- shared_ok = true;
- } else if (!ok) {
- shared_ok = false;
- }
-
- // must be: 'Private_Dirty: 0 kB' and 'Private_Clean: 0 kB'
- ok = isZero(content, pos, "Private_Dirty:") ||
- isZero(content, pos, "Private_Clean:");
- if (ok && !pass_ok) {
- private_ok = true;
- } else if (!ok) {
- private_ok = false;
- }
-
- // must be: 'Anonymous: 0 kB'
- ok = isZero(content, pos, "Anonymous:");
- if (ok && !pass_ok) {
- anonymous_ok = true;
- } else if (!ok) {
- anonymous_ok = false;
- }
-
- pass_ok = true;
+ // must not be: 'Shared_Clean: 0 kB'
+ bool ok =
+ isNotZero(content, pos, "Shared_Clean:") ||
+ // If not /etc/event-log-tags, thus r/w, then half points
+ // back for not 'Shared_Dirty: 0 kB'
+ ((content.substr(pos - 5 - strlen(event_log_tags), 5) != "/etc/") &&
+ isNotZero(content, pos, "Shared_Dirty:"));
+ if (ok && !pass_ok) {
+ shared_ok = true;
+ } else if (!ok) {
+ shared_ok = false;
}
- content = "";
- if (!pass_ok) return;
- if (shared_ok && anonymous_ok && private_ok) return;
+ // must be: 'Private_Dirty: 0 kB' and 'Private_Clean: 0 kB'
+ ok = isZero(content, pos, "Private_Dirty:") ||
+ isZero(content, pos, "Private_Clean:");
+ if (ok && !pass_ok) {
+ private_ok = true;
+ } else if (!ok) {
+ private_ok = false;
+ }
- filename = android::base::StringPrintf("/proc/%d/comm", pid);
- android::base::ReadFileToString(filename, &content);
- content = android::base::StringPrintf("%d:%s",
- pid, content.substr(0, content.find("\n")).c_str());
+ // must be: 'Anonymous: 0 kB'
+ ok = isZero(content, pos, "Anonymous:");
+ if (ok && !pass_ok) {
+ anonymous_ok = true;
+ } else if (!ok) {
+ anonymous_ok = false;
+ }
- EXPECT_TRUE(IsOk(shared_ok, content));
- EXPECT_TRUE(IsOk(private_ok, content));
- EXPECT_TRUE(IsOk(anonymous_ok, content));
+ pass_ok = true;
+ }
+ content = "";
+
+ if (!pass_ok) return;
+ if (shared_ok && anonymous_ok && private_ok) return;
+
+ filename = android::base::StringPrintf("/proc/%d/comm", pid);
+ android::base::ReadFileToString(filename, &content);
+ content = android::base::StringPrintf(
+ "%d:%s", pid, content.substr(0, content.find("\n")).c_str());
+
+ EXPECT_TRUE(IsOk(shared_ok, content));
+ EXPECT_TRUE(IsOk(private_ok, content));
+ EXPECT_TRUE(IsOk(anonymous_ok, content));
}
-#endif
+#endif // __ANDROID__
TEST(liblog, event_log_tags) {
#ifdef __ANDROID__
- std::unique_ptr<DIR, int(*)(DIR*)> proc_dir(opendir("/proc"), closedir);
- ASSERT_FALSE(!proc_dir);
+ std::unique_ptr<DIR, int (*)(DIR*)> proc_dir(opendir("/proc"), closedir);
+ ASSERT_FALSE(!proc_dir);
- dirent* e;
- while ((e = readdir(proc_dir.get()))) {
- if (e->d_type != DT_DIR) continue;
- if (!isdigit(e->d_name[0])) continue;
- long long id = atoll(e->d_name);
- if (id <= 0) continue;
- pid_t pid = id;
- if (id != pid) continue;
- event_log_tags_test_smap(pid);
- }
+ dirent* e;
+ while ((e = readdir(proc_dir.get()))) {
+ if (e->d_type != DT_DIR) continue;
+ if (!isdigit(e->d_name[0])) continue;
+ long long id = atoll(e->d_name);
+ if (id <= 0) continue;
+ pid_t pid = id;
+ if (id != pid) continue;
+ event_log_tags_test_smap(pid);
+ }
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOGGER_DEFAULT
+#ifdef USING_LOGGER_DEFAULT // Do not retest ratelimit
TEST(liblog, __android_log_ratelimit) {
- time_t state = 0;
+ time_t state = 0;
- errno = 42;
- // Prime
- __android_log_ratelimit(3, &state);
- EXPECT_EQ(errno, 42);
- // Check
- EXPECT_FALSE(__android_log_ratelimit(3, &state));
- sleep(1);
- EXPECT_FALSE(__android_log_ratelimit(3, &state));
- sleep(4);
- EXPECT_TRUE(__android_log_ratelimit(3, &state));
- sleep(5);
- EXPECT_TRUE(__android_log_ratelimit(3, &state));
+ errno = 42;
+ // Prime
+ __android_log_ratelimit(3, &state);
+ EXPECT_EQ(errno, 42);
+ // Check
+ EXPECT_FALSE(__android_log_ratelimit(3, &state));
+ sleep(1);
+ EXPECT_FALSE(__android_log_ratelimit(3, &state));
+ sleep(4);
+ EXPECT_TRUE(__android_log_ratelimit(3, &state));
+ sleep(5);
+ EXPECT_TRUE(__android_log_ratelimit(3, &state));
- // API checks
- IF_ALOG_RATELIMIT_LOCAL(3, &state) {
- EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)");
- }
+ // API checks
+ IF_ALOG_RATELIMIT_LOCAL(3, &state) {
+ EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)");
+ }
- IF_ALOG_RATELIMIT() {
- ;
- } else {
- EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()");
- }
- IF_ALOG_RATELIMIT() {
- EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()");
- }
- // Do not test default seconds, to allow liblog to tune freely
+ IF_ALOG_RATELIMIT() {
+ ;
+ }
+ else {
+ EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()");
+ }
+ IF_ALOG_RATELIMIT() {
+ EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()");
+ }
+ // Do not test default seconds, to allow liblog to tune freely
}
+#endif // USING_LOGGER_DEFAULT
+#ifdef USING_LOGGER_DEFAULT // Do not retest event mapping functionality
TEST(liblog, android_lookupEventTagNum) {
#ifdef __ANDROID__
- EventTagMap* map = android_openEventTagMap(NULL);
- EXPECT_TRUE(NULL != map);
- std::string Name = android::base::StringPrintf("a%d", getpid());
- int tag = android_lookupEventTagNum(map, Name.c_str(), "(new|1)", ANDROID_LOG_UNKNOWN);
- android_closeEventTagMap(map);
- if (tag == -1) system("tail -3 /dev/event-log-tags >&2");
- EXPECT_NE(-1, tag);
- EXPECT_NE(0, tag);
- EXPECT_GT(UINT32_MAX, (unsigned)tag);
+ EventTagMap* map = android_openEventTagMap(NULL);
+ EXPECT_TRUE(NULL != map);
+ std::string Name = android::base::StringPrintf("a%d", getpid());
+ int tag = android_lookupEventTagNum(map, Name.c_str(), "(new|1)",
+ ANDROID_LOG_UNKNOWN);
+ android_closeEventTagMap(map);
+ if (tag == -1) system("tail -3 /dev/event-log-tags >&2");
+ EXPECT_NE(-1, tag);
+ EXPECT_NE(0, tag);
+ EXPECT_GT(UINT32_MAX, (unsigned)tag);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
+#endif // USING_LOGGER_DEFAULT
diff --git a/liblog/tests/liblog_test_default.cpp b/liblog/tests/liblog_test_default.cpp
new file mode 100644
index 0000000..cbd0d25
--- /dev/null
+++ b/liblog/tests/liblog_test_default.cpp
@@ -0,0 +1,5 @@
+#ifdef __ANDROID__
+#include <log/log_transport.h>
+#define TEST_PREFIX android_set_log_transport(LOGGER_DEFAULT);
+#endif
+#include "liblog_test.cpp"
diff --git a/liblog/tests/liblog_test_local.cpp b/liblog/tests/liblog_test_local.cpp
new file mode 100644
index 0000000..9d7b3d7
--- /dev/null
+++ b/liblog/tests/liblog_test_local.cpp
@@ -0,0 +1,4 @@
+#include <log/log_transport.h>
+#define liblog liblog_local
+#define TEST_PREFIX android_set_log_transport(LOGGER_LOCAL);
+#include "liblog_test.cpp"
diff --git a/liblog/tests/liblog_test_stderr.cpp b/liblog/tests/liblog_test_stderr.cpp
new file mode 100644
index 0000000..f9e4e1f
--- /dev/null
+++ b/liblog/tests/liblog_test_stderr.cpp
@@ -0,0 +1,5 @@
+#include <log/log_transport.h>
+#define liblog liblog_stderr
+#define TEST_PREFIX android_set_log_transport(LOGGER_STDERR);
+#define USING_LOGGER_STDERR
+#include "liblog_test.cpp"
diff --git a/liblog/tests/liblog_test_stderr_local.cpp b/liblog/tests/liblog_test_stderr_local.cpp
new file mode 100644
index 0000000..21406ca
--- /dev/null
+++ b/liblog/tests/liblog_test_stderr_local.cpp
@@ -0,0 +1,4 @@
+#include <log/log_transport.h>
+#define liblog liblog_stderr_local
+#define TEST_PREFIX android_set_log_transport(LOGGER_LOCAL | LOGGER_STDERR);
+#include "liblog_test.cpp"
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
index 3241534..c56fa8b 100644
--- a/liblog/tests/log_id_test.cpp
+++ b/liblog/tests/log_id_test.cpp
@@ -27,99 +27,76 @@
// include file API purity. We do however want to allow the _option_ that
// log/log_id.h could include this file, or related content, in the future.
#ifndef __android_LogPriority_defined
-# define ANDROID_LOG_INFO 4
+#define ANDROID_LOG_INFO 4
#endif
TEST(liblog, log_id) {
-#ifdef __ANDROID__
- int count = 0;
+ int count = 0;
- for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- const char *name = android_log_id_to_name(id);
- if (id != android_name_to_log_id(name)) {
- continue;
- }
- ++count;
- fprintf(stderr, "log buffer %s\r", name);
+ for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ log_id_t id = static_cast<log_id_t>(i);
+ const char* name = android_log_id_to_name(id);
+ if (id != android_name_to_log_id(name)) {
+ continue;
}
- ASSERT_EQ(LOG_ID_MAX, count);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ ++count;
+ fprintf(stderr, "log buffer %s\r", name);
+ }
+ ASSERT_EQ(LOG_ID_MAX, count);
}
TEST(liblog, __android_log_buf_print) {
-#ifdef __ANDROID__
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print",
- "radio"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print",
- "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print",
- "main"));
- usleep(1000);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_print", "radio"));
+ usleep(1000);
+ EXPECT_LT(0,
+ __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_print", "system"));
+ usleep(1000);
+ EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_print", "main"));
+ usleep(1000);
}
TEST(liblog, __android_log_buf_write) {
-#ifdef __ANDROID__
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write",
- "radio"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write",
- "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write",
- "main"));
- usleep(1000);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_write", "radio"));
+ usleep(1000);
+ EXPECT_LT(0,
+ __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_write", "system"));
+ usleep(1000);
+ EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ "TEST__android_log_buf_write", "main"));
+ usleep(1000);
}
-#ifdef __ANDROID__
-static void* ConcurrentPrintFn(void *arg) {
- int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_print", "Concurrent %" PRIuPTR,
- reinterpret_cast<uintptr_t>(arg));
- return reinterpret_cast<void*>(ret);
+static void* ConcurrentPrintFn(void* arg) {
+ int ret = __android_log_buf_print(
+ LOG_ID_MAIN, ANDROID_LOG_INFO, "TEST__android_log_print",
+ "Concurrent %" PRIuPTR, reinterpret_cast<uintptr_t>(arg));
+ return reinterpret_cast<void*>(ret);
}
-#endif
#define NUM_CONCURRENT 64
-#define _concurrent_name(a,n) a##__concurrent##n
-#define concurrent_name(a,n) _concurrent_name(a,n)
+#define _concurrent_name(a, n) a##__concurrent##n
+#define concurrent_name(a, n) _concurrent_name(a, n)
TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
-#ifdef __ANDROID__
- pthread_t t[NUM_CONCURRENT];
- int i;
- for (i=0; i < NUM_CONCURRENT; i++) {
- ASSERT_EQ(0, pthread_create(&t[i], NULL,
- ConcurrentPrintFn,
- reinterpret_cast<void *>(i)));
+ pthread_t t[NUM_CONCURRENT];
+ int i;
+ for (i = 0; i < NUM_CONCURRENT; i++) {
+ ASSERT_EQ(0, pthread_create(&t[i], NULL, ConcurrentPrintFn,
+ reinterpret_cast<void*>(i)));
+ }
+ int ret = 0;
+ for (i = 0; i < NUM_CONCURRENT; i++) {
+ void* result;
+ ASSERT_EQ(0, pthread_join(t[i], &result));
+ int this_result = reinterpret_cast<uintptr_t>(result);
+ if ((0 == ret) && (0 != this_result)) {
+ ret = this_result;
}
- int ret = 0;
- for (i=0; i < NUM_CONCURRENT; i++) {
- void* result;
- ASSERT_EQ(0, pthread_join(t[i], &result));
- int this_result = reinterpret_cast<uintptr_t>(result);
- if ((0 == ret) && (0 != this_result)) {
- ret = this_result;
- }
- }
- ASSERT_LT(0, ret);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ }
+ ASSERT_LT(0, ret);
}
diff --git a/liblog/tests/log_radio_test.cpp b/liblog/tests/log_radio_test.cpp
index 591748a..f202c67 100644
--- a/liblog/tests/log_radio_test.cpp
+++ b/liblog/tests/log_radio_test.cpp
@@ -27,91 +27,93 @@
#include <log/log_radio.h>
TEST(liblog, RLOG) {
+ static const char content[] = "log_radio.h";
+ static const char content_false[] = "log_radio.h false";
+
+// ratelimit content to 10/s to keep away from spam filters
+// do not send identical content together to keep away from spam filters
+
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGV"
+ RLOGV(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGD"
+ RLOGD(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGI"
+ RLOGI(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGW"
+ RLOGW(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGE"
+ RLOGE(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGV"
+ RLOGV_IF(true, content);
+ usleep(100000);
+ RLOGV_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGD"
+ RLOGD_IF(true, content);
+ usleep(100000);
+ RLOGD_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGI"
+ RLOGI_IF(true, content);
+ usleep(100000);
+ RLOGI_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGW"
+ RLOGW_IF(true, content);
+ usleep(100000);
+ RLOGW_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__RLOGE"
+ RLOGE_IF(true, content);
+ usleep(100000);
+ RLOGE_IF(false, content_false);
+
#ifdef __ANDROID__
- static const char content[] = "log_radio.h";
- static const char content_false[] = "log_radio.h false";
+ // give time for content to long-path through logger
+ sleep(1);
- // ratelimit content to 10/s to keep away from spam filters
- // do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV_IF(true, content);
- usleep(100000);
- RLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD_IF(true, content);
- usleep(100000);
- RLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI_IF(true, content);
- usleep(100000);
- RLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW_IF(true, content);
- usleep(100000);
- RLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE_IF(true, content);
- usleep(100000);
- RLOGE_IF(false, content_false);
-
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b radio --pid=%u -d -s"
- " TEST__RLOGV TEST__RLOGD TEST__RLOGI TEST__RLOGW TEST__RLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "r");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos; ++pos) {
- ++count;
- }
- for (size_t pos = 0; (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
+ std::string buf = android::base::StringPrintf(
+ "logcat -b radio --pid=%u -d -s"
+ " TEST__RLOGV TEST__RLOGD TEST__RLOGI TEST__RLOGW TEST__RLOGE",
+ (unsigned)getpid());
+ FILE* fp = popen(buf.c_str(), "r");
+ int count = 0;
+ int count_false = 0;
+ if (fp) {
+ if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
+ pclose(fp);
+ for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
+ ++pos) {
+ ++count;
}
- EXPECT_EQ(0, count_false);
+ for (size_t pos = 0;
+ (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
+ ++count_false;
+ }
+ }
+ EXPECT_EQ(0, count_false);
#if LOG_NDEBUG
- ASSERT_EQ(8, count);
+ ASSERT_EQ(8, count);
#else
- ASSERT_EQ(10, count);
+ ASSERT_EQ(10, count);
#endif
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
#endif
}
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 2e02407..a63ab8e 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -20,8 +20,8 @@
#include <string>
-#include <android/log.h> // minimal logging API
#include <android-base/stringprintf.h>
+#include <android/log.h> // minimal logging API
#include <gtest/gtest.h>
// Test the APIs in this standalone include file
#include <log/log_read.h>
@@ -29,90 +29,90 @@
TEST(liblog, __android_log_write__android_logger_list_read) {
#ifdef __ANDROID__
- pid_t pid = getpid();
+ pid_t pid = getpid();
- struct logger_list *logger_list;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ struct logger_list* logger_list;
+ ASSERT_TRUE(
+ NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- std::string buf = android::base::StringPrintf("pid=%u ts=%ld.%09ld",
- pid, ts.tv_sec, ts.tv_nsec);
- static const char tag[] = "liblog.__android_log_write__android_logger_list_read";
- static const char prio = ANDROID_LOG_DEBUG;
- ASSERT_LT(0, __android_log_write(prio, tag, buf.c_str()));
- usleep(1000000);
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ std::string buf = android::base::StringPrintf("pid=%u ts=%ld.%09ld", pid,
+ ts.tv_sec, ts.tv_nsec);
+ static const char tag[] =
+ "liblog.__android_log_write__android_logger_list_read";
+ static const char prio = ANDROID_LOG_DEBUG;
+ ASSERT_LT(0, __android_log_write(prio, tag, buf.c_str()));
+ usleep(1000000);
- buf = std::string(&prio, sizeof(prio)) +
- tag +
- std::string("", 1) +
- buf +
- std::string("", 1);
+ buf = std::string(&prio, sizeof(prio)) + tag + std::string("", 1) + buf +
+ std::string("", 1);
- int count = 0;
+ int count = 0;
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
- EXPECT_EQ(log_msg.entry.pid, pid);
- // There may be a future where we leak "liblog" tagged LOG_ID_EVENT
- // binary messages through so that logger losses can be correlated?
- EXPECT_EQ(log_msg.id(), LOG_ID_MAIN);
+ EXPECT_EQ(log_msg.entry.pid, pid);
+ // There may be a future where we leak "liblog" tagged LOG_ID_EVENT
+ // binary messages through so that logger losses can be correlated?
+ EXPECT_EQ(log_msg.id(), LOG_ID_MAIN);
- if (log_msg.entry.len != buf.length()) continue;
+ if (log_msg.entry.len != buf.length()) continue;
- if (buf != std::string(log_msg.msg(), log_msg.entry.len)) continue;
+ if (buf != std::string(log_msg.msg(), log_msg.entry.len)) continue;
- ++count;
- }
- android_logger_list_close(logger_list);
+ ++count;
+ }
+ android_logger_list_close(logger_list);
- EXPECT_EQ(1, count);
+ EXPECT_EQ(1, count);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
TEST(liblog, android_logger_get_) {
#ifdef __ANDROID__
- // This test assumes the log buffers are filled with noise from
- // normal operations. It will fail if done immediately after a
- // logcat -c.
- struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
+ // This test assumes the log buffers are filled with noise from
+ // normal operations. It will fail if done immediately after a
+ // logcat -c.
+ struct logger_list* logger_list =
+ android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
- for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- const char *name = android_log_id_to_name(id);
- if (id != android_name_to_log_id(name)) {
- continue;
- }
- fprintf(stderr, "log buffer %s\r", name);
- struct logger * logger;
- EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
- EXPECT_EQ(id, android_logger_get_id(logger));
- ssize_t get_log_size = android_logger_get_log_size(logger);
- /* security buffer is allowed to be denied */
- if (strcmp("security", name)) {
- EXPECT_LT(0, get_log_size);
- /* crash buffer is allowed to be empty, that is actually healthy! */
- EXPECT_LE((strcmp("crash", name)) != 0,
- android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_NE(0, get_log_size);
- if (get_log_size < 0) {
- EXPECT_GT(0, android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_LE(0, android_logger_get_log_readable_size(logger));
- }
- }
- EXPECT_LT(0, android_logger_get_log_version(logger));
+ for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ log_id_t id = static_cast<log_id_t>(i);
+ const char* name = android_log_id_to_name(id);
+ if (id != android_name_to_log_id(name)) {
+ continue;
}
+ fprintf(stderr, "log buffer %s\r", name);
+ struct logger* logger;
+ EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
+ EXPECT_EQ(id, android_logger_get_id(logger));
+ ssize_t get_log_size = android_logger_get_log_size(logger);
+ /* security buffer is allowed to be denied */
+ if (strcmp("security", name)) {
+ EXPECT_LT(0, get_log_size);
+ /* crash buffer is allowed to be empty, that is actually healthy! */
+ EXPECT_LE((strcmp("crash", name)) != 0,
+ android_logger_get_log_readable_size(logger));
+ } else {
+ EXPECT_NE(0, get_log_size);
+ if (get_log_size < 0) {
+ EXPECT_GT(0, android_logger_get_log_readable_size(logger));
+ } else {
+ EXPECT_LE(0, android_logger_get_log_readable_size(logger));
+ }
+ }
+ EXPECT_LT(0, android_logger_get_log_version(logger));
+ }
- android_logger_list_close(logger_list);
+ android_logger_list_close(logger_list);
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-
diff --git a/liblog/tests/log_system_test.cpp b/liblog/tests/log_system_test.cpp
index b62832e..0656c0b 100644
--- a/liblog/tests/log_system_test.cpp
+++ b/liblog/tests/log_system_test.cpp
@@ -27,91 +27,93 @@
#include <log/log_system.h>
TEST(liblog, SLOG) {
+ static const char content[] = "log_system.h";
+ static const char content_false[] = "log_system.h false";
+
+// ratelimit content to 10/s to keep away from spam filters
+// do not send identical content together to keep away from spam filters
+
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGV"
+ SLOGV(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGD"
+ SLOGD(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGI"
+ SLOGI(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGW"
+ SLOGW(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGE"
+ SLOGE(content);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGV"
+ SLOGV_IF(true, content);
+ usleep(100000);
+ SLOGV_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGD"
+ SLOGD_IF(true, content);
+ usleep(100000);
+ SLOGD_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGI"
+ SLOGI_IF(true, content);
+ usleep(100000);
+ SLOGI_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGW"
+ SLOGW_IF(true, content);
+ usleep(100000);
+ SLOGW_IF(false, content_false);
+ usleep(100000);
+#undef LOG_TAG
+#define LOG_TAG "TEST__SLOGE"
+ SLOGE_IF(true, content);
+ usleep(100000);
+ SLOGE_IF(false, content_false);
+
#ifdef __ANDROID__
- static const char content[] = "log_system.h";
- static const char content_false[] = "log_system.h false";
+ // give time for content to long-path through logger
+ sleep(1);
- // ratelimit content to 10/s to keep away from spam filters
- // do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV_IF(true, content);
- usleep(100000);
- SLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD_IF(true, content);
- usleep(100000);
- SLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI_IF(true, content);
- usleep(100000);
- SLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW_IF(true, content);
- usleep(100000);
- SLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE_IF(true, content);
- usleep(100000);
- SLOGE_IF(false, content_false);
-
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b system --pid=%u -d -s"
- " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "r");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos; ++pos) {
- ++count;
- }
- for (size_t pos = 0; (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
+ std::string buf = android::base::StringPrintf(
+ "logcat -b system --pid=%u -d -s"
+ " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
+ (unsigned)getpid());
+ FILE* fp = popen(buf.c_str(), "r");
+ int count = 0;
+ int count_false = 0;
+ if (fp) {
+ if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
+ pclose(fp);
+ for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
+ ++pos) {
+ ++count;
}
- EXPECT_EQ(0, count_false);
+ for (size_t pos = 0;
+ (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
+ ++count_false;
+ }
+ }
+ EXPECT_EQ(0, count_false);
#if LOG_NDEBUG
- ASSERT_EQ(8, count);
+ ASSERT_EQ(8, count);
#else
- ASSERT_EQ(10, count);
+ ASSERT_EQ(10, count);
#endif
#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
+ GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
#endif
}
diff --git a/liblog/tests/log_time_test.cpp b/liblog/tests/log_time_test.cpp
index f2601b6..0ae1d18 100644
--- a/liblog/tests/log_time_test.cpp
+++ b/liblog/tests/log_time_test.cpp
@@ -21,23 +21,17 @@
#include <log/log_time.h>
TEST(liblog, log_time) {
-#ifdef __ANDROID__
-
#ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
- log_time(CLOCK_MONOTONIC);
+ log_time(CLOCK_MONOTONIC);
- EXPECT_EQ(log_time, log_time::EPOCH);
+ EXPECT_EQ(log_time, log_time::EPOCH);
#endif
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- log_time tl(ts);
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ log_time tl(ts);
- EXPECT_EQ(tl, ts);
- EXPECT_GE(tl, ts);
- EXPECT_LE(tl, ts);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+ EXPECT_EQ(tl, ts);
+ EXPECT_GE(tl, ts);
+ EXPECT_LE(tl, ts);
}
diff --git a/liblog/uio.c b/liblog/uio.c
index ac0558f..e127202 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -22,58 +22,52 @@
#include "log_portability.h"
-LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count)
-{
- int total = 0;
+LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec* vecs, int count) {
+ int total = 0;
- for ( ; count > 0; count--, vecs++ ) {
- char* buf = vecs->iov_base;
- int len = vecs->iov_len;
+ for (; count > 0; count--, vecs++) {
+ char* buf = vecs->iov_base;
+ int len = vecs->iov_len;
- while (len > 0) {
- int ret = read( fd, buf, len );
- if (ret < 0) {
- if (total == 0)
- total = -1;
- goto Exit;
- }
- if (ret == 0)
- goto Exit;
+ while (len > 0) {
+ int ret = read(fd, buf, len);
+ if (ret < 0) {
+ if (total == 0) total = -1;
+ goto Exit;
+ }
+ if (ret == 0) goto Exit;
- total += ret;
- buf += ret;
- len -= ret;
- }
+ total += ret;
+ buf += ret;
+ len -= ret;
}
+ }
Exit:
- return total;
+ return total;
}
-LIBLOG_ABI_PUBLIC int writev(int fd, const struct iovec *vecs, int count)
-{
- int total = 0;
+LIBLOG_ABI_PUBLIC int writev(int fd, const struct iovec* vecs, int count) {
+ int total = 0;
- for ( ; count > 0; count--, vecs++ ) {
- const char* buf = vecs->iov_base;
- int len = vecs->iov_len;
+ for (; count > 0; count--, vecs++) {
+ const char* buf = vecs->iov_base;
+ int len = vecs->iov_len;
- while (len > 0) {
- int ret = write( fd, buf, len );
- if (ret < 0) {
- if (total == 0)
- total = -1;
- goto Exit;
- }
- if (ret == 0)
- goto Exit;
+ while (len > 0) {
+ int ret = write(fd, buf, len);
+ if (ret < 0) {
+ if (total == 0) total = -1;
+ goto Exit;
+ }
+ if (ret == 0) goto Exit;
- total += ret;
- buf += ret;
- len -= ret;
- }
+ total += ret;
+ buf += ret;
+ len -= ret;
}
+ }
Exit:
- return total;
+ return total;
}
#endif
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
new file mode 100644
index 0000000..75eab66
--- /dev/null
+++ b/libmetricslogger/Android.bp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+metricslogger_lib_src_files = [
+ "metrics_logger.cpp",
+]
+
+cc_defaults {
+ name: "metricslogger_defaults",
+
+ clang: true,
+ host_supported: true,
+
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+ shared_libs: ["liblog"],
+ whole_static_libs: ["libgtest_prod"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+
+ // 524291 corresponds to sysui_histogram, from
+ // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
+ "-DHISTOGRAM_LOG_TAG=524291",
+ ],
+}
+
+// metricslogger shared library
+// -----------------------------------------------------------------------------
+cc_library_shared {
+ name: "libmetricslogger",
+ srcs: metricslogger_lib_src_files,
+ defaults: ["metricslogger_defaults"],
+}
+
+// metricslogger shared library, debug
+// -----------------------------------------------------------------------------
+cc_library_shared {
+ name: "libmetricslogger_debug",
+ srcs: metricslogger_lib_src_files,
+ defaults: ["metricslogger_defaults"],
+
+ target: {
+ host: {
+ cflags: ["-UNDEBUG"],
+ },
+ },
+}
+
+// Native tests
+// -----------------------------------------------------------------------------
+cc_test {
+ name: "metricslogger_tests",
+ defaults: ["metricslogger_defaults"],
+ shared_libs: [
+ "libbase",
+ "libmetricslogger_debug",
+ ],
+ static_libs: ["libBionicGtestMain"],
+ srcs: [
+ "metrics_logger_test.cpp",
+ ],
+}
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
similarity index 72%
rename from bootstat/histogram_logger.h
rename to libmetricslogger/include/metricslogger/metrics_logger.h
index 60c7776..d30e56c 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -17,10 +17,12 @@
#include <cstdint>
#include <string>
-namespace bootstat {
+namespace android {
+namespace metricslogger {
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
+// Logs a Tron histogram metric named |event| containing |data| to the Tron log
+// buffer.
void LogHistogram(const std::string& event, int32_t data);
-} // namespace bootstat
\ No newline at end of file
+} // namespace metricslogger
+} // namespace android
diff --git a/bootstat/histogram_logger.cpp b/libmetricslogger/metrics_logger.cpp
similarity index 76%
rename from bootstat/histogram_logger.cpp
rename to libmetricslogger/metrics_logger.cpp
index 73f3295..f8e0174 100644
--- a/bootstat/histogram_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#include "histogram_logger.h"
+#include "metricslogger/metrics_logger.h"
#include <cstdlib>
-#include <android-base/logging.h>
#include <log/log_event_list.h>
-namespace bootstat {
+namespace android {
+namespace metricslogger {
void LogHistogram(const std::string& event, int32_t data) {
- LOG(INFO) << "Logging histogram: " << event << " " << data;
android_log_event_list log(HISTOGRAM_LOG_TAG);
log << event << data << LOG_ID_EVENTS;
}
-} // namespace bootstat
+} // namespace metricslogger
+} // namespace android
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/metrics_logger_test.cpp
similarity index 70%
copy from bootstat/histogram_logger.h
copy to libmetricslogger/metrics_logger_test.cpp
index 60c7776..5a30ad7 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/metrics_logger_test.cpp
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-#include <cstdint>
-#include <string>
+#include "metricslogger/metrics_logger.h"
-namespace bootstat {
+#include <gtest/gtest.h>
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-} // namespace bootstat
\ No newline at end of file
+TEST(MetricsLoggerTest, AddSingleBootEvent) {
+ android::metricslogger::LogHistogram("test_event", 42);
+ // TODO(jhawkins): Verify the EventLog is updated.
+}
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 02e7075..ac64f71 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -22,16 +22,15 @@
__BEGIN_DECLS
/*
- * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
- * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- * The libraries in this list should be loaded prior to this call.
+ * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
+ * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
*
- * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * The library_search_path is the search path for anonymous namespace. The anonymous namespace
* is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
* for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
*/
-extern bool android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path);
enum {
@@ -87,6 +86,26 @@
android_namespace_t* parent);
/*
+ * Creates a link between namespaces. Every link has list of sonames of
+ * shared libraries. These are the libraries which are accessible from
+ * namespace 'from' but loaded within namespace 'to' context.
+ * When to namespace is nullptr this function establishes a link between
+ * 'from' namespace and the default namespace.
+ *
+ * The lookup order of the libraries in namespaces with links is following:
+ * 1. Look inside current namespace using 'this' namespace search path.
+ * 2. Look in linked namespaces
+ * 2.1. Perform soname check - if library soname is not in the list of shared
+ * libraries sonames skip this link, otherwise
+ * 2.2. Search library using linked namespace search path. Note that this
+ * step will not go deeper into linked namespaces for this library but
+ * will do so for DT_NEEDED libraries.
+ */
+extern bool android_link_namespaces(android_namespace_t* from,
+ android_namespace_t* to,
+ const char* shared_libs_sonames);
+
+/*
* Get the default library search path.
* The path will be copied into buffer, which must have space for at least
* buffer_size chars. Elements are separated with ':', and the path will always
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 2f23c2c..74f2f1d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -165,6 +165,11 @@
return false;
}
+ if (!android_link_namespaces(ns, nullptr, public_libraries_.c_str())) {
+ *error_msg = dlerror();
+ return false;
+ }
+
native_loader_ns = NativeLoaderNamespace(ns);
} else {
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
@@ -310,8 +315,8 @@
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- initialized_ = android_init_namespaces(public_libraries_.c_str(),
- is_native_bridge ? nullptr : library_path);
+ initialized_ = android_init_anonymous_namespace(public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
if (!initialized_) {
*error_msg = dlerror();
return false;
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
deleted file mode 100644
index b8c6428..0000000
--- a/libprocinfo/.clang-format
+++ /dev/null
@@ -1,14 +0,0 @@
-BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
-
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-IndentWidth: 2
-PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
-PenaltyExcessCharacter: 32
-
-Cpp11BracedListStyle: false
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libprocinfo/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 8e17f1b..c13ffe9 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -35,6 +35,9 @@
darwin: {
enabled: false,
},
+ linux_bionic: {
+ enabled: true,
+ },
windows: {
enabled: false,
},
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 330d6cb..584e5a2 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -17,6 +17,7 @@
LOCAL_CFLAGS := -Werror
LOCAL_SHARED_LIBRARIES := \
+ libbase \
libcutils \
liblog \
libnl
@@ -24,4 +25,3 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := system/core/libsysutils/include
include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index fef801a..79bc888 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -561,10 +561,12 @@
static const char*
has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
{
- if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
+ if ((end - str) >= (ptrdiff_t)prefixlen &&
+ (prefixlen == 0 || !memcmp(str, prefix, prefixlen))) {
return str + prefixlen;
- else
+ } else {
return NULL;
+ }
}
/* Same as strlen(x) for constant string literals ONLY */
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 13bac09..c7aa1f7 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -19,34 +19,23 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <sys/system_properties.h>
#include <unistd.h>
-#include <cutils/properties.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <log/log.h>
#include <sysutils/ServiceManager.h>
ServiceManager::ServiceManager() {
}
-/* The service name should not exceed SERVICE_NAME_MAX to avoid
- * some weird things. This is due to the fact that:
- *
- * - Starting a service is done by writing its name to the "ctl.start"
- * system property. This triggers the init daemon to actually start
- * the service for us.
- *
- * - Stopping the service is done by writing its name to "ctl.stop"
- * in a similar way.
- *
- * - Reading the status of a service is done by reading the property
- * named "init.svc.<name>"
- *
- * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
- * the service by writing to ctl.start/stop, but you won't be able to
- * read its state due to the truncation of "init.svc.<name>" into a
- * zero-terminated buffer of PROPERTY_KEY_MAX characters.
- */
-#define SERVICE_NAME_MAX (PROPERTY_KEY_MAX-10)
+// The length of a service name should not exceed SERVICE_NAME_MAX. Starting
+// a service is done by writing its name to the "ctl.start" system property
+// and stopping a service is done by writing its name to "ctl.stop". If a
+// service name is too long to fit in a property, you won't be able to start
+// or stop it.
+static constexpr size_t SERVICE_NAME_MAX = PROP_VALUE_MAX;
/* The maximum amount of time to wait for a service to start or stop,
* in micro-seconds (really an approximation) */
@@ -61,13 +50,14 @@
SLOGE("Service name '%s' is too long", name);
return 0;
}
+
if (isRunning(name)) {
SLOGW("Service '%s' is already running", name);
return 0;
}
SLOGD("Starting service '%s'", name);
- property_set("ctl.start", name);
+ android::base::SetProperty("ctl.start", name);
int count = SLEEP_MAX_USEC;
while(count > 0) {
@@ -90,13 +80,14 @@
SLOGE("Service name '%s' is too long", name);
return 0;
}
+
if (!isRunning(name)) {
SLOGW("Service '%s' is already stopped", name);
return 0;
}
SLOGD("Stopping service '%s'", name);
- property_set("ctl.stop", name);
+ android::base::SetProperty("ctl.stop", name);
int count = SLEEP_MAX_USEC;
while(count > 0) {
@@ -116,19 +107,6 @@
}
bool ServiceManager::isRunning(const char *name) {
- char propVal[PROPERTY_VALUE_MAX];
- char propName[PROPERTY_KEY_MAX];
- int ret;
-
- ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
- if (ret > (int)sizeof(propName)-1) {
- SLOGD("Service name '%s' is too long", name);
- return false;
- }
-
- if (property_get(propName, propVal, NULL)) {
- if (!strcmp(propVal, "running"))
- return true;
- }
- return false;
+ std::string property_name = android::base::StringPrintf("init.svc.%s", name);
+ return (android::base::GetProperty(property_name, "") == "running");
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 0c777b1..2b98fef 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -17,9 +17,12 @@
host_supported: true,
export_include_dirs: ["include"],
target: {
+ linux_bionic: {
+ enabled: true,
+ },
windows: {
- enabled: true,
- },
+ enabled: true,
+ },
},
}
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 1f8395b..4252ba6 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -22,7 +22,6 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <typeinfo>
#include <unistd.h>
#include <utils/RefBase.h>
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index 25a53aa..3019a21 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -41,6 +41,11 @@
* call wait(), then either re-wait() if things aren't quite what you want,
* or unlock the mutex and continue. All threads calling wait() must
* use the same mutex for a given Condition.
+ *
+ * On Android and Apple platforms, these are implemented as a simple wrapper
+ * around pthread condition variables. Care must be taken to abide by
+ * the pthreads semantics, in particular, a boolean predicate must
+ * be re-evaluated after a wake-up, as spurious wake-ups may happen.
*/
class Condition {
public:
@@ -58,10 +63,11 @@
explicit Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
+ // Note that spurious wake-ups may happen.
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
- // Signal the condition variable, allowing exactly one thread to continue.
+ // Signal the condition variable, allowing one thread to continue.
void signal();
// Signal the condition variable, allowing one or all threads to continue.
void signal(WakeUpType type) {
@@ -86,19 +92,22 @@
#if !defined(_WIN32)
-inline Condition::Condition() {
- pthread_cond_init(&mCond, NULL);
+inline Condition::Condition() : Condition(PRIVATE) {
}
inline Condition::Condition(int type) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+#if defined(__linux__)
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+#endif
+
if (type == SHARED) {
- pthread_condattr_t attr;
- pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
- pthread_cond_init(&mCond, &attr);
- pthread_condattr_destroy(&attr);
- } else {
- pthread_cond_init(&mCond, NULL);
}
+
+ pthread_cond_init(&mCond, &attr);
+ pthread_condattr_destroy(&attr);
+
}
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
@@ -109,7 +118,7 @@
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
struct timespec ts;
#if defined(__linux__)
- clock_gettime(CLOCK_REALTIME, &ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
#else // __APPLE__
// Apple doesn't support POSIX clocks.
struct timeval t;
@@ -139,17 +148,6 @@
return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
}
inline void Condition::signal() {
- /*
- * POSIX says pthread_cond_signal wakes up "one or more" waiting threads.
- * However bionic follows the glibc guarantee which wakes up "exactly one"
- * waiting thread.
- *
- * man 3 pthread_cond_signal
- * pthread_cond_signal restarts one of the threads that are waiting on
- * the condition variable cond. If no threads are waiting on cond,
- * nothing happens. If several threads are waiting on cond, exactly one
- * is restarted, but it is not specified which.
- */
pthread_cond_signal(&mCond);
}
inline void Condition::broadcast() {
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index 7cc4c18..a989a47 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -26,6 +26,16 @@
namespace android {
// ---------------------------------------------------------------------------
+// Singleton<TYPE> may be used in multiple libraries, only one of which should
+// define the static member variables using ANDROID_SINGLETON_STATIC_INSTANCE.
+// Turn off -Wundefined-var-template so other users don't get:
+// instantiation of variable 'android::Singleton<TYPE>::sLock' required here,
+// but no definition is available
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-var-template"
+#endif
+
template <typename TYPE>
class ANDROID_API Singleton
{
@@ -56,11 +66,9 @@
static TYPE* sInstance;
};
-template <typename TYPE>
-Mutex Singleton<TYPE>::sLock;
-
-template <typename TYPE>
-TYPE* Singleton<TYPE>::sInstance;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
/*
* use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 07c4de7..f6433a8 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -67,7 +67,10 @@
inline const char16_t* string() const;
+//TODO(b/35363681): remove
+private:
static inline std::string std_string(const String16& str);
+public:
size_t size() const;
void setTo(const String16& other);
status_t setTo(const char16_t* other);
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 1d12994..f5f9219 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -64,8 +64,14 @@
static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
static String8 formatV(const char* fmt, va_list args);
+ inline const char* c_str() const;
inline const char* string() const;
+
+// TODO(b/35363681): remove
+private:
static inline std::string std_string(const String8& str);
+public:
+
inline size_t size() const;
inline size_t bytes() const;
inline bool isEmpty() const;
@@ -259,6 +265,10 @@
return String8();
}
+inline const char* String8::c_str() const
+{
+ return mString;
+}
inline const char* String8::string() const
{
return mString;
diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h
index 28a77b8..9a643f9 100644
--- a/libutils/include/utils/Vector.h
+++ b/libutils/include/utils/Vector.h
@@ -20,8 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <new>
-
#include <log/log.h>
#include <utils/TypeHelpers.h>
#include <utils/VectorImpl.h>
diff --git a/libutils/primes.py b/libutils/primes.py
deleted file mode 100755
index e161dd8..0000000
--- a/libutils/primes.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python2.6
-#
-# Copyright (C) 2011 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.
-#
-
-#
-# Generates a table of prime numbers for use in BasicHashtable.cpp.
-#
-# Each prime is chosen such that it is a little more than twice as large as
-# the previous prime in the table. This makes it easier to choose a new
-# hashtable size when the underlying array is grown by as nominal factor
-# of two each time.
-#
-
-def is_odd_prime(n):
- limit = (n - 1) / 2
- d = 3
- while d <= limit:
- if n % d == 0:
- return False
- d += 2
- return True
-
-print "static size_t PRIMES[] = {"
-
-n = 5
-max = 2**31 - 1
-while n < max:
- print " %d," % (n)
- n = n * 2 + 1
- while not is_odd_prime(n):
- n += 2
-
-print " 0,"
-print "};"
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index ec6b67f..ea606a1 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -18,33 +18,74 @@
cc_test {
name: "libutils_tests",
+ host_supported: true,
srcs: [
- "BlobCache_test.cpp",
"BitSet_test.cpp",
- "Looper_test.cpp",
"LruCache_test.cpp",
- "RefBase_test.cpp",
+ "Singleton_test.cpp",
"String8_test.cpp",
"StrongPointer_test.cpp",
- "SystemClock_test.cpp",
"Unicode_test.cpp",
"Vector_test.cpp",
],
- shared_libs: [
- "libz",
- "liblog",
- "libcutils",
- "libutils",
+ target: {
+ android: {
+ srcs: [
+ "BlobCache_test.cpp",
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ "SystemClock_test.cpp",
+ ],
+ shared_libs: [
+ "libz",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbase",
+ "libdl",
+ ],
+ },
+ linux: {
+ srcs: [
+ "Looper_test.cpp",
+ "RefBase_test.cpp",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libutils",
+ "liblog",
+ "libbase",
+ ],
+ host_ldlibs: ["-ldl"],
+ },
+ },
+
+ required: [
+ "libutils_tests_singleton1",
+ "libutils_tests_singleton2",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
],
}
-cc_test_host {
- name: "libutils_tests_host",
- srcs: ["Vector_test.cpp"],
- static_libs: [
- "libutils",
- "liblog",
- ],
+cc_test_library {
+ name: "libutils_tests_singleton1",
+ host_supported: true,
+ relative_install_path: "libutils_tests",
+ srcs: ["Singleton_test1.cpp"],
+}
+
+cc_test_library {
+ name: "libutils_tests_singleton2",
+ host_supported: true,
+ relative_install_path: "libutils_tests",
+ srcs: ["Singleton_test2.cpp"],
+ shared_libs: ["libutils_tests_singleton1"],
}
diff --git a/libutils/tests/Singleton_test.cpp b/libutils/tests/Singleton_test.cpp
new file mode 100644
index 0000000..9acd3c3
--- /dev/null
+++ b/libutils/tests/Singleton_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "Singleton_test"
+
+#include <dlfcn.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <utils/Singleton.h>
+
+#include <gtest/gtest.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+TEST(SingletonTest, bug35674422) {
+ std::string path = android::base::GetExecutableDirectory();
+ // libutils_tests_singleton1.so contains the ANDROID_SINGLETON_STATIC_INSTANCE
+ // definition of SingletonTestData, load it first.
+ std::string lib = android::base::StringPrintf("%s/libutils_tests_singleton1.so", path.c_str());
+ void* handle1 = dlopen(lib.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle1 != nullptr) << dlerror();
+
+ // libutils_tests_singleton2.so references SingletonTestData but should not
+ // have a definition
+ lib = android::base::StringPrintf("%s/libutils_tests_singleton2.so", path.c_str());
+ void* handle2 = dlopen(lib.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle2 != nullptr) << dlerror();
+
+ using has_fn_t = decltype(&singletonHasInstance);
+ using get_fn_t = decltype(&singletonGetInstanceContents);
+ using set_fn_t = decltype(&singletonSetInstanceContents);
+
+ has_fn_t has1 = reinterpret_cast<has_fn_t>(dlsym(handle1, "singletonHasInstance"));
+ ASSERT_TRUE(has1 != nullptr) << dlerror();
+ has_fn_t has2 = reinterpret_cast<has_fn_t>(dlsym(handle2, "singletonHasInstance"));
+ ASSERT_TRUE(has2 != nullptr) << dlerror();
+ get_fn_t get1 = reinterpret_cast<get_fn_t>(dlsym(handle1, "singletonGetInstanceContents"));
+ ASSERT_TRUE(get1 != nullptr) << dlerror();
+ get_fn_t get2 = reinterpret_cast<get_fn_t>(dlsym(handle2, "singletonGetInstanceContents"));
+ ASSERT_TRUE(get2 != nullptr) << dlerror();
+ set_fn_t set1 = reinterpret_cast<set_fn_t>(dlsym(handle2, "singletonSetInstanceContents"));
+ ASSERT_TRUE(set1 != nullptr) << dlerror();
+
+ EXPECT_FALSE(has1());
+ EXPECT_FALSE(has2());
+ set1(12345678U);
+ EXPECT_TRUE(has1());
+ EXPECT_TRUE(has2());
+ EXPECT_EQ(12345678U, get1());
+ EXPECT_EQ(12345678U, get2());
+}
+
+}
diff --git a/libutils/tests/Singleton_test.h b/libutils/tests/Singleton_test.h
new file mode 100644
index 0000000..c77d9ff
--- /dev/null
+++ b/libutils/tests/Singleton_test.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_UTILS_SINGLETON_TEST_H
+#define ANDROID_UTILS_SINGLETON_TEST_H
+
+#include <sys/cdefs.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+struct SingletonTestData : Singleton<SingletonTestData> {
+ unsigned int contents;
+};
+
+__BEGIN_DECLS
+
+unsigned int singletonGetInstanceContents();
+void singletonSetInstanceContents(unsigned int);
+bool singletonHasInstance();
+
+__END_DECLS
+
+}
+
+#endif // ANDROID_UTILS_SINGLETON_TEST_H
+
diff --git a/libutils/tests/Singleton_test1.cpp b/libutils/tests/Singleton_test1.cpp
new file mode 100644
index 0000000..4a91ec0
--- /dev/null
+++ b/libutils/tests/Singleton_test1.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 <utils/Singleton.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+// Singleton<SingletonTestStruct> is referenced in Singleton_test1.cpp and
+// Singleton_test2.cpp, but only defined in Singleton_test1.cpp.
+ANDROID_SINGLETON_STATIC_INSTANCE(SingletonTestData);
+
+void singletonSetInstanceContents(unsigned int contents) {
+ SingletonTestData::getInstance().contents = contents;
+}
+
+unsigned int singletonGetInstanceContents() {
+ return SingletonTestData::getInstance().contents;
+}
+
+bool singletonHasInstance() {
+ return SingletonTestData::hasInstance();
+}
+
+}
diff --git a/libutils/tests/Singleton_test2.cpp b/libutils/tests/Singleton_test2.cpp
new file mode 100644
index 0000000..eb2a9df
--- /dev/null
+++ b/libutils/tests/Singleton_test2.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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 <utils/Singleton.h>
+
+#include "Singleton_test.h"
+
+namespace android {
+
+// Singleton<SingletonTestStruct> is referenced in Singleton_test1.cpp and
+// Singleton_test2.cpp, but only defined in Singleton_test1.cpp.
+
+void singletonSetInstanceContents(unsigned int contents) {
+ SingletonTestData::getInstance().contents = contents;
+}
+
+unsigned int singletonGetInstanceContents() {
+ return SingletonTestData::getInstance().contents;
+}
+
+bool singletonHasInstance() {
+ return SingletonTestData::hasInstance();
+}
+
+}
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/tests/StrongPointer_test.cpp
index 323a6f2..153cf96 100644
--- a/libutils/tests/StrongPointer_test.cpp
+++ b/libutils/tests/StrongPointer_test.cpp
@@ -21,13 +21,13 @@
using namespace android;
-class Foo : public LightRefBase<Foo> {
+class SPFoo : public LightRefBase<SPFoo> {
public:
- explicit Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
- ~Foo() {
+ ~SPFoo() {
*mDeleted = true;
}
private:
@@ -36,13 +36,13 @@
TEST(StrongPointer, move) {
bool isDeleted;
- Foo* foo = new Foo(&isDeleted);
+ SPFoo* foo = new SPFoo(&isDeleted);
ASSERT_EQ(0, foo->getStrongCount());
ASSERT_FALSE(isDeleted) << "Already deleted...?";
- sp<Foo> sp1(foo);
+ sp<SPFoo> sp1(foo);
ASSERT_EQ(1, foo->getStrongCount());
{
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
ASSERT_EQ(1, foo->getStrongCount()) << "std::move failed, incremented refcnt";
ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
// The strong count isn't increasing, let's double check the old object
@@ -52,7 +52,7 @@
ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
{
// Now let's double check it deletes on time
- sp<Foo> sp2 = std::move(sp1);
+ sp<SPFoo> sp2 = std::move(sp1);
}
ASSERT_TRUE(isDeleted) << "foo was leaked!";
}
diff --git a/base/.clang-format b/logcat/.clang-format
similarity index 68%
copy from base/.clang-format
copy to logcat/.clang-format
index 2b83a1f..393c309 100644
--- a/base/.clang-format
+++ b/logcat/.clang-format
@@ -1,11 +1,11 @@
BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
-IndentWidth: 2
+IndentWidth: 4
PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
+TabWidth: 4
PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 1dacbe1..f564f0f 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -1,20 +1,31 @@
# Copyright 2006-2014 The Android Open Source Project
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
+
+logcatLibs := liblog libbase libcutils libpcrecpp
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= logcat.cpp event.logtags
-
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils libpcrecpp
-
LOCAL_MODULE := logcat
-
+LOCAL_SRC_FILES := logcat_main.cpp event.logtags
+LOCAL_SHARED_LIBRARIES := liblogcat $(logcatLibs)
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
+LOCAL_MODULE := liblogcat
+LOCAL_SRC_FILES := logcat.cpp getopt_long.cpp logcat_system.cpp
+LOCAL_SHARED_LIBRARIES := $(logcatLibs)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
LOCAL_MODULE := logpersist.start
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_CLASS := EXECUTABLES
diff --git a/logcat/getopt_long.cpp b/logcat/getopt_long.cpp
new file mode 100644
index 0000000..5f8dd66
--- /dev/null
+++ b/logcat/getopt_long.cpp
@@ -0,0 +1,402 @@
+/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+#include <log/getopt.h>
+
+#define PRINT_ERROR ((context->opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 // permute non-options to the end of argv
+#define FLAG_ALLARGS 0x02 // treat non-options as args to option "-1"
+
+// return values
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define D_PREFIX 0
+#define DD_PREFIX 1
+#define W_PREFIX 2
+
+// Compute the greatest common divisor of a and b.
+static int gcd(int a, int b) {
+ int c = a % b;
+ while (c) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+ return b;
+}
+
+// Exchange the block from nonopt_start to nonopt_end with the block from
+// nonopt_end to opt_end (keeping the same order of arguments in each block).
+// Returns optind - (nonopt_end - nonopt_start) for convenience.
+static int permute_args(getopt_context* context, char* const* nargv) {
+ // compute lengths of blocks and number and size of cycles
+ int nnonopts = context->nonopt_end - context->nonopt_start;
+ int nopts = context->optind - context->nonopt_end;
+ int ncycle = gcd(nnonopts, nopts);
+ int cyclelen = (context->optind - context->nonopt_start) / ncycle;
+
+ for (int i = 0; i < ncycle; i++) {
+ int cstart = context->nonopt_end + i;
+ int pos = cstart;
+ for (int j = 0; j < cyclelen; j++) {
+ if (pos >= context->nonopt_end) {
+ pos -= nnonopts;
+ } else {
+ pos += nopts;
+ }
+ char* swap = nargv[pos];
+ const_cast<char**>(nargv)[pos] = nargv[cstart];
+ const_cast<char**>(nargv)[cstart] = swap;
+ }
+ }
+ return context->optind - (context->nonopt_end - context->nonopt_start);
+}
+
+// parse_long_options_r --
+// Parse long options in argc/argv argument vector.
+// Returns -1 if short_too is set and the option does not match long_options.
+static int parse_long_options_r(char* const* nargv, const char* options,
+ const struct option* long_options, int* idx,
+ bool short_too, struct getopt_context* context) {
+ const char* current_argv = context->place;
+ const char* current_dash;
+ switch (context->dash_prefix) {
+ case D_PREFIX:
+ current_dash = "-";
+ break;
+ case DD_PREFIX:
+ current_dash = "--";
+ break;
+ case W_PREFIX:
+ current_dash = "-W ";
+ break;
+ default:
+ current_dash = "";
+ break;
+ }
+ context->optind++;
+
+ const char* has_equal;
+ size_t current_argv_len;
+ if (!!(has_equal = strchr(current_argv, '='))) {
+ // argument found (--option=arg)
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else {
+ current_argv_len = strlen(current_argv);
+ }
+
+ int match = -1;
+ bool exact_match = false;
+ bool second_partial_match = false;
+ for (int i = 0; long_options[i].name; i++) {
+ // find matching long option
+ if (strncmp(current_argv, long_options[i].name, current_argv_len)) {
+ continue;
+ }
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ // exact match
+ match = i;
+ exact_match = true;
+ break;
+ }
+ // If this is a known short option, don't allow
+ // a partial match of a single character.
+ if (short_too && current_argv_len == 1) continue;
+
+ if (match == -1) { // first partial match
+ match = i;
+ } else if (long_options[i].has_arg != long_options[match].has_arg ||
+ long_options[i].flag != long_options[match].flag ||
+ long_options[i].val != long_options[match].val) {
+ second_partial_match = true;
+ }
+ }
+ if (!exact_match && second_partial_match) {
+ // ambiguous abbreviation
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr,
+ "option `%s%.*s' is ambiguous", current_dash,
+ (int)current_argv_len, current_argv);
+ }
+ context->optopt = 0;
+ return BADCH;
+ }
+ if (match != -1) { // option found
+ if (long_options[match].has_arg == no_argument && has_equal) {
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr,
+ "option `%s%.*s' doesn't allow an argument",
+ current_dash, (int)current_argv_len, current_argv);
+ }
+ // XXX: GNU sets optopt to val regardless of flag
+ context->optopt =
+ long_options[match].flag ? 0 : long_options[match].val;
+ return BADCH;
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal) {
+ context->optarg = has_equal;
+ } else if (long_options[match].has_arg == required_argument) {
+ // optional argument doesn't use next nargv
+ context->optarg = nargv[context->optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument) &&
+ !context->optarg) {
+ // Missing argument; leading ':' indicates no error
+ // should be generated.
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr,
+ "option `%s%s' requires an argument", current_dash,
+ current_argv);
+ }
+ // XXX: GNU sets optopt to val regardless of flag
+ context->optopt =
+ long_options[match].flag ? 0 : long_options[match].val;
+ context->optind--;
+ return BADARG;
+ }
+ } else { // unknown option
+ if (short_too) {
+ context->optind--;
+ return -1;
+ }
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr, "unrecognized option `%s%s'",
+ current_dash, current_argv);
+ }
+ context->optopt = 0;
+ return BADCH;
+ }
+ if (idx) *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return 0;
+ }
+ return long_options[match].val;
+}
+
+// getopt_long_r --
+// Parse argc/argv argument vector.
+int getopt_long_r(int nargc, char* const* nargv, const char* options,
+ const struct option* long_options, int* idx,
+ struct getopt_context* context) {
+ if (!options) return -1;
+
+ // XXX Some GNU programs (like cvs) set optind to 0 instead of
+ // XXX using optreset. Work around this braindamage.
+ if (!context->optind) context->optind = context->optreset = 1;
+
+ // Disable GNU extensions if options string begins with a '+'.
+ int flags = FLAG_PERMUTE;
+ if (*options == '-') {
+ flags |= FLAG_ALLARGS;
+ } else if (*options == '+') {
+ flags &= ~FLAG_PERMUTE;
+ }
+ if (*options == '+' || *options == '-') options++;
+
+ context->optarg = nullptr;
+ if (context->optreset) context->nonopt_start = context->nonopt_end = -1;
+start:
+ if (context->optreset || !*context->place) { // update scanning pointer
+ context->optreset = 0;
+ if (context->optind >= nargc) { // end of argument vector
+ context->place = EMSG;
+ if (context->nonopt_end != -1) {
+ // do permutation, if we have to
+ context->optind = permute_args(context, nargv);
+ } else if (context->nonopt_start != -1) {
+ // If we skipped non-options, set optind to the first of them.
+ context->optind = context->nonopt_start;
+ }
+ context->nonopt_start = context->nonopt_end = -1;
+ return -1;
+ }
+ if (*(context->place = nargv[context->optind]) != '-' ||
+ context->place[1] == '\0') {
+ context->place = EMSG; // found non-option
+ if (flags & FLAG_ALLARGS) {
+ // GNU extension: return non-option as argument to option 1
+ context->optarg = nargv[context->optind++];
+ return INORDER;
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ // If no permutation wanted, stop parsing at first non-option.
+ return -1;
+ }
+ // do permutation
+ if (context->nonopt_start == -1) {
+ context->nonopt_start = context->optind;
+ } else if (context->nonopt_end != -1) {
+ context->nonopt_start = permute_args(context, nargv);
+ context->nonopt_end = -1;
+ }
+ context->optind++;
+ // process next argument
+ goto start;
+ }
+ if (context->nonopt_start != -1 && context->nonopt_end == -1) {
+ context->nonopt_end = context->optind;
+ }
+
+ // If we have "-" do nothing, if "--" we are done.
+ if (context->place[1] != '\0' && *++(context->place) == '-' &&
+ context->place[1] == '\0') {
+ context->optind++;
+ context->place = EMSG;
+ // We found an option (--), so if we skipped
+ // non-options, we have to permute.
+ if (context->nonopt_end != -1) {
+ context->optind = permute_args(context, nargv);
+ }
+ context->nonopt_start = context->nonopt_end = -1;
+ return -1;
+ }
+ }
+
+ int optchar;
+ // Check long options if:
+ // 1) we were passed some
+ // 2) the arg is not just "-"
+ // 3) either the arg starts with -- we are getopt_long_only()
+ if (long_options && context->place != nargv[context->optind] &&
+ (*context->place == '-')) {
+ bool short_too = false;
+ context->dash_prefix = D_PREFIX;
+ if (*context->place == '-') {
+ context->place++; // --foo long option
+ context->dash_prefix = DD_PREFIX;
+ } else if (*context->place != ':' && strchr(options, *context->place)) {
+ short_too = true; // could be short option too
+ }
+
+ optchar = parse_long_options_r(nargv, options, long_options, idx,
+ short_too, context);
+ if (optchar != -1) {
+ context->place = EMSG;
+ return optchar;
+ }
+ }
+
+ const char* oli; // option letter list index
+ if ((optchar = (int)*(context->place)++) == (int)':' ||
+ (optchar == (int)'-' && *context->place != '\0') ||
+ !(oli = strchr(options, optchar))) {
+ // If the user specified "-" and '-' isn't listed in
+ // options, return -1 (non-option) as per POSIX.
+ // Otherwise, it is an unknown option character (or ':').
+ if (optchar == (int)'-' && *context->place == '\0') return -1;
+ if (!*context->place) context->optind++;
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr, "invalid option -- %c",
+ optchar);
+ }
+ context->optopt = optchar;
+ return BADCH;
+ }
+
+ static const char recargchar[] = "option requires an argument -- %c";
+ if (long_options && optchar == 'W' && oli[1] == ';') {
+ // -W long-option
+ if (*context->place) { // no space
+ ; // NOTHING
+ } else if (++(context->optind) >= nargc) { // no arg
+ context->place = EMSG;
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr, recargchar, optchar);
+ }
+ context->optopt = optchar;
+ return BADARG;
+ } else { // white space
+ context->place = nargv[context->optind];
+ }
+ context->dash_prefix = W_PREFIX;
+ optchar = parse_long_options_r(nargv, options, long_options, idx, false,
+ context);
+ context->place = EMSG;
+ return optchar;
+ }
+ if (*++oli != ':') { // doesn't take argument
+ if (!*context->place) context->optind++;
+ } else { // takes (optional) argument
+ context->optarg = nullptr;
+ if (*context->place) { // no white space
+ context->optarg = context->place;
+ } else if (oli[1] != ':') { // arg not optional
+ if (++(context->optind) >= nargc) { // no arg
+ context->place = EMSG;
+ if (PRINT_ERROR) {
+ fprintf(context->optstderr ?: stderr, recargchar, optchar);
+ }
+ context->optopt = optchar;
+ return BADARG;
+ }
+ context->optarg = nargv[context->optind];
+ }
+ context->place = EMSG;
+ context->optind++;
+ }
+ // dump back option letter
+ return optchar;
+}
diff --git a/logcat/include/log/getopt.h b/logcat/include/log/getopt.h
new file mode 100644
index 0000000..0da2b10
--- /dev/null
+++ b/logcat/include/log/getopt.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 _LOG_GETOPT_H_
+#define _LOG_GETOPT_H_
+
+#ifndef __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 1
+#elif __ANDROID_API__ > 24 /* > Nougat */
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE
+
+#include <getopt.h>
+#include <sys/cdefs.h>
+
+struct getopt_context {
+ int opterr;
+ int optind;
+ int optopt;
+ int optreset;
+ const char* optarg;
+ FILE* optstderr; /* NULL defaults to stderr */
+ /* private */
+ const char* place;
+ int nonopt_start;
+ int nonopt_end;
+ int dash_prefix;
+ /* expansion space */
+ int __extra__;
+ void* __stuff__;
+};
+
+#define EMSG ""
+#define NO_PREFIX (-1)
+
+#define INIT_GETOPT_CONTEXT(context) \
+ context = { 1, 1, '?', 0, NULL, NULL, EMSG, -1, -1, NO_PREFIX, 0, NULL }
+
+__BEGIN_DECLS
+int getopt_long_r(int nargc, char* const* nargv, const char* options,
+ const struct option* long_options, int* idx,
+ struct getopt_context* context);
+
+__END_DECLS
+
+#endif /* __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE */
+
+#endif /* !_LOG_GETOPT_H_ */
diff --git a/logcat/include/log/logcat.h b/logcat/include/log/logcat.h
new file mode 100644
index 0000000..009672c
--- /dev/null
+++ b/logcat/include/log/logcat.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005-2017 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 _LIBS_LOGCAT_H /* header boilerplate */
+#define _LIBS_LOGCAT_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 1
+#elif __ANDROID_API__ > 24 /* > Nougat */
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE
+
+/* For managing an in-process logcat function, rather than forking/execing
+ *
+ * It also serves as the basis for the logcat command.
+ *
+ * The following C API allows a logcat instance to be created, run
+ * to completion, and then release all the associated resources.
+ */
+
+/*
+ * The opaque context
+ */
+#ifndef __android_logcat_context_defined /* typedef boilerplate */
+#define __android_logcat_context_defined
+typedef struct android_logcat_context_internal* android_logcat_context;
+#endif
+
+/* Creates a context associated with this logcat instance
+ *
+ * Returns a pointer to the context, or a NULL on error.
+ */
+android_logcat_context create_android_logcat();
+
+/* Collects and outputs the logcat data to output and error file descriptors
+ *
+ * Will block, performed in-thread and in-process
+ *
+ * The output file descriptor variable, if greater than or equal to 0, is
+ * where the output (ie: stdout) will be sent. The file descriptor is closed
+ * on android_logcat_destroy which terminates the instance, or when an -f flag
+ * (output redirect to a file) is present in the command. The error file
+ * descriptor variable, if greater than or equal to 0, is where the error
+ * stream (ie: stderr) will be sent, also closed on android_logcat_destroy.
+ * The error file descriptor can be set to equal to the output file descriptor,
+ * which will mix output and error stream content, and will defer closure of
+ * the file descriptor on -f flag redirection. Negative values for the file
+ * descriptors will use stdout and stderr FILE references respectively
+ * internally, and will not close the references as noted above.
+ *
+ * Return value is 0 for success, non-zero for errors.
+ */
+int android_logcat_run_command(android_logcat_context ctx, int output, int error,
+ int argc, char* const* argv, char* const* envp);
+
+/* Will not block, performed in-process
+ *
+ * Starts a thread, opens a pipe, returns reading end fd, saves off argv.
+ * The command supports 2>&1 (mix content) and 2>/dev/null (drop content) for
+ * scripted error (stderr) redirection.
+ */
+int android_logcat_run_command_thread(android_logcat_context ctx, int argc,
+ char* const* argv, char* const* envp);
+int android_logcat_run_command_thread_running(android_logcat_context ctx);
+
+/* Finished with context
+ *
+ * Kill the command thread ASAP (if any), and free up all associated resources.
+ *
+ * Return value is the result of the android_logcat_run_command, or
+ * non-zero for any errors.
+ */
+int android_logcat_destroy(android_logcat_context* ctx);
+
+/* derived helpers */
+
+/*
+ * In-process thread that acts like somewhat like libc-like system and popen
+ * respectively. Can not handle shell scripting, only pure calls to the
+ * logcat operations. The android_logcat_system is a wrapper for the
+ * create_android_logcat, android_logcat_run_command and android_logcat_destroy
+ * API above. The android_logcat_popen is a wrapper for the
+ * android_logcat_run_command_thread API above. The android_logcat_pclose is
+ * a wrapper for a reasonable wait until output has subsided for command
+ * completion, fclose on the FILE pointer and the android_logcat_destroy API.
+ */
+int android_logcat_system(const char* command);
+FILE* android_logcat_popen(android_logcat_context* ctx, const char* command);
+int android_logcat_pclose(android_logcat_context* ctx, FILE* output);
+
+#endif /* __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOGCAT_H */
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 4a171fd..4da5030 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,4 +1,18 @@
-// Copyright 2006-2015 The Android Open Source Project
+/*
+ * Copyright (C) 2006-2017 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 <arpa/inet.h>
#include <assert.h>
@@ -6,10 +20,9 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <getopt.h>
#include <math.h>
+#include <pthread.h>
#include <sched.h>
-#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,8 +35,10 @@
#include <time.h>
#include <unistd.h>
+#include <atomic>
#include <memory>
#include <string>
+#include <vector>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
@@ -31,6 +46,8 @@
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
+#include <log/getopt.h>
+#include <log/logcat.h>
#include <log/logprint.h>
#include <private/android_logger.h>
#include <system/thread_defs.h>
@@ -39,16 +56,11 @@
#define DEFAULT_MAX_ROTATED_LOGS 4
-static AndroidLogFormat * g_logformat;
-
-/* logd prefixes records with a length field */
-#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
-
struct log_device_t {
const char* device;
bool binary;
- struct logger *logger;
- struct logger_list *logger_list;
+ struct logger* logger;
+ struct logger_list* logger_list;
bool printed;
log_device_t* next;
@@ -56,76 +68,200 @@
log_device_t(const char* d, bool b) {
device = d;
binary = b;
- next = NULL;
+ next = nullptr;
printed = false;
- logger = NULL;
- logger_list = NULL;
+ logger = nullptr;
+ logger_list = nullptr;
}
};
+struct android_logcat_context_internal {
+ // status
+ volatile std::atomic_int retval; // valid if thread_stopped set
+ // Arguments passed in, or copies and storage thereof if a thread.
+ int argc;
+ char* const* argv;
+ char* const* envp;
+ std::vector<std::string> args;
+ std::vector<const char*> argv_hold;
+ std::vector<std::string> envs;
+ std::vector<const char*> envp_hold;
+ int output_fd; // duplication of fileno(output) (below)
+ int error_fd; // duplication of fileno(error) (below)
+
+ // library
+ int fds[2]; // From popen call
+ FILE* output; // everything writes to fileno(output), buffer unused
+ FILE* error; // unless error == output.
+ pthread_t thr;
+ volatile std::atomic_bool stop; // quick exit flag
+ volatile std::atomic_bool thread_stopped;
+ bool stderr_null; // shell "2>/dev/null"
+ bool stderr_stdout; // shell "2>&1"
+
+ // global variables
+ AndroidLogFormat* logformat;
+ const char* outputFileName;
+ // 0 means "no log rotation"
+ size_t logRotateSizeKBytes;
+ // 0 means "unbounded"
+ size_t maxRotatedLogs;
+ size_t outByteCount;
+ int printBinary;
+ int devCount; // >1 means multiple
+ pcrecpp::RE* regex;
+ log_device_t* devices;
+ EventTagMap* eventTagMap;
+ // 0 means "infinite"
+ size_t maxCount;
+ size_t printCount;
+
+ bool printItAnyways;
+ bool debug;
+ bool hasOpenedEventTagMap;
+};
+
+// Creates a context associated with this logcat instance
+android_logcat_context create_android_logcat() {
+ android_logcat_context_internal* context;
+
+ context = (android_logcat_context_internal*)calloc(
+ 1, sizeof(android_logcat_context_internal));
+ if (!context) return nullptr;
+
+ context->fds[0] = -1;
+ context->fds[1] = -1;
+ context->output_fd = -1;
+ context->error_fd = -1;
+ context->maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
+
+ context->argv_hold.clear();
+ context->args.clear();
+ context->envp_hold.clear();
+ context->envs.clear();
+
+ return (android_logcat_context)context;
+}
+
+// logd prefixes records with a length field
+#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
+
namespace android {
-/* Global Variables */
-
-static const char * g_outputFileName;
-// 0 means "no log rotation"
-static size_t g_logRotateSizeKBytes;
-// 0 means "unbounded"
-static size_t g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
-static int g_outFD = -1;
-static size_t g_outByteCount;
-static int g_printBinary;
-static int g_devCount; // >1 means multiple
-static pcrecpp::RE* g_regex;
-// 0 means "infinite"
-static size_t g_maxCount;
-static size_t g_printCount;
-static bool g_printItAnyways;
-static bool g_debug;
-
-enum helpType {
- HELP_FALSE,
- HELP_TRUE,
- HELP_FORMAT
-};
+enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
// if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
+static void logcat_panic(android_logcat_context_internal* context,
+ enum helpType showHelp, const char* fmt, ...)
+ __printflike(3, 4);
-static int openLogFile (const char *pathname)
-{
+static int openLogFile(const char* pathname) {
return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
}
-static void rotateLogs()
-{
+static void close_output(android_logcat_context_internal* context) {
+ // split output_from_error
+ if (context->error == context->output) {
+ context->output = nullptr;
+ context->output_fd = -1;
+ }
+ if (context->error && (context->output_fd == fileno(context->error))) {
+ context->output_fd = -1;
+ }
+ if (context->output_fd == context->error_fd) {
+ context->output_fd = -1;
+ }
+ // close output channel
+ if (context->output) {
+ if (context->output != stdout) {
+ if (context->output_fd == fileno(context->output)) {
+ context->output_fd = -1;
+ }
+ if (context->fds[1] == fileno(context->output)) {
+ context->fds[1] = -1;
+ }
+ fclose(context->output);
+ }
+ context->output = nullptr;
+ }
+ if (context->output_fd >= 0) {
+ if (context->output_fd != fileno(stdout)) {
+ if (context->fds[1] == context->output_fd) {
+ context->fds[1] = -1;
+ }
+ close(context->output_fd);
+ }
+ context->output_fd = -1;
+ }
+}
+
+static void close_error(android_logcat_context_internal* context) {
+ // split error_from_output
+ if (context->output == context->error) {
+ context->error = nullptr;
+ context->error_fd = -1;
+ }
+ if (context->output && (context->error_fd == fileno(context->output))) {
+ context->error_fd = -1;
+ }
+ if (context->error_fd == context->output_fd) {
+ context->error_fd = -1;
+ }
+ // close error channel
+ if (context->error) {
+ if ((context->error != stderr) && (context->error != stdout)) {
+ if (context->error_fd == fileno(context->error)) {
+ context->error_fd = -1;
+ }
+ if (context->fds[1] == fileno(context->error)) {
+ context->fds[1] = -1;
+ }
+ fclose(context->error);
+ }
+ context->error = nullptr;
+ }
+ if (context->error_fd >= 0) {
+ if ((context->error_fd != fileno(stdout)) &&
+ (context->error_fd != fileno(stderr))) {
+ if (context->fds[1] == context->error_fd) context->fds[1] = -1;
+ close(context->error_fd);
+ }
+ context->error_fd = -1;
+ }
+}
+
+static void rotateLogs(android_logcat_context_internal* context) {
int err;
// Can't rotate logs if we're not outputting to a file
- if (g_outputFileName == NULL) {
- return;
- }
+ if (!context->outputFileName) return;
- close(g_outFD);
+ close_output(context);
- // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal.
- // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2
+ // Compute the maximum number of digits needed to count up to
+ // maxRotatedLogs in decimal. eg:
+ // maxRotatedLogs == 30
+ // -> log10(30) == 1.477
+ // -> maxRotationCountDigits == 2
int maxRotationCountDigits =
- (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
+ (context->maxRotatedLogs > 0)
+ ? (int)(floor(log10(context->maxRotatedLogs) + 1))
+ : 0;
- for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
+ for (int i = context->maxRotatedLogs; i > 0; i--) {
std::string file1 = android::base::StringPrintf(
- "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
+ "%s.%.*d", context->outputFileName, maxRotationCountDigits, i);
std::string file0;
- if (i - 1 == 0) {
- file0 = android::base::StringPrintf("%s", g_outputFileName);
+ if (!(i - 1)) {
+ file0 = android::base::StringPrintf("%s", context->outputFileName);
} else {
- file0 = android::base::StringPrintf(
- "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
+ file0 =
+ android::base::StringPrintf("%s.%.*d", context->outputFileName,
+ maxRotationCountDigits, i - 1);
}
- if ((file0.length() == 0) || (file1.length() == 0)) {
+ if (!file0.length() || !file1.length()) {
perror("while rotating log files");
break;
}
@@ -137,153 +273,165 @@
}
}
- g_outFD = openLogFile(g_outputFileName);
+ context->output_fd = openLogFile(context->outputFileName);
- if (g_outFD < 0) {
- logcat_panic(HELP_FALSE, "couldn't open output file");
+ if (context->output_fd < 0) {
+ logcat_panic(context, HELP_FALSE, "couldn't open output file");
+ return;
+ }
+ context->output = fdopen(context->output_fd, "web");
+ if (!context->output) {
+ logcat_panic(context, HELP_FALSE, "couldn't fdopen output file");
+ return;
+ }
+ if (context->stderr_stdout) {
+ close_error(context);
+ context->error = context->output;
+ context->error_fd = context->output_fd;
}
- g_outByteCount = 0;
-
+ context->outByteCount = 0;
}
-void printBinary(struct log_msg *buf)
-{
+void printBinary(android_logcat_context_internal* context, struct log_msg* buf) {
size_t size = buf->len();
- TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
+ TEMP_FAILURE_RETRY(write(context->output_fd, buf, size));
}
-static bool regexOk(const AndroidLogEntry& entry)
-{
- if (!g_regex) {
- return true;
- }
+static bool regexOk(android_logcat_context_internal* context,
+ const AndroidLogEntry& entry) {
+ if (!context->regex) return true;
std::string messageString(entry.message, entry.messageLen);
- return g_regex->PartialMatch(messageString);
+ return context->regex->PartialMatch(messageString);
}
-static void processBuffer(log_device_t* dev, struct log_msg *buf)
-{
+static void processBuffer(android_logcat_context_internal* context,
+ log_device_t* dev, struct log_msg* buf) {
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
if (dev->binary) {
- static bool hasOpenedEventTagMap = false;
- static EventTagMap *eventTagMap = NULL;
-
- if (!eventTagMap && !hasOpenedEventTagMap) {
- eventTagMap = android_openEventTagMap(NULL);
- hasOpenedEventTagMap = true;
+ if (!context->eventTagMap && !context->hasOpenedEventTagMap) {
+ context->eventTagMap = android_openEventTagMap(nullptr);
+ context->hasOpenedEventTagMap = true;
}
- err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
- eventTagMap,
- binaryMsgBuf,
- sizeof(binaryMsgBuf));
- //printf(">>> pri=%d len=%d msg='%s'\n",
+ err = android_log_processBinaryLogBuffer(
+ &buf->entry_v1, &entry, context->eventTagMap, binaryMsgBuf,
+ sizeof(binaryMsgBuf));
+ // printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
err = android_log_processLogBuffer(&buf->entry_v1, &entry);
}
- if ((err < 0) && !g_debug) {
- goto error;
- }
+ if ((err < 0) && !context->debug) return;
- if (android_log_shouldPrintLine(g_logformat,
- std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = regexOk(entry);
+ if (android_log_shouldPrintLine(
+ context->logformat, std::string(entry.tag, entry.tagLen).c_str(),
+ entry.priority)) {
+ bool match = regexOk(context, entry);
- g_printCount += match;
- if (match || g_printItAnyways) {
- bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
+ context->printCount += match;
+ if (match || context->printItAnyways) {
+ bytesWritten = android_log_printLogLine(context->logformat,
+ context->output_fd, &entry);
if (bytesWritten < 0) {
- logcat_panic(HELP_FALSE, "output error");
+ logcat_panic(context, HELP_FALSE, "output error");
+ return;
}
}
}
- g_outByteCount += bytesWritten;
+ context->outByteCount += bytesWritten;
- if (g_logRotateSizeKBytes > 0
- && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
- ) {
- rotateLogs();
+ if (context->logRotateSizeKBytes > 0 &&
+ (context->outByteCount / 1024) >= context->logRotateSizeKBytes) {
+ rotateLogs(context);
}
-
-error:
- return;
}
-static void maybePrintStart(log_device_t* dev, bool printDividers) {
+static void maybePrintStart(android_logcat_context_internal* context,
+ log_device_t* dev, bool printDividers) {
if (!dev->printed || printDividers) {
- if (g_devCount > 1 && !g_printBinary) {
+ if (context->devCount > 1 && !context->printBinary) {
char buf[1024];
snprintf(buf, sizeof(buf), "--------- %s %s\n",
- dev->printed ? "switch to" : "beginning of",
- dev->device);
- if (write(g_outFD, buf, strlen(buf)) < 0) {
- logcat_panic(HELP_FALSE, "output error");
+ dev->printed ? "switch to" : "beginning of", dev->device);
+ if (write(context->output_fd, buf, strlen(buf)) < 0) {
+ logcat_panic(context, HELP_FALSE, "output error");
+ return;
}
}
dev->printed = true;
}
}
-static void setupOutputAndSchedulingPolicy(bool blocking) {
- if (g_outputFileName == NULL) {
- g_outFD = STDOUT_FILENO;
- return;
- }
+static void setupOutputAndSchedulingPolicy(
+ android_logcat_context_internal* context, bool blocking) {
+ if (!context->outputFileName) return;
if (blocking) {
// Lower priority and set to batch scheduling if we are saving
// the logs into files and taking continuous content.
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- fprintf(stderr, "failed to set background scheduling policy\n");
+ if ((set_sched_policy(0, SP_BACKGROUND) < 0) && context->error) {
+ fprintf(context->error,
+ "failed to set background scheduling policy\n");
}
struct sched_param param;
memset(¶m, 0, sizeof(param));
- if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
+ if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
fprintf(stderr, "failed to set to batch scheduler\n");
}
- if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
- fprintf(stderr, "failed set to priority\n");
+ if ((setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) &&
+ context->error) {
+ fprintf(context->error, "failed set to priority\n");
}
}
- g_outFD = openLogFile (g_outputFileName);
+ close_output(context);
- if (g_outFD < 0) {
- logcat_panic(HELP_FALSE, "couldn't open output file");
+ context->output_fd = openLogFile(context->outputFileName);
+
+ if (context->output_fd < 0) {
+ logcat_panic(context, HELP_FALSE, "couldn't open output file");
+ return;
}
struct stat statbuf;
- if (fstat(g_outFD, &statbuf) == -1) {
- close(g_outFD);
- logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
+ if (fstat(context->output_fd, &statbuf) == -1) {
+ close_output(context);
+ logcat_panic(context, HELP_FALSE, "couldn't get output file stat\n");
+ return;
}
- if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- close(g_outFD);
- logcat_panic(HELP_FALSE, "invalid output file stat\n");
+ if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
+ close_output(context);
+ logcat_panic(context, HELP_FALSE, "invalid output file stat\n");
+ return;
}
- g_outByteCount = statbuf.st_size;
+ context->output = fdopen(context->output_fd, "web");
+
+ context->outByteCount = statbuf.st_size;
}
-static void show_help(const char *cmd)
-{
- fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
+// clang-format off
+static void show_help(android_logcat_context_internal* context) {
+ if (!context->error) return;
- fprintf(stderr, "options include:\n"
+ const char* cmd = strrchr(context->argv[0], '/');
+ cmd = cmd ? cmd + 1 : context->argv[0];
+
+ fprintf(context->error, "Usage: %s [options] [filterspecs]\n", cmd);
+
+ fprintf(context->error, "options include:\n"
" -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
" -f <file>, --file=<file> Log to file. Default is stdout\n"
" -r <kbytes>, --rotate-kbytes=<kbytes>\n"
@@ -298,6 +446,8 @@
" and individually flagged modifying adverbs can be added:\n"
" color descriptive epoch monotonic printable uid\n"
" usec UTC year zone\n"
+ " Multiple -v parameters or comma separated list of format and\n"
+ " format modifiers are allowed.\n"
// private and undocumented nsec, no signal, too much noise
// useful for -T or -t <timestamp> accurate testing though.
" -D, --dividers Print dividers between each log buffer\n"
@@ -347,7 +497,7 @@
" comes first. Improves efficiency of polling by providing\n"
" an about-to-wrap wakeup.\n");
- fprintf(stderr,"\nfilterspecs are a series of \n"
+ fprintf(context->error, "\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
"where <tag> is a log component tag (or * for all) and priority is:\n"
" V Verbose (default for <tag>)\n"
@@ -365,9 +515,9 @@
"or defaults to \"threadtime\"\n\n");
}
-static void show_format_help()
-{
- fprintf(stderr,
+static void show_format_help(android_logcat_context_internal* context) {
+ if (!context->error) return;
+ fprintf(context->error,
"-v <format>, --format=<format> options:\n"
" Sets log print format verb and adverbs, where <format> is:\n"
" brief long process raw tag thread threadtime time\n"
@@ -398,141 +548,121 @@
" \"<zone>\" — Print using this public named timezone (experimental).\n\n"
);
}
+// clang-format on
-static int setLogFormat(const char * formatString)
-{
- static AndroidLogPrintFormat format;
+static int setLogFormat(android_logcat_context_internal* context,
+ const char* formatString) {
+ AndroidLogPrintFormat format;
format = android_log_formatFromString(formatString);
- if (format == FORMAT_OFF) {
- // FORMAT_OFF means invalid string
- return -1;
- }
+ // invalid string?
+ if (format == FORMAT_OFF) return -1;
- return android_log_setPrintFormat(g_logformat, format);
+ return android_log_setPrintFormat(context->logformat, format);
}
-static const char multipliers[][2] = {
- { "" },
- { "K" },
- { "M" },
- { "G" }
-};
+static const char multipliers[][2] = { { "" }, { "K" }, { "M" }, { "G" } };
-static unsigned long value_of_size(unsigned long value)
-{
+static unsigned long value_of_size(unsigned long value) {
for (unsigned i = 0;
- (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
- value /= 1024, ++i) ;
+ (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
+ value /= 1024, ++i)
+ ;
return value;
}
-static const char *multiplier_of_size(unsigned long value)
-{
+static const char* multiplier_of_size(unsigned long value) {
unsigned i;
for (i = 0;
- (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
- value /= 1024, ++i) ;
+ (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
+ value /= 1024, ++i)
+ ;
return multipliers[i];
}
-/*String to unsigned int, returns -1 if it fails*/
-static bool getSizeTArg(const char *ptr, size_t *val, size_t min = 0,
- size_t max = SIZE_MAX)
-{
- if (!ptr) {
- return false;
- }
+// String to unsigned int, returns -1 if it fails
+static bool getSizeTArg(const char* ptr, size_t* val, size_t min = 0,
+ size_t max = SIZE_MAX) {
+ if (!ptr) return false;
- char *endp;
+ char* endp;
errno = 0;
size_t ret = (size_t)strtoll(ptr, &endp, 0);
- if (endp[0] || errno) {
- return false;
- }
+ if (endp[0] || errno) return false;
- if ((ret > max) || (ret < min)) {
- return false;
- }
+ if ((ret > max) || (ret < min)) return false;
*val = ret;
return true;
}
-static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
-{
- va_list args;
+static void logcat_panic(android_logcat_context_internal* context,
+ enum helpType showHelp, const char* fmt, ...) {
+ context->retval = EXIT_FAILURE;
+ if (!context->error) {
+ context->stop = true;
+ return;
+ }
+
+ va_list args;
va_start(args, fmt);
- vfprintf(stderr, fmt, args);
+ vfprintf(context->error, fmt, args);
va_end(args);
switch (showHelp) {
- case HELP_TRUE:
- show_help(getprogname());
- break;
- case HELP_FORMAT:
- show_format_help();
- break;
- case HELP_FALSE:
- default:
- break;
+ case HELP_TRUE:
+ show_help(context);
+ break;
+ case HELP_FORMAT:
+ show_format_help(context);
+ break;
+ case HELP_FALSE:
+ default:
+ break;
}
- exit(EXIT_FAILURE);
+ context->stop = true;
}
-static char *parseTime(log_time &t, const char *cp) {
-
- char *ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
- if (ep) {
- return ep;
- }
+static char* parseTime(log_time& t, const char* cp) {
+ char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
+ if (ep) return ep;
ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
- if (ep) {
- return ep;
- }
+ if (ep) return ep;
return t.strptime(cp, "%s.%q");
}
// Find last logged line in <outputFileName>, or <outputFileName>.1
-static log_time lastLogTime(char *outputFileName) {
+static log_time lastLogTime(const char* outputFileName) {
log_time retval(log_time::EPOCH);
- if (!outputFileName) {
- return retval;
- }
+ if (!outputFileName) return retval;
std::string directory;
- char *file = strrchr(outputFileName, '/');
+ const char* file = strrchr(outputFileName, '/');
if (!file) {
directory = ".";
file = outputFileName;
} else {
- *file = '\0';
- directory = outputFileName;
- *file = '/';
+ directory = std::string(outputFileName, file - outputFileName);
++file;
}
- std::unique_ptr<DIR, int(*)(DIR*)>
- dir(opendir(directory.c_str()), closedir);
- if (!dir.get()) {
- return retval;
- }
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
+ closedir);
+ if (!dir.get()) return retval;
log_time now(android_log_clockid());
size_t len = strlen(file);
log_time modulo(0, NS_PER_SEC);
- struct dirent *dp;
+ struct dirent* dp;
- while ((dp = readdir(dir.get())) != NULL) {
- if ((dp->d_type != DT_REG) ||
- (strncmp(dp->d_name, file, len) != 0) ||
- (dp->d_name[len] &&
- ((dp->d_name[len] != '.') ||
- (strtoll(dp->d_name + 1, NULL, 10) != 1)))) {
+ while (!!(dp = readdir(dir.get()))) {
+ if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
+ (dp->d_name[len] && ((dp->d_name[len] != '.') ||
+ (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
continue;
}
@@ -540,17 +670,13 @@
file_name += "/";
file_name += dp->d_name;
std::string file;
- if (!android::base::ReadFileToString(file_name, &file)) {
- continue;
- }
+ if (!android::base::ReadFileToString(file_name, &file)) continue;
bool found = false;
for (const auto& line : android::base::Split(file, "\n")) {
log_time t(log_time::EPOCH);
- char *ep = parseTime(t, line.c_str());
- if (!ep || (*ep != ' ')) {
- continue;
- }
+ char* ep = parseTime(t, line.c_str());
+ if (!ep || (*ep != ' ')) continue;
// determine the time precision of the logs (eg: msec or usec)
for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
if (t.tv_nsec % (mod * 10)) {
@@ -568,38 +694,39 @@
}
}
// We count on the basename file to be the definitive end, so stop here.
- if (!dp->d_name[len] && found) {
- break;
- }
+ if (!dp->d_name[len] && found) break;
}
- if (retval == log_time::EPOCH) {
- return retval;
- }
+ if (retval == log_time::EPOCH) return retval;
// tail_time prints matching or higher, round up by the modulo to prevent
// a replay of the last entry we have just checked.
retval += modulo;
return retval;
}
-} /* namespace android */
+const char* getenv(android_logcat_context_internal* context, const char* name) {
+ if (!context->envp || !name || !*name) return nullptr;
-void reportErrorName(const char **current,
- const char* name,
- bool blockSecurity) {
- if (*current) {
- return;
+ for (size_t len = strlen(name), i = 0; context->envp[i]; ++i) {
+ if (strncmp(context->envp[i], name, len)) continue;
+ if (context->envp[i][len] == '=') return &context->envp[i][len + 1];
}
- if (blockSecurity && (android_name_to_log_id(name) == LOG_ID_SECURITY)) {
- return;
- }
- *current = name;
+ return nullptr;
}
-int main(int argc, char **argv)
-{
+} // namespace android
+
+void reportErrorName(const char** current, const char* name,
+ bool blockSecurity) {
+ if (*current) return;
+ if (!blockSecurity || (android_name_to_log_id(name) != LOG_ID_SECURITY)) {
+ *current = name;
+ }
+}
+
+static int __logcat(android_logcat_context_internal* context) {
using namespace android;
int err;
- int hasSetLogFormat = 0;
+ bool hasSetLogFormat = false;
bool clearLog = false;
bool allSelected = false;
bool getLogSize = false;
@@ -607,27 +734,129 @@
bool printStatistics = false;
bool printDividers = false;
unsigned long setLogSize = 0;
- char *setPruneList = NULL;
- char *setId = NULL;
+ const char* setPruneList = nullptr;
+ const char* setId = nullptr;
int mode = ANDROID_LOG_RDONLY;
- const char *forceFilters = NULL;
- log_device_t* devices = NULL;
+ std::string forceFilters;
log_device_t* dev;
- struct logger_list *logger_list;
+ struct logger_list* logger_list;
size_t tail_lines = 0;
log_time tail_time(log_time::EPOCH);
size_t pid = 0;
bool got_t = false;
- signal(SIGPIPE, exit);
+ // object instantiations before goto's can happen
+ log_device_t unexpected("unexpected", false);
+ const char* openDeviceFail = nullptr;
+ const char* clearFail = nullptr;
+ const char* setSizeFail = nullptr;
+ const char* getSizeFail = nullptr;
+ int argc = context->argc;
+ char* const* argv = context->argv;
- g_logformat = android_log_format_new();
+ context->output = stdout;
+ context->error = stderr;
- if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
- show_help(argv[0]);
- return EXIT_SUCCESS;
+ for (int i = 0; i < argc; ++i) {
+ // Simulate shell stderr redirect parsing
+ if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue;
+
+ // Append to file not implemented, just open file
+ size_t skip = (argv[i][2] == '>') + 2;
+ if (!strcmp(&argv[i][skip], "/dev/null")) {
+ context->stderr_null = true;
+ } else if (!strcmp(&argv[i][skip], "&1")) {
+ context->stderr_stdout = true;
+ } else {
+ // stderr file redirections are not supported
+ fprintf(context->stderr_stdout ? stdout : stderr,
+ "stderr redirection to file %s unsupported, skipping\n",
+ &argv[i][skip]);
+ }
+ // Only the first one
+ break;
}
+ const char* filename = nullptr;
+ for (int i = 0; i < argc; ++i) {
+ // Simulate shell stdout redirect parsing
+ if (argv[i][0] != '>') continue;
+
+ // Append to file not implemented, just open file
+ filename = &argv[i][(argv[i][1] == '>') + 1];
+ // Only the first one
+ break;
+ }
+
+ // Deal with setting up file descriptors and FILE pointers
+ if (context->error_fd >= 0) { // Is an error file descriptor supplied?
+ if (context->error_fd == context->output_fd) {
+ context->stderr_stdout = true;
+ } else if (context->stderr_null) { // redirection told us to close it
+ close(context->error_fd);
+ context->error_fd = -1;
+ } else { // All Ok, convert error to a FILE pointer
+ context->error = fdopen(context->error_fd, "web");
+ if (!context->error) {
+ context->retval = -errno;
+ fprintf(context->stderr_stdout ? stdout : stderr,
+ "Failed to fdopen(error_fd=%d) %s\n", context->error_fd,
+ strerror(errno));
+ goto exit;
+ }
+ }
+ }
+ if (context->output_fd >= 0) { // Is an output file descriptor supplied?
+ if (filename) { // redirect to file, close supplied file descriptor.
+ close(context->output_fd);
+ context->output_fd = -1;
+ } else { // All Ok, convert output to a FILE pointer
+ context->output = fdopen(context->output_fd, "web");
+ if (!context->output) {
+ context->retval = -errno;
+ fprintf(context->stderr_stdout ? stdout : context->error,
+ "Failed to fdopen(output_fd=%d) %s\n",
+ context->output_fd, strerror(errno));
+ goto exit;
+ }
+ }
+ }
+ if (filename) { // We supplied an output file redirected in command line
+ context->output = fopen(filename, "web");
+ }
+ // Deal with 2>&1
+ if (context->stderr_stdout) context->error = context->output;
+ // Deal with 2>/dev/null
+ if (context->stderr_null) {
+ context->error_fd = -1;
+ context->error = nullptr;
+ }
+ // Only happens if output=stdout or output=filename
+ if ((context->output_fd < 0) && context->output) {
+ context->output_fd = fileno(context->output);
+ }
+ // Only happens if error=stdout || error=stderr
+ if ((context->error_fd < 0) && context->error) {
+ context->error_fd = fileno(context->error);
+ }
+
+ context->logformat = android_log_format_new();
+
+ if (argc == 2 && !strcmp(argv[1], "--help")) {
+ show_help(context);
+ context->retval = EXIT_SUCCESS;
+ goto exit;
+ }
+
+ // meant to catch comma-delimited values, but cast a wider
+ // net for stability dealing with possible mistaken inputs.
+ static const char delimiters[] = ",:; \t\n\r\f";
+
+ struct getopt_context optctx;
+ INIT_GETOPT_CONTEXT(optctx);
+ optctx.opterr = !!context->error;
+ optctx.optstderr = context->error;
+
for (;;) {
int ret;
@@ -638,66 +867,71 @@
static const char id_str[] = "id";
static const char wrap_str[] = "wrap";
static const char print_str[] = "print";
+ // clang-format off
static const struct option long_options[] = {
- { "binary", no_argument, NULL, 'B' },
- { "buffer", required_argument, NULL, 'b' },
- { "buffer-size", optional_argument, NULL, 'g' },
- { "clear", no_argument, NULL, 'c' },
- { debug_str, no_argument, NULL, 0 },
- { "dividers", no_argument, NULL, 'D' },
- { "file", required_argument, NULL, 'f' },
- { "format", required_argument, NULL, 'v' },
+ { "binary", no_argument, nullptr, 'B' },
+ { "buffer", required_argument, nullptr, 'b' },
+ { "buffer-size", optional_argument, nullptr, 'g' },
+ { "clear", no_argument, nullptr, 'c' },
+ { debug_str, no_argument, nullptr, 0 },
+ { "dividers", no_argument, nullptr, 'D' },
+ { "file", required_argument, nullptr, 'f' },
+ { "format", required_argument, nullptr, 'v' },
// hidden and undocumented reserved alias for --regex
- { "grep", required_argument, NULL, 'e' },
+ { "grep", required_argument, nullptr, 'e' },
// hidden and undocumented reserved alias for --max-count
- { "head", required_argument, NULL, 'm' },
- { id_str, required_argument, NULL, 0 },
- { "last", no_argument, NULL, 'L' },
- { "max-count", required_argument, NULL, 'm' },
- { pid_str, required_argument, NULL, 0 },
- { print_str, no_argument, NULL, 0 },
- { "prune", optional_argument, NULL, 'p' },
- { "regex", required_argument, NULL, 'e' },
- { "rotate-count", required_argument, NULL, 'n' },
- { "rotate-kbytes", required_argument, NULL, 'r' },
- { "statistics", no_argument, NULL, 'S' },
+ { "head", required_argument, nullptr, 'm' },
+ { id_str, required_argument, nullptr, 0 },
+ { "last", no_argument, nullptr, 'L' },
+ { "max-count", required_argument, nullptr, 'm' },
+ { pid_str, required_argument, nullptr, 0 },
+ { print_str, no_argument, nullptr, 0 },
+ { "prune", optional_argument, nullptr, 'p' },
+ { "regex", required_argument, nullptr, 'e' },
+ { "rotate-count", required_argument, nullptr, 'n' },
+ { "rotate-kbytes", required_argument, nullptr, 'r' },
+ { "statistics", no_argument, nullptr, 'S' },
// hidden and undocumented reserved alias for -t
- { "tail", required_argument, NULL, 't' },
+ { "tail", required_argument, nullptr, 't' },
// support, but ignore and do not document, the optional argument
- { wrap_str, optional_argument, NULL, 0 },
- { NULL, 0, NULL, 0 }
+ { wrap_str, optional_argument, nullptr, 0 },
+ { nullptr, 0, nullptr, 0 }
};
+ // clang-format on
- ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:m:e:",
- long_options, &option_index);
-
- if (ret < 0) {
- break;
- }
+ ret = getopt_long_r(argc, argv,
+ ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
+ &option_index, &optctx);
+ if (ret < 0) break;
switch (ret) {
case 0:
// only long options
if (long_options[option_index].name == pid_str) {
// ToDo: determine runtime PID_MAX?
- if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
+ if (!getSizeTArg(optctx.optarg, &pid, 1)) {
+ logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name,
+ optctx.optarg);
+ goto exit;
}
break;
}
if (long_options[option_index].name == wrap_str) {
- mode |= ANDROID_LOG_WRAP |
- ANDROID_LOG_RDONLY |
+ mode |= ANDROID_LOG_WRAP | ANDROID_LOG_RDONLY |
ANDROID_LOG_NONBLOCK;
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
- if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
+ if (optctx.optarg &&
+ !getSizeTArg(optctx.optarg, &dummy, 1)) {
+ logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name,
+ optctx.optarg);
+ goto exit;
}
- if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
- fprintf(stderr,
+ if ((dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) &&
+ context->error) {
+ fprintf(context->error,
"WARNING: %s %u seconds, ignoring %zu\n",
long_options[option_index].name,
ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
@@ -705,305 +939,316 @@
break;
}
if (long_options[option_index].name == print_str) {
- g_printItAnyways = true;
+ context->printItAnyways = true;
break;
}
if (long_options[option_index].name == debug_str) {
- g_debug = true;
+ context->debug = true;
break;
}
if (long_options[option_index].name == id_str) {
- setId = optarg && optarg[0] ? optarg : NULL;
- break;
+ setId = (optctx.optarg && optctx.optarg[0]) ? optctx.optarg
+ : nullptr;
}
- break;
+ break;
case 's':
// default to all silent
- android_log_addFilterRule(g_logformat, "*:s");
- break;
+ android_log_addFilterRule(context->logformat, "*:s");
+ break;
case 'c':
clearLog = true;
mode |= ANDROID_LOG_WRONLY;
- break;
+ break;
case 'L':
- mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
- break;
+ mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE |
+ ANDROID_LOG_NONBLOCK;
+ break;
case 'd':
mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
- break;
+ break;
case 't':
got_t = true;
mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
- /* FALLTHRU */
+ // FALLTHRU
case 'T':
- if (strspn(optarg, "0123456789") != strlen(optarg)) {
- char *cp = parseTime(tail_time, optarg);
+ if (strspn(optctx.optarg, "0123456789") !=
+ strlen(optctx.optarg)) {
+ char* cp = parseTime(tail_time, optctx.optarg);
if (!cp) {
- logcat_panic(HELP_FALSE,
- "-%c \"%s\" not in time format\n",
- ret, optarg);
+ logcat_panic(context, HELP_FALSE,
+ "-%c \"%s\" not in time format\n", ret,
+ optctx.optarg);
+ goto exit;
}
if (*cp) {
char c = *cp;
*cp = '\0';
- fprintf(stderr,
+ if (context->error) {
+ fprintf(
+ context->error,
"WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
- ret, optarg, c, cp + 1);
+ ret, optctx.optarg, c, cp + 1);
+ }
*cp = c;
}
} else {
- if (!getSizeTArg(optarg, &tail_lines, 1)) {
- fprintf(stderr,
- "WARNING: -%c %s invalid, setting to 1\n",
- ret, optarg);
+ if (!getSizeTArg(optctx.optarg, &tail_lines, 1)) {
+ if (context->error) {
+ fprintf(context->error,
+ "WARNING: -%c %s invalid, setting to 1\n",
+ ret, optctx.optarg);
+ }
tail_lines = 1;
}
}
- break;
+ break;
case 'D':
printDividers = true;
- break;
+ break;
case 'e':
- g_regex = new pcrecpp::RE(optarg);
- break;
+ context->regex = new pcrecpp::RE(optctx.optarg);
+ break;
case 'm': {
- char *end = NULL;
- if (!getSizeTArg(optarg, &g_maxCount)) {
- logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
- "integer greater than zero\n", ret, optarg);
+ char* end = nullptr;
+ if (!getSizeTArg(optctx.optarg, &context->maxCount)) {
+ logcat_panic(context, HELP_FALSE,
+ "-%c \"%s\" isn't an "
+ "integer greater than zero\n",
+ ret, optctx.optarg);
+ goto exit;
}
- }
- break;
+ } break;
case 'g':
- if (!optarg) {
+ if (!optctx.optarg) {
getLogSize = true;
break;
}
- // FALLTHRU
+ // FALLTHRU
case 'G': {
- char *cp;
- if (strtoll(optarg, &cp, 0) > 0) {
- setLogSize = strtoll(optarg, &cp, 0);
+ char* cp;
+ if (strtoll(optctx.optarg, &cp, 0) > 0) {
+ setLogSize = strtoll(optctx.optarg, &cp, 0);
} else {
setLogSize = 0;
}
- switch(*cp) {
- case 'g':
- case 'G':
- setLogSize *= 1024;
- /* FALLTHRU */
- case 'm':
- case 'M':
- setLogSize *= 1024;
- /* FALLTHRU */
- case 'k':
- case 'K':
- setLogSize *= 1024;
- /* FALLTHRU */
- case '\0':
- break;
+ switch (*cp) {
+ case 'g':
+ case 'G':
+ setLogSize *= 1024;
+ // FALLTHRU
+ case 'm':
+ case 'M':
+ setLogSize *= 1024;
+ // FALLTHRU
+ case 'k':
+ case 'K':
+ setLogSize *= 1024;
+ // FALLTHRU
+ case '\0':
+ break;
- default:
- setLogSize = 0;
+ default:
+ setLogSize = 0;
}
if (!setLogSize) {
- fprintf(stderr, "ERROR: -G <num><multiplier>\n");
- return EXIT_FAILURE;
+ logcat_panic(context, HELP_FALSE,
+ "ERROR: -G <num><multiplier>\n");
+ goto exit;
}
- }
- break;
+ } break;
case 'p':
- if (!optarg) {
+ if (!optctx.optarg) {
getPruneList = true;
break;
}
- // FALLTHRU
+ // FALLTHRU
case 'P':
- setPruneList = optarg;
- break;
+ setPruneList = optctx.optarg;
+ break;
case 'b': {
+ std::unique_ptr<char, void (*)(void*)> buffers(
+ strdup(optctx.optarg), free);
+ char* arg = buffers.get();
unsigned idMask = 0;
- while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
- if (strcmp(optarg, "default") == 0) {
- idMask |= (1 << LOG_ID_MAIN) |
- (1 << LOG_ID_SYSTEM) |
+ char* sv = nullptr; // protect against -ENOMEM above
+ while (!!(arg = strtok_r(arg, delimiters, &sv))) {
+ if (!strcmp(arg, "default")) {
+ idMask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) |
(1 << LOG_ID_CRASH);
- } else if (strcmp(optarg, "all") == 0) {
+ } else if (!strcmp(arg, "all")) {
allSelected = true;
idMask = (unsigned)-1;
} else {
- log_id_t log_id = android_name_to_log_id(optarg);
- const char *name = android_log_id_to_name(log_id);
+ log_id_t log_id = android_name_to_log_id(arg);
+ const char* name = android_log_id_to_name(log_id);
- if (strcmp(name, optarg) != 0) {
- logcat_panic(HELP_TRUE,
- "unknown buffer %s\n", optarg);
+ if (!!strcmp(name, arg)) {
+ logcat_panic(context, HELP_TRUE,
+ "unknown buffer %s\n", arg);
+ goto exit;
}
if (log_id == LOG_ID_SECURITY) allSelected = false;
idMask |= (1 << log_id);
}
- optarg = NULL;
+ arg = nullptr;
}
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- const char *name = android_log_id_to_name((log_id_t)i);
+ const char* name = android_log_id_to_name((log_id_t)i);
log_id_t log_id = android_name_to_log_id(name);
- if (log_id != (log_id_t)i) {
- continue;
- }
- if ((idMask & (1 << i)) == 0) {
- continue;
- }
+ if (log_id != (log_id_t)i) continue;
+ if (!(idMask & (1 << i))) continue;
bool found = false;
- for (dev = devices; dev; dev = dev->next) {
+ for (dev = context->devices; dev; dev = dev->next) {
if (!strcmp(name, dev->device)) {
found = true;
break;
}
- if (!dev->next) {
- break;
- }
+ if (!dev->next) break;
}
- if (found) {
- continue;
- }
+ if (found) continue;
- bool binary = !strcmp(name, "events") ||
- !strcmp(name, "security");
+ bool binary =
+ !strcmp(name, "events") || !strcmp(name, "security");
log_device_t* d = new log_device_t(name, binary);
if (dev) {
dev->next = d;
dev = d;
} else {
- devices = dev = d;
+ context->devices = dev = d;
}
- g_devCount++;
+ context->devCount++;
}
- }
- break;
+ } break;
case 'B':
- g_printBinary = 1;
- break;
+ context->printBinary = 1;
+ break;
case 'f':
- if ((tail_time == log_time::EPOCH) && (tail_lines == 0)) {
- tail_time = lastLogTime(optarg);
+ if ((tail_time == log_time::EPOCH) && !tail_lines) {
+ tail_time = lastLogTime(optctx.optarg);
}
// redirect output to a file
- g_outputFileName = optarg;
- break;
+ context->outputFileName = optctx.optarg;
+ break;
case 'r':
- if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
- logcat_panic(HELP_TRUE,
- "Invalid parameter \"%s\" to -r\n", optarg);
+ if (!getSizeTArg(optctx.optarg, &context->logRotateSizeKBytes,
+ 1)) {
+ logcat_panic(context, HELP_TRUE,
+ "Invalid parameter \"%s\" to -r\n",
+ optctx.optarg);
+ goto exit;
}
- break;
+ break;
case 'n':
- if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
- logcat_panic(HELP_TRUE,
- "Invalid parameter \"%s\" to -n\n", optarg);
+ if (!getSizeTArg(optctx.optarg, &context->maxRotatedLogs, 1)) {
+ logcat_panic(context, HELP_TRUE,
+ "Invalid parameter \"%s\" to -n\n",
+ optctx.optarg);
+ goto exit;
}
- break;
+ break;
- case 'v':
- if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
- show_format_help();
- exit(0);
+ case 'v': {
+ if (!strcmp(optctx.optarg, "help") ||
+ !strcmp(optctx.optarg, "--help")) {
+ show_format_help(context);
+ context->retval = EXIT_SUCCESS;
+ goto exit;
}
- err = setLogFormat(optarg);
- if (err < 0) {
- logcat_panic(HELP_FORMAT,
- "Invalid parameter \"%s\" to -v\n", optarg);
+ std::unique_ptr<char, void (*)(void*)> formats(
+ strdup(optctx.optarg), free);
+ char* arg = formats.get();
+ unsigned idMask = 0;
+ char* sv = nullptr; // protect against -ENOMEM above
+ while (!!(arg = strtok_r(arg, delimiters, &sv))) {
+ err = setLogFormat(context, arg);
+ if (err < 0) {
+ logcat_panic(context, HELP_FORMAT,
+ "Invalid parameter \"%s\" to -v\n", arg);
+ goto exit;
+ }
+ arg = nullptr;
+ if (err) hasSetLogFormat = true;
}
- hasSetLogFormat |= err;
- break;
+ } break;
case 'Q':
- /* this is a *hidden* option used to start a version of logcat */
- /* in an emulated device only. it basically looks for androidboot.logcat= */
- /* on the kernel command line. If something is found, it extracts a log filter */
- /* and uses it to run the program. If nothing is found, the program should */
- /* quit immediately */
-#define KERNEL_OPTION "androidboot.logcat="
-#define CONSOLE_OPTION "androidboot.console="
+#define KERNEL_OPTION "androidboot.logcat="
+#define CONSOLE_OPTION "androidboot.console="
+ // This is a *hidden* option used to start a version of logcat
+ // in an emulated device only. It basically looks for
+ // androidboot.logcat= on the kernel command line. If
+ // something is found, it extracts a log filter and uses it to
+ // run the program. If nothing is found, the program should
+ // quit immediately.
{
- int fd;
- char* logcat;
- char* console;
- int force_exit = 1;
- static char cmdline[1024];
+ std::string cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
- fd = open("/proc/cmdline", O_RDONLY);
- if (fd >= 0) {
- int n = read(fd, cmdline, sizeof(cmdline)-1 );
- if (n < 0) n = 0;
- cmdline[n] = 0;
- close(fd);
- } else {
- cmdline[0] = 0;
+ const char* logcat = strstr(cmdline.c_str(), KERNEL_OPTION);
+ // if nothing found or invalid filters, exit quietly
+ if (!logcat) {
+ context->retval = EXIT_SUCCESS;
+ goto exit;
}
- logcat = strstr( cmdline, KERNEL_OPTION );
- console = strstr( cmdline, CONSOLE_OPTION );
- if (logcat != NULL) {
- char* p = logcat + sizeof(KERNEL_OPTION)-1;;
- char* q = strpbrk( p, " \t\n\r" );;
+ const char* p = logcat + strlen(KERNEL_OPTION);
+ const char* q = strpbrk(p, " \t\n\r");
+ if (!q) q = p + strlen(p);
+ forceFilters = std::string(p, q);
- if (q != NULL)
- *q = 0;
+ // redirect our output to the emulator console
+ const char* console =
+ strstr(cmdline.c_str(), CONSOLE_OPTION);
+ if (!console) break;
- forceFilters = p;
- force_exit = 0;
- }
- /* if nothing found or invalid filters, exit quietly */
- if (force_exit) {
- return EXIT_SUCCESS;
+ p = console + strlen(CONSOLE_OPTION);
+ q = strpbrk(p, " \t\n\r");
+ int len = q ? q - p : strlen(p);
+ std::string devname = "/dev/" + std::string(p, len);
+ cmdline.erase();
+
+ if (context->error) {
+ fprintf(context->error, "logcat using %s\n",
+ devname.c_str());
}
- /* redirect our output to the emulator console */
- if (console) {
- char* p = console + sizeof(CONSOLE_OPTION)-1;
- char* q = strpbrk( p, " \t\n\r" );
- char devname[64];
- int len;
+ FILE* fp = fopen(devname.c_str(), "web");
+ devname.erase();
+ if (!fp) break;
- if (q != NULL) {
- len = q - p;
- } else
- len = strlen(p);
-
- len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
- fprintf(stderr, "logcat using %s (%d)\n", devname, len);
- if (len < (int)sizeof(devname)) {
- fd = open( devname, O_WRONLY );
- if (fd >= 0) {
- dup2(fd, 1);
- dup2(fd, 2);
- close(fd);
- }
- }
- }
+ // close output and error channels, replace with console
+ android::close_output(context);
+ android::close_error(context);
+ context->stderr_stdout = true;
+ context->output = fp;
+ context->output_fd = fileno(fp);
+ if (context->stderr_null) break;
+ context->stderr_stdout = true;
+ context->error = fp;
+ context->error_fd = fileno(fp);
}
break;
@@ -1012,117 +1257,138 @@
break;
case ':':
- logcat_panic(HELP_TRUE,
- "Option -%c needs an argument\n", optopt);
- break;
+ logcat_panic(context, HELP_TRUE,
+ "Option -%c needs an argument\n", optctx.optopt);
+ goto exit;
default:
- logcat_panic(HELP_TRUE,
- "Unrecognized Option %c\n", optopt);
- break;
+ logcat_panic(context, HELP_TRUE, "Unrecognized Option %c\n",
+ optctx.optopt);
+ goto exit;
}
}
- if (g_maxCount && got_t) {
- logcat_panic(HELP_TRUE,
+ if (context->maxCount && got_t) {
+ logcat_panic(context, HELP_TRUE,
"Cannot use -m (--max-count) and -t together\n");
+ goto exit;
}
- if (g_printItAnyways && (!g_regex || !g_maxCount)) {
+ if (context->printItAnyways && (!context->regex || !context->maxCount)) {
// One day it would be nice if --print -v color and --regex <expr>
// could play with each other and show regex highlighted content.
- fprintf(stderr, "WARNING: "
+ // clang-format off
+ if (context->error) {
+ fprintf(context->error, "WARNING: "
"--print ignored, to be used in combination with\n"
- " "
+ " "
"--regex <expr> and --max-count <N>\n");
- g_printItAnyways = false;
+ }
+ context->printItAnyways = false;
}
- if (!devices) {
- dev = devices = new log_device_t("main", false);
- g_devCount = 1;
+ if (!context->devices) {
+ dev = context->devices = new log_device_t("main", false);
+ context->devCount = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
dev = dev->next = new log_device_t("system", false);
- g_devCount++;
+ context->devCount++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
dev = dev->next = new log_device_t("crash", false);
- g_devCount++;
+ context->devCount++;
}
}
- if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
- logcat_panic(HELP_TRUE, "-r requires -f as well\n");
+ if (!!context->logRotateSizeKBytes && !context->outputFileName) {
+ logcat_panic(context, HELP_TRUE, "-r requires -f as well\n");
+ goto exit;
}
- if (setId != NULL) {
- if (g_outputFileName == NULL) {
- logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
+ if (!!setId) {
+ if (!context->outputFileName) {
+ logcat_panic(context, HELP_TRUE,
+ "--id='%s' requires -f as well\n", setId);
+ goto exit;
}
- std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
+ std::string file_name = android::base::StringPrintf(
+ "%s.id", context->outputFileName);
std::string file;
bool file_ok = android::base::ReadFileToString(file_name, &file);
- android::base::WriteStringToFile(setId, file_name,
- S_IRUSR | S_IWUSR, getuid(), getgid());
- if (!file_ok || (file.compare(setId) == 0)) {
- setId = NULL;
- }
+ android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
+ getuid(), getgid());
+ if (!file_ok || !file.compare(setId)) setId = nullptr;
}
- if (hasSetLogFormat == 0) {
- const char* logFormat = getenv("ANDROID_PRINTF_LOG");
+ if (!hasSetLogFormat) {
+ const char* logFormat = android::getenv(context, "ANDROID_PRINTF_LOG");
- if (logFormat != NULL) {
- err = setLogFormat(logFormat);
- if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
- logFormat);
+ if (!!logFormat) {
+ std::unique_ptr<char, void (*)(void*)> formats(strdup(logFormat),
+ free);
+ char* sv = nullptr; // protect against -ENOMEM above
+ char* arg = formats.get();
+ while (!!(arg = strtok_r(arg, delimiters, &sv))) {
+ err = setLogFormat(context, arg);
+ // environment should not cause crash of logcat
+ if ((err < 0) && context->error) {
+ fprintf(context->error,
+ "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
+ }
+ arg = nullptr;
+ if (err > 0) hasSetLogFormat = true;
}
- } else {
- setLogFormat("threadtime");
+ }
+ if (!hasSetLogFormat) {
+ setLogFormat(context, "threadtime");
}
}
- if (forceFilters) {
- err = android_log_addFilterString(g_logformat, forceFilters);
+ if (forceFilters.size()) {
+ err = android_log_addFilterString(context->logformat,
+ forceFilters.c_str());
if (err < 0) {
- logcat_panic(HELP_FALSE,
+ logcat_panic(context, HELP_FALSE,
"Invalid filter expression in logcat args\n");
+ goto exit;
}
- } else if (argc == optind) {
+ } else if (argc == optctx.optind) {
// Add from environment variable
- char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
+ const char* env_tags_orig = android::getenv(context, "ANDROID_LOG_TAGS");
- if (env_tags_orig != NULL) {
- err = android_log_addFilterString(g_logformat, env_tags_orig);
+ if (!!env_tags_orig) {
+ err = android_log_addFilterString(context->logformat,
+ env_tags_orig);
if (err < 0) {
- logcat_panic(HELP_TRUE,
+ logcat_panic(context, HELP_TRUE,
"Invalid filter expression in ANDROID_LOG_TAGS\n");
+ goto exit;
}
}
} else {
// Add from commandline
- for (int i = optind ; i < argc ; i++) {
- err = android_log_addFilterString(g_logformat, argv[i]);
+ for (int i = optctx.optind ; i < argc ; i++) {
+ // skip stderr redirections of _all_ kinds
+ if ((argv[i][0] == '2') && (argv[i][1] == '>')) continue;
+ // skip stdout redirections of _all_ kinds
+ if (argv[i][0] == '>') continue;
+ err = android_log_addFilterString(context->logformat, argv[i]);
if (err < 0) {
- logcat_panic(HELP_TRUE,
+ logcat_panic(context, HELP_TRUE,
"Invalid filter expression '%s'\n", argv[i]);
+ goto exit;
}
}
}
- dev = devices;
+ dev = context->devices;
if (tail_time != log_time::EPOCH) {
logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
} else {
logger_list = android_logger_list_alloc(mode, tail_lines, pid);
}
- const char *openDeviceFail = NULL;
- const char *clearFail = NULL;
- const char *setSizeFail = NULL;
- const char *getSizeFail = NULL;
// We have three orthogonal actions below to clear, set log size and
// get log size. All sharing the same iteration loop.
while (dev) {
@@ -1136,21 +1402,24 @@
}
if (clearLog || setId) {
- if (g_outputFileName) {
+ if (context->outputFileName) {
int maxRotationCountDigits =
- (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
+ (context->maxRotatedLogs > 0) ?
+ (int)(floor(log10(context->maxRotatedLogs) + 1)) :
+ 0;
- for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
+ for (int i = context->maxRotatedLogs ; i >= 0 ; --i) {
std::string file;
- if (i == 0) {
- file = android::base::StringPrintf("%s", g_outputFileName);
+ if (!i) {
+ file = android::base::StringPrintf(
+ "%s", context->outputFileName);
} else {
file = android::base::StringPrintf("%s.%.*d",
- g_outputFileName, maxRotationCountDigits, i);
+ context->outputFileName, maxRotationCountDigits, i);
}
- if (file.length() == 0) {
+ if (!file.length()) {
perror("while clearing log files");
reportErrorName(&clearFail, dev->device, allSelected);
break;
@@ -1158,7 +1427,7 @@
err = unlink(file.c_str());
- if (err < 0 && errno != ENOENT && clearFail == NULL) {
+ if (err < 0 && errno != ENOENT && !clearFail) {
perror("while clearing log files");
reportErrorName(&clearFail, dev->device, allSelected);
}
@@ -1181,67 +1450,80 @@
if ((size < 0) || (readable < 0)) {
reportErrorName(&getSizeFail, dev->device, allSelected);
} else {
- printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
- "max entry is %db, max payload is %db\n", dev->device,
+ std::string str = android::base::StringPrintf(
+ "%s: ring buffer is %ld%sb (%ld%sb consumed),"
+ " max entry is %db, max payload is %db\n",
+ dev->device,
value_of_size(size), multiplier_of_size(size),
value_of_size(readable), multiplier_of_size(readable),
- (int) LOGGER_ENTRY_MAX_LEN,
- (int) LOGGER_ENTRY_MAX_PAYLOAD);
+ (int)LOGGER_ENTRY_MAX_LEN,
+ (int)LOGGER_ENTRY_MAX_PAYLOAD);
+ TEMP_FAILURE_RETRY(write(context->output_fd,
+ str.data(), str.length()));
}
}
dev = dev->next;
}
+
+ context->retval = EXIT_SUCCESS;
+
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(HELP_FALSE,
+ logcat_panic(context, HELP_FALSE,
"Unable to open log device '%s'\n", openDeviceFail);
+ goto close;
}
if (clearFail) {
- logcat_panic(HELP_FALSE,
+ logcat_panic(context, HELP_FALSE,
"failed to clear the '%s' log\n", clearFail);
+ goto close;
}
if (setSizeFail) {
- logcat_panic(HELP_FALSE,
+ logcat_panic(context, HELP_FALSE,
"failed to set the '%s' log size\n", setSizeFail);
+ goto close;
}
if (getSizeFail) {
- logcat_panic(HELP_FALSE,
+ logcat_panic(context, HELP_FALSE,
"failed to get the readable '%s' log size", getSizeFail);
+ goto close;
}
if (setPruneList) {
size_t len = strlen(setPruneList);
- /*extra 32 bytes are needed by android_logger_set_prune_list */
+ // extra 32 bytes are needed by android_logger_set_prune_list
size_t bLen = len + 32;
- char *buf = NULL;
+ char* buf = nullptr;
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(HELP_FALSE, "failed to set the prune list");
+ logcat_panic(context, HELP_FALSE,
+ "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
+ logcat_panic(context, HELP_FALSE,
+ "failed to set the prune list (alloc)");
}
+ goto close;
}
if (printStatistics || getPruneList) {
size_t len = 8192;
- char *buf;
+ char* buf;
- for (int retry = 32;
- (retry >= 0) && ((buf = new char [len]));
- delete [] buf, buf = NULL, --retry) {
+ for (int retry = 32; (retry >= 0) && ((buf = new char[len]));
+ delete[] buf, buf = nullptr, --retry) {
if (getPruneList) {
android_logger_get_prune_list(logger_list, buf, len);
} else {
android_logger_get_statistics(logger_list, buf, len);
}
- buf[len-1] = '\0';
+ buf[len - 1] = '\0';
if (atol(buf) < 3) {
- delete [] buf;
- buf = NULL;
+ delete[] buf;
+ buf = nullptr;
break;
}
size_t ret = atol(buf) + 1;
@@ -1253,98 +1535,282 @@
}
if (!buf) {
- logcat_panic(HELP_FALSE, "failed to read data");
+ logcat_panic(context, HELP_FALSE, "failed to read data");
+ goto close;
}
// remove trailing FF
- char *cp = buf + len - 1;
+ char* cp = buf + len - 1;
*cp = '\0';
bool truncated = *--cp != '\f';
- if (!truncated) {
- *cp = '\0';
- }
+ if (!truncated) *cp = '\0';
// squash out the byte count
cp = buf;
if (!truncated) {
- while (isdigit(*cp)) {
- ++cp;
- }
- if (*cp == '\n') {
- ++cp;
- }
+ while (isdigit(*cp)) ++cp;
+ if (*cp == '\n') ++cp;
}
- printf("%s", cp);
- delete [] buf;
- return EXIT_SUCCESS;
+ len = strlen(cp);
+ TEMP_FAILURE_RETRY(write(context->output_fd, cp, len));
+ delete[] buf;
+ goto close;
}
- if (getLogSize) {
- return EXIT_SUCCESS;
- }
- if (setLogSize || setPruneList) {
- return EXIT_SUCCESS;
- }
- if (clearLog) {
- return EXIT_SUCCESS;
- }
+ if (getLogSize || setLogSize || clearLog) goto close;
- setupOutputAndSchedulingPolicy((mode & ANDROID_LOG_NONBLOCK) == 0);
+ setupOutputAndSchedulingPolicy(context, !(mode & ANDROID_LOG_NONBLOCK));
+ if (context->stop) goto close;
- //LOG_EVENT_INT(10, 12345);
- //LOG_EVENT_LONG(11, 0x1122334455667788LL);
- //LOG_EVENT_STRING(0, "whassup, doc?");
+ // LOG_EVENT_INT(10, 12345);
+ // LOG_EVENT_LONG(11, 0x1122334455667788LL);
+ // LOG_EVENT_STRING(0, "whassup, doc?");
- dev = NULL;
- log_device_t unexpected("unexpected", false);
+ dev = nullptr;
- while (!g_maxCount || (g_printCount < g_maxCount)) {
+ while (!context->stop &&
+ (!context->maxCount || (context->printCount < context->maxCount))) {
struct log_msg log_msg;
- log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);
-
- if (ret == 0) {
- logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
+ if (!ret) {
+ logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
+ break;
}
if (ret < 0) {
- if (ret == -EAGAIN) {
- break;
- }
+ if (ret == -EAGAIN) break;
if (ret == -EIO) {
- logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
- }
- if (ret == -EINVAL) {
- logcat_panic(HELP_FALSE, "read: unexpected length.\n");
- }
- logcat_panic(HELP_FALSE, "logcat read failure");
- }
-
- for (d = devices; d; d = d->next) {
- if (android_name_to_log_id(d->device) == log_msg.id()) {
+ logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
break;
}
+ if (ret == -EINVAL) {
+ logcat_panic(context, HELP_FALSE, "read: unexpected length.\n");
+ break;
+ }
+ logcat_panic(context, HELP_FALSE, "logcat read failure");
+ break;
+ }
+
+ log_device_t* d;
+ for (d = context->devices; d; d = d->next) {
+ if (android_name_to_log_id(d->device) == log_msg.id()) break;
}
if (!d) {
- g_devCount = 2; // set to Multiple
+ context->devCount = 2; // set to Multiple
d = &unexpected;
d->binary = log_msg.id() == LOG_ID_EVENTS;
}
if (dev != d) {
dev = d;
- maybePrintStart(dev, printDividers);
+ maybePrintStart(context, dev, printDividers);
+ if (context->stop) break;
}
- if (g_printBinary) {
- printBinary(&log_msg);
+ if (context->printBinary) {
+ printBinary(context, &log_msg);
} else {
- processBuffer(dev, &log_msg);
+ processBuffer(context, dev, &log_msg);
}
}
+close:
+ // Short and sweet. Implemented generic version in android_logcat_destroy.
+ while (!!(dev = context->devices)) {
+ context->devices = dev->next;
+ delete dev;
+ }
android_logger_list_free(logger_list);
- return EXIT_SUCCESS;
+exit:
+ // close write end of pipe to help things along
+ if (context->output_fd == context->fds[1]) {
+ android::close_output(context);
+ }
+ if (context->error_fd == context->fds[1]) {
+ android::close_error(context);
+ }
+ if (context->fds[1] >= 0) {
+ // NB: should be closed by the above
+ int save_errno = errno;
+ close(context->fds[1]);
+ errno = save_errno;
+ context->fds[1] = -1;
+ }
+ context->thread_stopped = true;
+ return context->retval;
+}
+
+// Can block
+int android_logcat_run_command(android_logcat_context ctx,
+ int output, int error,
+ int argc, char* const* argv,
+ char* const* envp) {
+ android_logcat_context_internal* context = ctx;
+
+ context->output_fd = output;
+ context->error_fd = error;
+ context->argc = argc;
+ context->argv = argv;
+ context->envp = envp;
+ context->stop = false;
+ context->thread_stopped = false;
+ return __logcat(context);
+}
+
+// starts a thread, opens a pipe, returns reading end.
+int android_logcat_run_command_thread(android_logcat_context ctx,
+ int argc, char* const* argv,
+ char* const* envp) {
+ android_logcat_context_internal* context = ctx;
+
+ int save_errno = EBUSY;
+ if ((context->fds[0] >= 0) || (context->fds[1] >= 0)) goto exit;
+
+ if (pipe(context->fds) < 0) {
+ save_errno = errno;
+ goto exit;
+ }
+
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr)) {
+ save_errno = errno;
+ goto close_exit;
+ }
+
+ struct sched_param param;
+ memset(¶m, 0, sizeof(param));
+ pthread_attr_setschedparam(&attr, ¶m);
+ pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+ int save_errno = errno;
+ goto pthread_attr_exit;
+ }
+
+ context->stop = false;
+ context->thread_stopped = false;
+ context->output_fd = context->fds[1];
+ // save off arguments so they remain while thread is active.
+ for (int i = 0; i < argc; ++i) {
+ context->args.push_back(std::string(argv[i]));
+ }
+ // save off environment so they remain while thread is active.
+ if (envp) for (size_t i = 0; envp[i]; ++i) {
+ context->envs.push_back(std::string(envp[i]));
+ }
+
+ for (auto& str : context->args) {
+ context->argv_hold.push_back(str.c_str());
+ }
+ context->argv_hold.push_back(nullptr);
+ for (auto& str : context->envs) {
+ context->envp_hold.push_back(str.c_str());
+ }
+ context->envp_hold.push_back(nullptr);
+
+ context->argc = context->argv_hold.size() - 1;
+ context->argv = (char* const*)&context->argv_hold[0];
+ context->envp = (char* const*)&context->envp_hold[0];
+
+#ifdef DEBUG
+ fprintf(stderr, "argv[%d] = {", context->argc);
+ for (auto str : context->argv_hold) {
+ fprintf(stderr, " \"%s\"", str ?: "nullptr");
+ }
+ fprintf(stderr, " }\n");
+ fflush(stderr);
+#endif
+ context->retval = EXIT_SUCCESS;
+ if (pthread_create(&context->thr, &attr,
+ (void*(*)(void*))__logcat, context)) {
+ int save_errno = errno;
+ goto argv_exit;
+ }
+ pthread_attr_destroy(&attr);
+
+ return context->fds[0];
+
+argv_exit:
+ context->argv_hold.clear();
+ context->args.clear();
+ context->envp_hold.clear();
+ context->envs.clear();
+pthread_attr_exit:
+ pthread_attr_destroy(&attr);
+close_exit:
+ close(context->fds[0]);
+ context->fds[0] = -1;
+ close(context->fds[1]);
+ context->fds[1] = -1;
+exit:
+ errno = save_errno;
+ context->stop = true;
+ context->thread_stopped = true;
+ context->retval = EXIT_FAILURE;
+ return -1;
+}
+
+// test if the thread is still doing 'stuff'
+int android_logcat_run_command_thread_running(android_logcat_context ctx) {
+ android_logcat_context_internal* context = ctx;
+
+ return context->thread_stopped == false;
+}
+
+// Finished with context
+int android_logcat_destroy(android_logcat_context* ctx) {
+ android_logcat_context_internal* context = *ctx;
+
+ if (!context) return -EBADF;
+
+ *ctx = nullptr;
+
+ context->stop = true;
+
+ while (context->thread_stopped == false) {
+ // Makes me sad, replace thread_stopped with semaphore. Short lived.
+ sched_yield();
+ }
+
+ delete context->regex;
+ context->argv_hold.clear();
+ context->args.clear();
+ context->envp_hold.clear();
+ context->envs.clear();
+ if (context->fds[0] >= 0) {
+ close(context->fds[0]);
+ context->fds[0] = -1;
+ }
+ android::close_output(context);
+ android::close_error(context);
+ if (context->fds[1] >= 0) {
+ // NB: could be closed by the above fclose(s), ignore error.
+ int save_errno = errno;
+ close(context->fds[1]);
+ errno = save_errno;
+ context->fds[1] = -1;
+ }
+
+ android_closeEventTagMap(context->eventTagMap);
+
+ // generic cleanup of devices list to handle all possible dirty cases
+ log_device_t* dev;
+ while (!!(dev = context->devices)) {
+ struct logger_list* logger_list = dev->logger_list;
+ if (logger_list) {
+ for (log_device_t* d = dev; d; d = d->next) {
+ if (d->logger_list == logger_list) d->logger_list = nullptr;
+ }
+ android_logger_list_free(logger_list);
+ }
+ context->devices = dev->next;
+ delete dev;
+ }
+
+ int retval = context->retval;
+
+ free(context);
+
+ return retval;
}
diff --git a/logcat/logcat_main.cpp b/logcat/logcat_main.cpp
new file mode 100644
index 0000000..9477e79
--- /dev/null
+++ b/logcat/logcat_main.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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 <signal.h>
+#include <stdlib.h>
+
+#include <log/logcat.h>
+
+int main(int argc, char** argv, char** envp) {
+ android_logcat_context ctx = create_android_logcat();
+ if (!ctx) return -1;
+ signal(SIGPIPE, exit);
+ int retval = android_logcat_run_command(ctx, -1, -1, argc, argv, envp);
+ int ret = android_logcat_destroy(&ctx);
+ if (!ret) ret = retval;
+ return ret;
+}
diff --git a/logcat/logcat_system.cpp b/logcat/logcat_system.cpp
new file mode 100644
index 0000000..ea393bd
--- /dev/null
+++ b/logcat/logcat_system.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <log/logcat.h>
+
+static std::string unquote(const char*& cp, const char*& delim) {
+ if ((*cp == '\'') || (*cp == '"')) {
+ // KISS: Simple quotes. Do not handle the case
+ // of concatenation like "blah"foo'bar'
+ char quote = *cp++;
+ delim = strchr(cp, quote);
+ if (!delim) delim = cp + strlen(cp);
+ std::string str(cp, delim);
+ if (*delim) ++delim;
+ return str;
+ }
+ delim = strpbrk(cp, " \t\f\r\n");
+ if (!delim) delim = cp + strlen(cp);
+ return std::string(cp, delim);
+}
+
+static bool __android_logcat_parse(const char* command,
+ std::vector<std::string>& args,
+ std::vector<std::string>& envs) {
+ for (const char *delim, *cp = command; cp && *cp; cp = delim) {
+ while (isspace(*cp)) ++cp;
+ if ((args.size() == 0) && (*cp != '=') && !isdigit(*cp)) {
+ const char* env = cp;
+ while (isalnum(*cp) || (*cp == '_')) ++cp;
+ if (cp && (*cp == '=')) {
+ std::string str(env, ++cp);
+ str += unquote(cp, delim);
+ envs.push_back(str);
+ continue;
+ }
+ cp = env;
+ }
+ args.push_back(unquote(cp, delim));
+ if ((args.size() == 1) && (args[0] != "logcat") &&
+ (args[0] != "/system/bin/logcat")) {
+ return false;
+ }
+ }
+ return args.size() != 0;
+}
+
+FILE* android_logcat_popen(android_logcat_context* ctx, const char* command) {
+ *ctx = NULL;
+
+ std::vector<std::string> args;
+ std::vector<std::string> envs;
+ if (!__android_logcat_parse(command, args, envs)) return NULL;
+
+ std::vector<const char*> argv;
+ for (auto& str : args) {
+ argv.push_back(str.c_str());
+ }
+ argv.push_back(NULL);
+
+ std::vector<const char*> envp;
+ for (auto& str : envs) {
+ envp.push_back(str.c_str());
+ }
+ envp.push_back(NULL);
+
+ *ctx = create_android_logcat();
+ if (!*ctx) return NULL;
+
+ int fd = android_logcat_run_command_thread(
+ *ctx, argv.size() - 1, (char* const*)&argv[0], (char* const*)&envp[0]);
+ argv.clear();
+ args.clear();
+ envp.clear();
+ envs.clear();
+ if (fd < 0) {
+ android_logcat_destroy(ctx);
+ return NULL;
+ }
+
+ FILE* retval = fdopen(fd, "reb");
+ if (!retval) android_logcat_destroy(ctx);
+ return retval;
+}
+
+int android_logcat_pclose(android_logcat_context* ctx, FILE* output) {
+ if (*ctx) {
+ static const useconds_t wait_sample = 20000;
+ // Wait two seconds maximum
+ for (size_t retry = ((2 * 1000000) + wait_sample - 1) / wait_sample;
+ android_logcat_run_command_thread_running(*ctx) && retry; --retry) {
+ usleep(wait_sample);
+ }
+ }
+
+ if (output) fclose(output);
+ return android_logcat_destroy(ctx);
+}
+
+int android_logcat_system(const char* command) {
+ std::vector<std::string> args;
+ std::vector<std::string> envs;
+ if (!__android_logcat_parse(command, args, envs)) return -1;
+
+ std::vector<const char*> argv;
+ for (auto& str : args) {
+ argv.push_back(str.c_str());
+ }
+ argv.push_back(NULL);
+
+ std::vector<const char*> envp;
+ for (auto& str : envs) {
+ envp.push_back(str.c_str());
+ }
+ envp.push_back(NULL);
+
+ android_logcat_context ctx = create_android_logcat();
+ if (!ctx) return -1;
+ /* Command return value */
+ int retval = android_logcat_run_command(ctx, -1, -1, argv.size() - 1,
+ (char* const*)&argv[0],
+ (char* const*)&envp[0]);
+ /* destroy return value */
+ int ret = android_logcat_destroy(&ctx);
+ /* Paranoia merging any discrepancies between the two return values */
+ if (!ret) ret = retval;
+ return ret;
+}
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index cb8b061..22aca17 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -27,11 +27,12 @@
-fno-builtin \
# -----------------------------------------------------------------------------
-# Benchmarks (actually a gTest where the result code does not matter)
+# Benchmarks
# ----------------------------------------------------------------------------
benchmark_src_files := \
- logcat_benchmark.cpp
+ logcat_benchmark.cpp \
+ exec_benchmark.cpp \
# Build benchmarks for the device. Run with:
# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
@@ -40,7 +41,8 @@
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
LOCAL_SRC_FILES := $(benchmark_src_files)
-include $(BUILD_NATIVE_TEST)
+LOCAL_SHARED_LIBRARIES := libbase liblogcat
+include $(BUILD_NATIVE_BENCHMARK)
# -----------------------------------------------------------------------------
# Unit tests.
@@ -48,6 +50,7 @@
test_src_files := \
logcat_test.cpp \
+ liblogcat_test.cpp \
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
@@ -55,6 +58,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_SHARED_LIBRARIES := liblog libbase liblogcat
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/exec_benchmark.cpp b/logcat/tests/exec_benchmark.cpp
new file mode 100644
index 0000000..c30a5f5
--- /dev/null
+++ b/logcat/tests/exec_benchmark.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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 <stdio.h>
+
+#include <android-base/file.h>
+#include <benchmark/benchmark.h>
+#include <log/logcat.h>
+
+// Dump the statistics and report results
+
+static void logcat_popen_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ FILE* fp = popen(cmd, "r");
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ pclose(fp);
+ }
+}
+
+static void BM_logcat_stat_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_libc);
+
+static void logcat_popen_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_context ctx;
+ FILE* fp = android_logcat_popen(&ctx, cmd);
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ android_logcat_pclose(&ctx, fp);
+ }
+}
+
+static void BM_logcat_stat_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_liblogcat);
+
+static void logcat_system_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_libc);
+
+static void logcat_system_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_liblogcat);
+
+// Dump the logs and report results
+
+static void BM_logcat_dump_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_libc);
+
+static void BM_logcat_dump_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_liblogcat);
+
+static void BM_logcat_dump_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_libc);
+
+static void BM_logcat_dump_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_liblogcat);
diff --git a/logcat/tests/liblogcat_test.cpp b/logcat/tests/liblogcat_test.cpp
new file mode 100644
index 0000000..9e9a2c2
--- /dev/null
+++ b/logcat/tests/liblogcat_test.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 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 <log/logcat.h>
+
+#define logcat_define(context) android_logcat_context context
+#define logcat_popen(context, command) android_logcat_popen(&context, command)
+#define logcat_pclose(context, fp) android_logcat_pclose(&context, fp)
+#define logcat_system(command) android_logcat_system(command)
+#define logcat liblogcat
+
+#include "logcat_test.cpp"
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index dd85164..8d88628 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -18,19 +18,22 @@
#include <stdlib.h>
#include <string.h>
-#include <gtest/gtest.h>
+#include <benchmark/benchmark.h>
static const char begin[] = "--------- beginning of ";
-TEST(logcat, sorted_order) {
- FILE *fp;
+static void BM_logcat_sorted_order(benchmark::State& state) {
+ FILE* fp;
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
+ if (!state.KeepRunning()) return;
+
+ fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r");
+ if (!fp) return;
class timestamp {
- private:
+ private:
int month;
int day;
int hour;
@@ -39,44 +42,39 @@
int millisecond;
bool ok;
- public:
- void init(const char *buffer)
- {
+ public:
+ void init(const char* buffer) {
ok = false;
if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
- &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
+ &minute, &second, &millisecond) == 6;
}
}
- explicit timestamp(const char *buffer)
- {
+ explicit timestamp(const char* buffer) {
init(buffer);
}
- bool operator< (timestamp &T)
- {
- return !ok || !T.ok
- || (month < T.month)
- || ((month == T.month)
- && ((day < T.day)
- || ((day == T.day)
- && ((hour < T.hour)
- || ((hour == T.hour)
- && ((minute < T.minute)
- || ((minute == T.minute)
- && ((second < T.second)
- || ((second == T.second)
- && (millisecond < T.millisecond))))))))));
+ bool operator<(timestamp& T) {
+ return !ok || !T.ok || (month < T.month) ||
+ ((month == T.month) &&
+ ((day < T.day) ||
+ ((day == T.day) &&
+ ((hour < T.hour) ||
+ ((hour == T.hour) &&
+ ((minute < T.minute) ||
+ ((minute == T.minute) &&
+ ((second < T.second) ||
+ ((second == T.second) &&
+ (millisecond < T.millisecond))))))))));
}
- bool valid(void)
- {
+ bool valid(void) {
return ok;
}
} last(NULL);
- char *last_buffer = NULL;
+ char* last_buffer = NULL;
char buffer[5120];
int count = 0;
@@ -114,15 +112,22 @@
// Allow few fails, happens with readers active
fprintf(stderr, "%s: %d/%d out of order entries\n",
- (next_lt_last)
- ? ((next_lt_last <= max_ok)
- ? "WARNING"
- : "ERROR")
- : "INFO",
+ (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
+ : "INFO",
next_lt_last, count);
- EXPECT_GE(max_ok, next_lt_last);
+ if (next_lt_last > max_ok) {
+ fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
+ next_lt_last);
+ }
// sample statistically too small
- EXPECT_LT(100, count);
+ if (count < 100) {
+ fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
+ }
+
+ state.KeepRunning();
}
+BENCHMARK(BM_logcat_sorted_order);
+
+BENCHMARK_MAIN();
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 081bf92..0895834 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -33,36 +33,45 @@
#include <log/log.h>
#include <log/log_event_list.h>
+#ifndef logcat_popen
+#define logcat_define(context)
+#define logcat_popen(context, command) popen((command), "r")
+#define logcat_pclose(context, fp) pclose(fp)
+#define logcat_system(command) system(command)
+#endif
+
#define BIG_BUFFER (5 * 1024)
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
// a signal to stuff a terminating code into the logs, we will spin rather
// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) \
- && ((errno == EINTR) \
- || (errno == EAGAIN))) \
- || (_rc == -EINTR) \
- || (_rc == -EAGAIN)); \
- _rc; })
+#define LOG_FAILURE_RETRY(exp) \
+ ({ \
+ typeof(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
+ (_rc == -EINTR) || (_rc == -EAGAIN)); \
+ _rc; \
+ })
static const char begin[] = "--------- beginning of ";
TEST(logcat, buckets) {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
#undef LOG_TAG
#define LOG_TAG "inject"
RLOGE("logcat.buckets");
sleep(1);
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = logcat_popen(
+ ctx,
+ "logcat -b radio -b events -b system -b main -d 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -71,7 +80,7 @@
while (fgets(buffer, sizeof(buffer), fp)) {
if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- while (char *cp = strrchr(buffer, '\n')) {
+ while (char* cp = strrchr(buffer, '\n')) {
*cp = '\0';
}
log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1);
@@ -80,7 +89,7 @@
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
EXPECT_EQ(15, ids);
@@ -88,11 +97,14 @@
}
TEST(logcat, event_tag_filter) {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -b events -d -s auditd am_proc_start am_pss am_proc_bound dvm_lock_sample am_wtf 2>/dev/null",
- "r")));
+ ASSERT_TRUE(NULL !=
+ (fp = logcat_popen(ctx,
+ "logcat -b events -d -s auditd "
+ "am_proc_start am_pss am_proc_bound "
+ "dvm_lock_sample am_wtf 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -102,7 +114,7 @@
++count;
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
EXPECT_LT(4, count);
}
@@ -115,7 +127,7 @@
static const size_t retry = 4;
size_t errors = retry;
size_t num = 0;
- for(;;) {
+ for (;;) {
log_time ts(CLOCK_MONOTONIC);
if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) {
if (++num >= (size_t)count) {
@@ -124,7 +136,7 @@
return num;
}
errors = retry;
- usleep(100); // ~32 per timer tick, we are a spammer regardless
+ usleep(100); // ~32 per timer tick, we are a spammer regardless
} else if (--errors <= 0) {
return num;
}
@@ -134,22 +146,22 @@
}
TEST(logcat, year) {
-
if (android_log_clockid() == CLOCK_MONOTONIC) {
fprintf(stderr, "Skipping test, logd is monotonic time\n");
return;
}
int count;
- int tries = 3; // in case run too soon after system start or buffer clear
+ int tries = 3; // in case run too soon after system start or buffer clear
do {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
char needle[32];
time_t now;
time(&now);
- struct tm *ptm;
+ struct tm* ptm;
#if !defined(_WIN32)
struct tm tmBuf;
ptm = localtime_r(&now, &tmBuf);
@@ -158,9 +170,10 @@
#endif
strftime(needle, sizeof(needle), "[ %Y-", ptm);
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v long -v year -b all -t 3 2>/dev/null",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = logcat_popen(
+ ctx, "logcat -v long -v year -b all -t 3 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -171,7 +184,7 @@
++count;
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
} while ((count < 3) && --tries && inject(3 - count));
@@ -179,25 +192,25 @@
}
// Return a pointer to each null terminated -v long time field.
-char *fgetLongTime(char *buffer, size_t buflen, FILE *fp) {
+static char* fgetLongTime(char* buffer, size_t buflen, FILE* fp) {
while (fgets(buffer, buflen, fp)) {
- char *cp = buffer;
+ char* cp = buffer;
if (*cp != '[') {
continue;
}
while (*++cp == ' ') {
;
}
- char *ep = cp;
+ char* ep = cp;
while (isdigit(*ep)) {
++ep;
}
if ((*ep != '-') && (*ep != '.')) {
- continue;
+ continue;
}
- // Find PID field
+ // Find PID field. Look for ': ' or ':[0-9][0-9][0-9]'
while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) {
- ;
+ if (isdigit(ep[0]) && isdigit(ep[1]) && isdigit(ep[2])) break;
}
if (!ep) {
continue;
@@ -211,21 +224,22 @@
}
TEST(logcat, tz) {
-
if (android_log_clockid() == CLOCK_MONOTONIC) {
fprintf(stderr, "Skipping test, logd is monotonic time\n");
return;
}
- int tries = 4; // in case run too soon after system start or buffer clear
+ int tries = 4; // in case run too soon after system start or buffer clear
int count;
do {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
- "r")));
+ ASSERT_TRUE(NULL !=
+ (fp = logcat_popen(ctx,
+ "logcat -v long -v America/Los_Angeles "
+ "-b all -t 3 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -239,7 +253,7 @@
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
} while ((count < 3) && --tries && inject(3 - count));
@@ -247,11 +261,13 @@
}
TEST(logcat, ntz) {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
- "r")));
+ ASSERT_TRUE(NULL !=
+ (fp = logcat_popen(ctx,
+ "logcat -v long -v America/Los_Angeles -v "
+ "zone -b all -t 3 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -263,13 +279,13 @@
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
ASSERT_EQ(0, count);
}
-void do_tail(int num) {
- int tries = 4; // in case run too soon after system start or buffer clear
+static void do_tail(int num) {
+ int tries = 4; // in case run too soon after system start or buffer clear
int count;
if (num > 10) ++tries;
@@ -278,10 +294,11 @@
char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer),
- "logcat -v long -b all -t %d 2>/dev/null", num);
+ "ANDROID_PRINTF_LOG=long logcat -b all -t %d 2>/dev/null", num);
- FILE *fp;
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+ FILE* fp;
+ logcat_define(ctx);
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
count = 0;
@@ -289,7 +306,7 @@
++count;
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
} while ((count < num) && --tries && inject(num - count));
@@ -312,26 +329,23 @@
do_tail(1000);
}
-TEST(logcat, tail_time) {
- FILE *fp;
+static void do_tail_time(const char* cmd) {
+ FILE* fp;
int count;
char buffer[BIG_BUFFER];
- char *last_timestamp = NULL;
+ char* last_timestamp = NULL;
// Hard to predict 100% if first (overlap) or second line will match.
// -v nsec will in a substantial majority be the second line.
- char *first_timestamp = NULL;
- char *second_timestamp = NULL;
- char *input;
+ char* first_timestamp = NULL;
+ char* second_timestamp = NULL;
+ char* input;
- int tries = 4; // in case run too soon after system start or buffer clear
+ int tries = 4; // in case run too soon after system start or buffer clear
do {
- ASSERT_TRUE(NULL != (fp = popen("logcat"
- " -v long"
- " -v nsec"
- " -b all"
- " -t 10"
- " 2>&1", "r")));
+ snprintf(buffer, sizeof(buffer), "%s -t 10 2>&1", cmd);
+ logcat_define(ctx);
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
count = 0;
while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
@@ -344,28 +358,23 @@
free(last_timestamp);
last_timestamp = strdup(input);
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
} while ((count < 10) && --tries && inject(10 - count));
- EXPECT_EQ(10, count); // We want _some_ history, too small, falses below
+ EXPECT_EQ(10, count); // We want _some_ history, too small, falses below
EXPECT_TRUE(last_timestamp != NULL);
EXPECT_TRUE(first_timestamp != NULL);
EXPECT_TRUE(second_timestamp != NULL);
- snprintf(buffer, sizeof(buffer), "logcat"
- " -v long"
- " -v nsec"
- " -b all"
- " -t '%s'"
- " 2>&1",
- first_timestamp);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+ snprintf(buffer, sizeof(buffer), "%s -t '%s' 2>&1", cmd, first_timestamp);
+ logcat_define(ctx);
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
int second_count = 0;
int last_timestamp_count = -1;
- --count; // One less unless we match the first_timestamp
+ --count; // One less unless we match the first_timestamp
bool found = false;
while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
++second_count;
@@ -381,9 +390,8 @@
found = !strcmp(input, first_timestamp);
if (found) {
++count;
- GTEST_LOG_(INFO) << "input = first("
- << first_timestamp
- << ")\n";
+ GTEST_LOG_(INFO)
+ << "input = first(" << first_timestamp << ")\n";
}
free(first_timestamp);
first_timestamp = NULL;
@@ -391,11 +399,8 @@
if (second_timestamp) {
found = found || !strcmp(input, second_timestamp);
if (!found) {
- GTEST_LOG_(INFO) << "input("
- << input
- << ") != second("
- << second_timestamp
- << ")\n";
+ GTEST_LOG_(INFO) << "input(" << input << ") != second("
+ << second_timestamp << ")\n";
}
free(second_timestamp);
second_timestamp = NULL;
@@ -404,7 +409,7 @@
last_timestamp_count = second_count;
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
EXPECT_TRUE(found);
if (!found) {
@@ -429,6 +434,14 @@
EXPECT_LE(count, last_timestamp_count);
}
+TEST(logcat, tail_time) {
+ do_tail_time("logcat -v long -v nsec -b all");
+}
+
+TEST(logcat, tail_time_epoch) {
+ do_tail_time("logcat -v long -v nsec -v epoch -b all");
+}
+
TEST(logcat, End_to_End) {
pid_t pid = getpid();
@@ -436,10 +449,11 @@
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- FILE *fp;
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v brief -b events -t 100 2>/dev/null",
- "r")));
+ FILE* fp;
+ logcat_define(ctx);
+ ASSERT_TRUE(NULL !=
+ (fp = logcat_popen(
+ ctx, "logcat -v brief -b events -t 100 2>/dev/null")));
char buffer[BIG_BUFFER];
@@ -449,27 +463,28 @@
int p;
unsigned long long t;
- if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t))
- || (p != pid)) {
+ if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) ||
+ (p != pid)) {
continue;
}
- log_time tx((const char *) &t);
+ log_time tx((const char*)&t);
if (ts == tx) {
++count;
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
ASSERT_EQ(1, count);
}
-int get_groups(const char *cmd) {
- FILE *fp;
+static int get_groups(const char* cmd) {
+ FILE* fp;
+ logcat_define(ctx);
// NB: crash log only available in user space
- EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
+ EXPECT_TRUE(NULL != (fp = logcat_popen(ctx, cmd)));
if (fp == NULL) {
return 0;
@@ -487,75 +502,78 @@
size = consumed = max = payload = 0;
// NB: crash log can be very small, not hit a Kb of consumed space
// doubly lucky we are not including it.
- if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed),"
- " max entry is %db, max payload is %db",
- &size, size_mult, &consumed, consumed_mult,
- &max, &payload)) {
+ if (6 != sscanf(buffer,
+ "%*s ring buffer is %d%2s (%d%2s consumed),"
+ " max entry is %db, max payload is %db",
+ &size, size_mult, &consumed, consumed_mult, &max,
+ &payload)) {
fprintf(stderr, "WARNING: Parse error: %s", buffer);
continue;
}
full_size = size;
- switch(size_mult[0]) {
- case 'G':
- full_size *= 1024;
+ switch (size_mult[0]) {
+ case 'G':
+ full_size *= 1024;
/* FALLTHRU */
- case 'M':
- full_size *= 1024;
+ case 'M':
+ full_size *= 1024;
/* FALLTHRU */
- case 'K':
- full_size *= 1024;
+ case 'K':
+ full_size *= 1024;
/* FALLTHRU */
- case 'b':
- break;
+ case 'b':
+ break;
}
full_consumed = consumed;
- switch(consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
+ switch (consumed_mult[0]) {
+ case 'G':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'M':
- full_consumed *= 1024;
+ case 'M':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'K':
- full_consumed *= 1024;
+ case 'K':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'b':
- break;
+ case 'b':
+ break;
}
EXPECT_GT((full_size * 9) / 4, full_consumed);
EXPECT_GT(full_size, max);
EXPECT_GT(max, payload);
- if ((((full_size * 9) / 4) >= full_consumed)
- && (full_size > max)
- && (max > payload)) {
+ if ((((full_size * 9) / 4) >= full_consumed) && (full_size > max) &&
+ (max > payload)) {
++count;
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
return count;
}
TEST(logcat, get_size) {
- ASSERT_EQ(4, get_groups(
- "logcat -v brief -b radio -b events -b system -b main -g 2>/dev/null"));
+ ASSERT_EQ(4, get_groups("logcat -v brief -b radio -b events -b system -b "
+ "main -g 2>/dev/null"));
}
// duplicate test for get_size, but use comma-separated list of buffers
TEST(logcat, multiple_buffer) {
- ASSERT_EQ(4, get_groups(
- "logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
+ ASSERT_EQ(
+ 4, get_groups(
+ "logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
}
TEST(logcat, bad_buffer) {
- ASSERT_EQ(0, get_groups(
- "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
+ ASSERT_EQ(
+ 0,
+ get_groups(
+ "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
}
-static void caught_blocking(int signum)
-{
+#ifndef logcat
+static void caught_blocking(int signum) {
unsigned long long v = 0xDEADBEEFA55A0000ULL;
v += getpid() & 0xFFFF;
@@ -565,7 +583,7 @@
}
TEST(logcat, blocking) {
- FILE *fp;
+ FILE* fp;
unsigned long long v = 0xDEADBEEFA55F0000ULL;
pid_t pid = getpid();
@@ -576,10 +594,11 @@
v &= 0xFFFFFFFFFFFAFFFFULL;
- ASSERT_TRUE(NULL != (fp = popen(
- "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events 2>&1",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+ " logcat -v brief -b events 2>&1",
+ "r")));
char buffer[BIG_BUFFER];
@@ -590,7 +609,6 @@
signal(SIGALRM, caught_blocking);
alarm(2);
while (fgets(buffer, sizeof(buffer), fp)) {
-
if (!strncmp(buffer, "DONE", 4)) {
break;
}
@@ -600,8 +618,7 @@
int p;
unsigned long long l;
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
- || (p != pid)) {
+ if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
continue;
}
@@ -624,8 +641,7 @@
EXPECT_EQ(1, signals);
}
-static void caught_blocking_tail(int signum)
-{
+static void caught_blocking_tail(int signum) {
unsigned long long v = 0xA55ADEADBEEF0000ULL;
v += getpid() & 0xFFFF;
@@ -635,7 +651,7 @@
}
TEST(logcat, blocking_tail) {
- FILE *fp;
+ FILE* fp;
unsigned long long v = 0xA55FDEADBEEF0000ULL;
pid_t pid = getpid();
@@ -646,10 +662,11 @@
v &= 0xFFFAFFFFFFFFFFFFULL;
- ASSERT_TRUE(NULL != (fp = popen(
- "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events -T 5 2>&1",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+ " logcat -v brief -b events -T 5 2>&1",
+ "r")));
char buffer[BIG_BUFFER];
@@ -660,7 +677,6 @@
signal(SIGALRM, caught_blocking_tail);
alarm(2);
while (fgets(buffer, sizeof(buffer), fp)) {
-
if (!strncmp(buffer, "DONE", 4)) {
break;
}
@@ -670,8 +686,7 @@
int p;
unsigned long long l;
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
- || (p != pid)) {
+ if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
continue;
}
@@ -695,13 +710,13 @@
EXPECT_EQ(1, signals);
}
+#endif
// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
static testing::AssertionResult IsFalse(int ret, const char* command) {
- return ret ?
- (testing::AssertionSuccess() <<
- "ret=" << ret << " command=\"" << command << "\"") :
- testing::AssertionFailure();
+ return ret ? (testing::AssertionSuccess()
+ << "ret=" << ret << " command=\"" << command << "\"")
+ : testing::AssertionFailure();
}
TEST(logcat, logrotate) {
@@ -709,17 +724,18 @@
char buf[sizeof(form)];
ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
- static const char comm[] = "logcat -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 7 -r 1";
+ static const char comm[] =
+ "logcat -b radio -b events -b system -b main"
+ " -d -f %s/log.txt -n 7 -r 1";
char command[sizeof(buf) + sizeof(comm)];
snprintf(command, sizeof(command), comm, buf);
int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (!ret) {
snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
- FILE *fp;
+ FILE* fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
if (fp) {
char buffer[BIG_BUFFER];
@@ -731,7 +747,7 @@
char c;
if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
- (num <= 40)) {
+ (num <= 40)) {
++count;
} else if (strncmp(buffer, total, sizeof(total) - 1)) {
fprintf(stderr, "WARNING: Parse error: %s", buffer);
@@ -749,21 +765,23 @@
}
TEST(logcat, logrotate_suffix) {
- static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ static const char tmp_out_dir_form[] =
+ "/data/local/tmp/logcat.logrotate.XXXXXX";
char tmp_out_dir[sizeof(tmp_out_dir_form)];
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
- static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 10 -r 1";
+ static const char logcat_cmd[] =
+ "logcat -b radio -b events -b system -b main"
+ " -d -f %s/log.txt -n 10 -r 1";
char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (!ret) {
snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
- FILE *fp;
+ FILE* fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
char buffer[BIG_BUFFER];
int log_file_count = 0;
@@ -774,21 +792,24 @@
strlen(rotated_log_filename_prefix);
static const char log_filename[] = "log.txt";
- if (!strncmp(buffer, rotated_log_filename_prefix, rotated_log_filename_prefix_len)) {
- // Rotated file should have form log.txt.##
- char* rotated_log_filename_suffix = buffer + rotated_log_filename_prefix_len;
- char* endptr;
- const long int suffix_value = strtol(rotated_log_filename_suffix, &endptr, 10);
- EXPECT_EQ(rotated_log_filename_suffix + 2, endptr);
- EXPECT_LE(suffix_value, 10);
- EXPECT_GT(suffix_value, 0);
- ++log_file_count;
- continue;
+ if (!strncmp(buffer, rotated_log_filename_prefix,
+ rotated_log_filename_prefix_len)) {
+ // Rotated file should have form log.txt.##
+ char* rotated_log_filename_suffix =
+ buffer + rotated_log_filename_prefix_len;
+ char* endptr;
+ const long int suffix_value =
+ strtol(rotated_log_filename_suffix, &endptr, 10);
+ EXPECT_EQ(rotated_log_filename_suffix + 2, endptr);
+ EXPECT_LE(suffix_value, 10);
+ EXPECT_GT(suffix_value, 0);
+ ++log_file_count;
+ continue;
}
if (!strncmp(buffer, log_filename, strlen(log_filename))) {
- ++log_file_count;
- continue;
+ ++log_file_count;
+ continue;
}
fprintf(stderr, "ERROR: Unexpected file: %s", buffer);
@@ -802,24 +823,26 @@
}
TEST(logcat, logrotate_continue) {
- static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ static const char tmp_out_dir_form[] =
+ "/data/local/tmp/logcat.logrotate.XXXXXX";
char tmp_out_dir[sizeof(tmp_out_dir_form)];
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
static const char log_filename[] = "log.txt";
- static const char logcat_cmd[] = "logcat -b all -v nsec -d -f %s/%s -n 256 -r 1024";
+ static const char logcat_cmd[] =
+ "logcat -b all -v nsec -d -f %s/%s -n 256 -r 1024";
static const char cleanup_cmd[] = "rm -rf %s";
char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)];
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- FILE *fp;
+ FILE* fp;
snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename);
EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
if (!fp) {
@@ -827,10 +850,11 @@
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- char *line = NULL;
- char *last_line = NULL; // this line is allowed to stutter, one-line overlap
- char *second_last_line = NULL; // should never stutter
- char *first_line = NULL; // help diagnose failure?
+ char* line = NULL;
+ char* last_line =
+ NULL; // this line is allowed to stutter, one-line overlap
+ char* second_last_line = NULL; // should never stutter
+ char* first_line = NULL; // help diagnose failure?
size_t len = 0;
while (getline(&line, &len, fp) != -1) {
if (!first_line) {
@@ -861,7 +885,7 @@
// re-run the command, it should only add a few lines more content if it
// continues where it left off.
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
@@ -869,7 +893,8 @@
free(first_line);
return;
}
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
+ closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
@@ -878,7 +903,7 @@
free(first_line);
return;
}
- struct dirent *entry;
+ struct dirent* entry;
unsigned count = 0;
while ((entry = readdir(dir.get()))) {
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
@@ -904,15 +929,15 @@
unlink(command);
}
if (count > 1) {
- char *brk = strpbrk(second_last_line, "\r\n");
+ char* brk = strpbrk(second_last_line, "\r\n");
if (!brk) brk = second_last_line + strlen(second_last_line);
fprintf(stderr, "\"%.*s\" occurred %u times\n",
- (int)(brk - second_last_line), second_last_line, count);
+ (int)(brk - second_last_line), second_last_line, count);
if (first_line) {
brk = strpbrk(first_line, "\r\n");
if (!brk) brk = first_line + strlen(first_line);
fprintf(stderr, "\"%.*s\" was first line, fault?\n",
- (int)(brk - first_line), first_line);
+ (int)(brk - first_line), first_line);
}
}
free(second_last_line);
@@ -923,7 +948,8 @@
}
TEST(logcat, logrotate_clear) {
- static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ static const char tmp_out_dir_form[] =
+ "/data/local/tmp/logcat.logrotate.XXXXXX";
char tmp_out_dir[sizeof(tmp_out_dir_form)];
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
@@ -932,28 +958,30 @@
static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n %d -r 1";
static const char clear_cmd[] = " -c";
static const char cleanup_cmd[] = "rm -rf %s";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename) + sizeof(clear_cmd) + 32];
+ char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) +
+ sizeof(log_filename) + sizeof(clear_cmd) + 32];
// Run command with all data
{
- snprintf(command, sizeof(command) - sizeof(clear_cmd),
- logcat_cmd, tmp_out_dir, log_filename, num_val);
+ snprintf(command, sizeof(command) - sizeof(clear_cmd), logcat_cmd,
+ tmp_out_dir, log_filename, num_val);
int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
+ closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- struct dirent *entry;
+ struct dirent* entry;
unsigned count = 0;
while ((entry = readdir(dir.get()))) {
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
@@ -969,21 +997,22 @@
strcat(command, clear_cmd);
int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ EXPECT_FALSE(IsFalse(ret = logcat_system(command), command));
if (ret) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(system(command));
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
+ closedir);
EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(IsFalse(system(command), command));
return;
}
- struct dirent *entry;
+ struct dirent* entry;
unsigned count = 0;
while ((entry = readdir(dir.get()))) {
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
@@ -999,24 +1028,25 @@
EXPECT_FALSE(IsFalse(system(command), command));
}
-static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) {
-
+static int logrotate_count_id(const char* logcat_cmd, const char* tmp_out_dir) {
static const char log_filename[] = "log.txt";
- char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + strlen(log_filename) + 32];
+ char command[strlen(tmp_out_dir) + strlen(logcat_cmd) +
+ strlen(log_filename) + 32];
snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
+ int ret = logcat_system(command);
if (ret) {
+ fprintf(stderr, "system(\"%s\")=%d", command, ret);
return -1;
}
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
- EXPECT_NE(nullptr, dir);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
+ closedir);
if (!dir) {
+ fprintf(stderr, "opendir(\"%s\") failed", tmp_out_dir);
return -1;
}
- struct dirent *entry;
+ struct dirent* entry;
int count = 0;
while ((entry = readdir(dir.get()))) {
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
@@ -1028,9 +1058,12 @@
}
TEST(logcat, logrotate_id) {
- static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test";
- static const char logcat_short_cmd[] = "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
- static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ static const char logcat_cmd[] =
+ "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test";
+ static const char logcat_short_cmd[] =
+ "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
+ static const char tmp_out_dir_form[] =
+ "/data/local/tmp/logcat.logrotate.XXXXXX";
static const char log_filename[] = "log.txt";
char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
@@ -1047,19 +1080,21 @@
unlink(id_file);
EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
- FILE *fp = fopen(id_file, "w");
+ FILE* fp = fopen(id_file, "w");
if (fp) {
fprintf(fp, "not_a_test");
fclose(fp);
}
if (getuid() != 0) {
- chmod(id_file, 0); // API to preserve content even with signature change
+ chmod(id_file,
+ 0); // API to preserve content even with signature change
ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
chmod(id_file, 0600);
}
int new_signature;
- EXPECT_LE(2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)));
+ EXPECT_LE(
+ 2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)));
EXPECT_GT(34, new_signature);
static const char cleanup_cmd[] = "rm -rf %s";
@@ -1069,13 +1104,15 @@
}
TEST(logcat, logrotate_nodir) {
- // expect logcat to error out on writing content and exit(1) for nodir
- EXPECT_EQ(W_EXITCODE(1, 0),
- system("logcat -b all -d"
- " -f /das/nein/gerfingerpoken/logcat/log.txt"
- " -n 256 -r 1024"));
+ // expect logcat to error out on writing content and not exit(0) for nodir
+ static const char command[] =
+ "logcat -b all -d"
+ " -f /das/nein/gerfingerpoken/logcat/log.txt"
+ " -n 256 -r 1024";
+ EXPECT_FALSE(IsFalse(0 == logcat_system(command), command));
}
+#ifndef logcat
static void caught_blocking_clear(int signum) {
unsigned long long v = 0xDEADBEEFA55C0000ULL;
@@ -1086,7 +1123,7 @@
}
TEST(logcat, blocking_clear) {
- FILE *fp;
+ FILE* fp;
unsigned long long v = 0xDEADBEEFA55C0000ULL;
pid_t pid = getpid();
@@ -1095,12 +1132,13 @@
// This test is racey; an event occurs between clear and dump.
// We accept that we will get a false positive, but never a false negative.
- ASSERT_TRUE(NULL != (fp = popen(
- "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -b events -c 2>&1 ;"
- " logcat -b events -g 2>&1 ;"
- " logcat -v brief -b events 2>&1",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+ " logcat -b events -c 2>&1 ;"
+ " logcat -b events -g 2>&1 ;"
+ " logcat -v brief -b events 2>&1",
+ "r")));
char buffer[BIG_BUFFER];
@@ -1112,7 +1150,6 @@
signal(SIGALRM, caught_blocking_clear);
alarm(2);
while (fgets(buffer, sizeof(buffer), fp)) {
-
if (!strncmp(buffer, "clearLog: ", 10)) {
fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
count = signals = 1;
@@ -1126,37 +1163,38 @@
int size, consumed, max, payload;
char size_mult[3], consumed_mult[3];
size = consumed = max = payload = 0;
- if (6 == sscanf(buffer, "events: ring buffer is %d%2s (%d%2s consumed),"
- " max entry is %db, max payload is %db",
- &size, size_mult, &consumed, consumed_mult,
- &max, &payload)) {
+ if (6 == sscanf(buffer,
+ "events: ring buffer is %d%2s (%d%2s consumed),"
+ " max entry is %db, max payload is %db",
+ &size, size_mult, &consumed, consumed_mult, &max,
+ &payload)) {
long full_size = size, full_consumed = consumed;
- switch(size_mult[0]) {
- case 'G':
- full_size *= 1024;
+ switch (size_mult[0]) {
+ case 'G':
+ full_size *= 1024;
/* FALLTHRU */
- case 'M':
- full_size *= 1024;
+ case 'M':
+ full_size *= 1024;
/* FALLTHRU */
- case 'K':
- full_size *= 1024;
+ case 'K':
+ full_size *= 1024;
/* FALLTHRU */
- case 'b':
- break;
+ case 'b':
+ break;
}
- switch(consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
+ switch (consumed_mult[0]) {
+ case 'G':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'M':
- full_consumed *= 1024;
+ case 'M':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'K':
- full_consumed *= 1024;
+ case 'K':
+ full_consumed *= 1024;
/* FALLTHRU */
- case 'b':
- break;
+ case 'b':
+ break;
}
EXPECT_GT(full_size, full_consumed);
EXPECT_GT(full_size, max);
@@ -1172,8 +1210,7 @@
int p;
unsigned long long l;
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
- || (p != pid)) {
+ if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
continue;
}
@@ -1199,11 +1236,13 @@
EXPECT_EQ(1, signals);
}
+#endif
-static bool get_white_black(char **list) {
- FILE *fp;
+static bool get_white_black(char** list) {
+ FILE* fp;
+ logcat_define(ctx);
- fp = popen("logcat -p 2>/dev/null", "r");
+ fp = logcat_popen(ctx, "logcat -p 2>/dev/null");
if (fp == NULL) {
fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
return false;
@@ -1212,12 +1251,12 @@
char buffer[BIG_BUFFER];
while (fgets(buffer, sizeof(buffer), fp)) {
- char *hold = *list;
- char *buf = buffer;
+ char* hold = *list;
+ char* buf = buffer;
while (isspace(*buf)) {
++buf;
}
- char *end = buf + strlen(buf);
+ char* end = buf + strlen(buf);
while (isspace(*--end) && (end >= buf)) {
*end = '\0';
}
@@ -1231,28 +1270,29 @@
asprintf(list, "%s", buf);
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
return *list != NULL;
}
-static bool set_white_black(const char *list) {
- FILE *fp;
+static bool set_white_black(const char* list) {
+ FILE* fp;
+ logcat_define(ctx);
char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
- fp = popen(buffer, "r");
+ fp = logcat_popen(ctx, buffer);
if (fp == NULL) {
fprintf(stderr, "ERROR: %s\n", buffer);
return false;
}
while (fgets(buffer, sizeof(buffer), fp)) {
- char *buf = buffer;
+ char* buf = buffer;
while (isspace(*buf)) {
++buf;
}
- char *end = buf + strlen(buf);
+ char* end = buf + strlen(buf);
while ((end > buf) && isspace(*--end)) {
*end = '\0';
}
@@ -1260,15 +1300,15 @@
continue;
}
fprintf(stderr, "%s\n", buf);
- pclose(fp);
+ logcat_pclose(ctx, fp);
return false;
}
- return pclose(fp) == 0;
+ return logcat_pclose(ctx, fp) == 0;
}
TEST(logcat, white_black_adjust) {
- char *list = NULL;
- char *adjust = NULL;
+ char* list = NULL;
+ char* adjust = NULL;
get_white_black(&list);
@@ -1297,55 +1337,72 @@
}
TEST(logcat, regex) {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
int count = 0;
char buffer[BIG_BUFFER];
+// Have to make liblogcat data unique from logcat data injection
+#ifdef logcat
+#define logcat_regex_prefix "lolcat_test"
+#else
+#define logcat_regex_prefix "logcat_test"
+#endif
- snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", getpid());
+ snprintf(buffer, sizeof(buffer),
+ "logcat --pid %d -d -e " logcat_regex_prefix "_a+b", getpid());
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_ab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_b"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_aaaab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_aaaa"));
-
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
+ logcat_regex_prefix "_ab"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
+ logcat_regex_prefix "_b"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
+ logcat_regex_prefix "_aaaab"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
+ logcat_regex_prefix "_aaaa"));
// Let the logs settle
sleep(1);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
while (fgets(buffer, sizeof(buffer), fp)) {
if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
continue;
}
- EXPECT_TRUE(strstr(buffer, "logcat_test_") != NULL);
+ EXPECT_TRUE(strstr(buffer, logcat_regex_prefix "_") != NULL);
count++;
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
ASSERT_EQ(2, count);
}
TEST(logcat, maxcount) {
- FILE *fp;
+ FILE* fp;
+ logcat_define(ctx);
int count = 0;
char buffer[BIG_BUFFER];
- snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());
+ snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3",
+ getpid());
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(
+ __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(
+ __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(
+ __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(
+ __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
// Let the logs settle
sleep(1);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+ ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer)));
while (fgets(buffer, sizeof(buffer), fp)) {
if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
@@ -1355,7 +1412,7 @@
count++;
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
ASSERT_EQ(3, count);
}
@@ -1367,8 +1424,18 @@
;
static bool End_to_End(const char* tag, const char* fmt, ...) {
- FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
- if (!fp) return false;
+ logcat_define(ctx);
+ FILE* fp = logcat_popen(ctx,
+ "logcat"
+ " -v brief"
+ " -b events"
+ " -v descriptive"
+ " -t 100"
+ " 2>/dev/null");
+ if (!fp) {
+ fprintf(stderr, "End_to_End: popen failed");
+ return false;
+ }
char buffer[BIG_BUFFER];
va_list ap;
@@ -1377,7 +1444,7 @@
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
- char *str = NULL;
+ char* str = NULL;
asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
std::string expect(str);
free(str);
@@ -1399,15 +1466,19 @@
}
}
- pclose(fp);
+ logcat_pclose(ctx, fp);
if ((count == 0) && (lastMatch.length() > 0)) {
// Help us pinpoint where things went wrong ...
fprintf(stderr, "Closest match for\n %s\n is\n %s",
expect.c_str(), lastMatch.c_str());
+ } else if (count > 2) {
+ fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str());
}
- return count == 1;
+ // Expect one the first time around as either liblogcat.descriptive or
+ // logcat.descriptive. Expect two the second time as the other.
+ return count == 1 || count == 2;
}
TEST(logcat, descriptive) {
@@ -1422,8 +1493,8 @@
static const char theAnswer[] = "what is five by seven";
ctx << theAnswer;
ctx.write();
- EXPECT_TRUE(End_to_End(hhgtg.tagStr,
- "to life the universe etc=%s", theAnswer));
+ EXPECT_TRUE(
+ End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
}
{
@@ -1434,8 +1505,7 @@
ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr,
- "[id=%s,event=42,source=-1,account=0]",
- id));
+ "[id=%s,event=42,source=-1,account=0]", id));
}
// Partial match to description
@@ -1443,9 +1513,7 @@
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
ctx.write();
- EXPECT_TRUE(End_to_End(sync.tagStr,
- "[id=%s,event=43,-1,0]",
- id));
+ EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
}
// Negative Test of End_to_End, ensure it is working
@@ -1454,9 +1522,8 @@
ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
ctx.write();
fprintf(stderr, "Expect a \"Closest match\" message\n");
- EXPECT_FALSE(End_to_End(sync.tagStr,
- "[id=%s,event=44,source=-1,account=0]",
- id));
+ EXPECT_FALSE(End_to_End(
+ sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
}
}
@@ -1466,16 +1533,16 @@
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)30 << (int32_t)2;
ctx.write();
- EXPECT_TRUE(End_to_End(sync.tagStr,
- "[aggregation time=30ms,count=2]"));
+ EXPECT_TRUE(
+ End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
}
{
android_log_event_list ctx(sync.tagNo);
ctx << (uint64_t)31570 << (int32_t)911;
ctx.write();
- EXPECT_TRUE(End_to_End(sync.tagStr,
- "[aggregation time=31.57s,count=911]"));
+ EXPECT_TRUE(
+ End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
}
}
@@ -1518,7 +1585,7 @@
{
android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
+ ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
ctx.write();
EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
}
@@ -1533,12 +1600,13 @@
}
static bool reportedSecurity(const char* command) {
- FILE* fp = popen(command, "r");
+ logcat_define(ctx);
+ FILE* fp = logcat_popen(ctx, command);
if (!fp) return true;
std::string ret;
bool val = android::base::ReadFdToString(fileno(fp), &ret);
- pclose(fp);
+ logcat_pclose(ctx, fp);
if (!val) return true;
return std::string::npos != ret.find("'security'");
diff --git a/base/.clang-format b/logd/.clang-format
similarity index 68%
copy from base/.clang-format
copy to logd/.clang-format
index 2b83a1f..393c309 100644
--- a/base/.clang-format
+++ b/logd/.clang-format
@@ -1,11 +1,11 @@
BasedOnStyle: Google
-AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
-IndentWidth: 2
+IndentWidth: 4
PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
+TabWidth: 4
PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 74e0ea5..06c0ab5 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -20,8 +20,8 @@
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -37,9 +37,9 @@
#include "LogCommand.h"
#include "LogUtils.h"
-CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
- LogListener * /*swl*/) :
- FrameworkListener(getLogSocket()) {
+CommandListener::CommandListener(LogBuffer* buf, LogReader* /*reader*/,
+ LogListener* /*swl*/)
+ : FrameworkListener(getLogSocket()) {
// registerCmd(new ShutdownCmd(buf, writer, swl));
registerCmd(new ClearCmd(buf));
registerCmd(new GetBufSizeCmd(buf));
@@ -53,24 +53,19 @@
registerCmd(new ExitCmd(this));
}
-CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
- LogListener *swl) :
- LogCommand("shutdown"),
- mReader(*reader),
- mSwl(*swl) {
+CommandListener::ShutdownCmd::ShutdownCmd(LogReader* reader, LogListener* swl)
+ : LogCommand("shutdown"), mReader(*reader), mSwl(*swl) {
}
-int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
- int /*argc*/,
- char ** /*argv*/) {
+int CommandListener::ShutdownCmd::runCommand(SocketClient* /*cli*/,
+ int /*argc*/, char** /*argv*/) {
mSwl.stopListener();
mReader.stopListener();
exit(0);
}
-CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
- LogCommand("clear"),
- mBuf(*buf) {
+CommandListener::ClearCmd::ClearCmd(LogBuffer* buf)
+ : LogCommand("clear"), mBuf(*buf) {
}
static void setname() {
@@ -81,8 +76,8 @@
}
}
-int CommandListener::ClearCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
uid_t uid = cli->getUid();
if (clientHasLogCredentials(cli)) {
@@ -100,17 +95,16 @@
return 0;
}
- cli->sendMsg(mBuf.clear((log_id_t) id, uid) ? "busy" : "success");
+ cli->sendMsg(mBuf.clear((log_id_t)id, uid) ? "busy" : "success");
return 0;
}
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
- LogCommand("getLogSize"),
- mBuf(*buf) {
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer* buf)
+ : LogCommand("getLogSize"), mBuf(*buf) {
}
-int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
if (argc < 2) {
cli->sendMsg("Missing Argument");
@@ -123,20 +117,19 @@
return 0;
}
- unsigned long size = mBuf.getSize((log_id_t) id);
+ unsigned long size = mBuf.getSize((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
return 0;
}
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
- LogCommand("setLogSize"),
- mBuf(*buf) {
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer* buf)
+ : LogCommand("setLogSize"), mBuf(*buf) {
}
-int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
if (!clientHasLogCredentials(cli)) {
cli->sendMsg("Permission Denied");
@@ -155,7 +148,7 @@
}
unsigned long size = atol(argv[2]);
- if (mBuf.setSize((log_id_t) id, size)) {
+ if (mBuf.setSize((log_id_t)id, size)) {
cli->sendMsg("Range Error");
return 0;
}
@@ -164,13 +157,12 @@
return 0;
}
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
- LogCommand("getLogSizeUsed"),
- mBuf(*buf) {
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer* buf)
+ : LogCommand("getLogSizeUsed"), mBuf(*buf) {
}
-int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
if (argc < 2) {
cli->sendMsg("Missing Argument");
@@ -183,29 +175,29 @@
return 0;
}
- unsigned long size = mBuf.getSizeUsed((log_id_t) id);
+ unsigned long size = mBuf.getSizeUsed((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
return 0;
}
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
- LogCommand("getStatistics"),
- mBuf(*buf) {
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer* buf)
+ : LogCommand("getStatistics"), mBuf(*buf) {
}
-static std::string package_string(const std::string &str) {
+static std::string package_string(const std::string& str) {
// Calculate total buffer size prefix, count is the string length w/o nul
char fmt[32];
- for(size_t l = str.length(), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
+ for (size_t l = str.length(), y = 0, x = 6; y != x;
+ y = x, x = strlen(fmt) - 2) {
snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
}
return android::base::StringPrintf(fmt, str.c_str());
}
-int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
uid_t uid = cli->getUid();
if (clientHasLogCredentials(cli)) {
@@ -236,30 +228,28 @@
}
}
- cli->sendMsg(package_string(mBuf.formatStatistics(uid, pid,
- logMask)).c_str());
+ cli->sendMsg(
+ package_string(mBuf.formatStatistics(uid, pid, logMask)).c_str());
return 0;
}
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
- LogCommand("getPruneList"),
- mBuf(*buf) {
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer* buf)
+ : LogCommand("getPruneList"), mBuf(*buf) {
}
-int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
- int /*argc*/, char ** /*argv*/) {
+int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
+ int /*argc*/, char** /*argv*/) {
setname();
cli->sendMsg(package_string(mBuf.formatPrune()).c_str());
return 0;
}
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
- LogCommand("setPruneList"),
- mBuf(*buf) {
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer* buf)
+ : LogCommand("setPruneList"), mBuf(*buf) {
}
-int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
+int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
if (!clientHasLogCredentials(cli)) {
cli->sendMsg("Permission Denied");
@@ -286,21 +276,21 @@
return 0;
}
-CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer *buf) :
- LogCommand("getEventTag"),
- mBuf(*buf) {
+CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer* buf)
+ : LogCommand("getEventTag"), mBuf(*buf) {
}
-int CommandListener::GetEventTagCmd::runCommand(SocketClient *cli,
- int argc, char ** argv) {
+int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
+ char** argv) {
setname();
uid_t uid = cli->getUid();
if (clientHasLogCredentials(cli)) {
uid = AID_ROOT;
}
- const char *name = NULL;
- const char *format = NULL;
+ const char* name = NULL;
+ const char* format = NULL;
+ const char* id = NULL;
for (int i = 1; i < argc; ++i) {
static const char _name[] = "name=";
if (!strncmp(argv[i], _name, strlen(_name))) {
@@ -313,10 +303,25 @@
format = argv[i] + strlen(_format);
continue;
}
+
+ static const char _id[] = "id=";
+ if (!strncmp(argv[i], _id, strlen(_id))) {
+ id = argv[i] + strlen(_id);
+ continue;
+ }
}
- cli->sendMsg(package_string(mBuf.formatGetEventTag(uid,
- name, format)).c_str());
+ if (id) {
+ if (format || name) {
+ cli->sendMsg("can not mix id= with either format= or name=");
+ return 0;
+ }
+ cli->sendMsg(package_string(mBuf.formatEntry(atoi(id), uid)).c_str());
+ return 0;
+ }
+
+ cli->sendMsg(
+ package_string(mBuf.formatGetEventTag(uid, name, format)).c_str());
return 0;
}
@@ -324,8 +329,8 @@
CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
}
-int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
- int /*argc*/, char ** /*argv*/) {
+int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
+ char** /*argv*/) {
setname();
reinit_signal_handler(SIGHUP);
@@ -335,13 +340,12 @@
return 0;
}
-CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
- LogCommand("EXIT"),
- mParent(*parent) {
+CommandListener::ExitCmd::ExitCmd(CommandListener* parent)
+ : LogCommand("EXIT"), mParent(*parent) {
}
-int CommandListener::ExitCmd::runCommand(SocketClient * cli,
- int /*argc*/, char ** /*argv*/) {
+int CommandListener::ExitCmd::runCommand(SocketClient* cli, int /*argc*/,
+ char** /*argv*/) {
setname();
cli->sendMsg("success");
@@ -355,9 +359,8 @@
int sock = android_get_control_socket(socketName);
if (sock < 0) {
- sock = socket_local_server(socketName,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
+ sock = socket_local_server(
+ socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
}
return sock;
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index 39de03b..ed99419 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -18,40 +18,43 @@
#define _COMMANDLISTENER_H__
#include <sysutils/FrameworkListener.h>
-#include "LogCommand.h"
#include "LogBuffer.h"
-#include "LogReader.h"
+#include "LogCommand.h"
#include "LogListener.h"
+#include "LogReader.h"
// See main.cpp for implementation
void reinit_signal_handler(int /*signal*/);
class CommandListener : public FrameworkListener {
+ public:
+ CommandListener(LogBuffer* buf, LogReader* reader, LogListener* swl);
+ virtual ~CommandListener() {
+ }
-public:
- CommandListener(LogBuffer *buf, LogReader *reader, LogListener *swl);
- virtual ~CommandListener() {}
-
-private:
+ private:
static int getLogSocket();
class ShutdownCmd : public LogCommand {
- LogReader &mReader;
- LogListener &mSwl;
+ LogReader& mReader;
+ LogListener& mSwl;
- public:
- ShutdownCmd(LogReader *reader, LogListener *swl);
- virtual ~ShutdownCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
+ public:
+ ShutdownCmd(LogReader* reader, LogListener* swl);
+ virtual ~ShutdownCmd() {
+ }
+ int runCommand(SocketClient* c, int argc, char** argv);
};
-#define LogBufferCmd(name) \
- class name##Cmd : public LogCommand { \
- LogBuffer &mBuf; \
- public: \
- explicit name##Cmd(LogBuffer *buf); \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient *c, int argc, char ** argv); \
+#define LogBufferCmd(name) \
+ class name##Cmd : public LogCommand { \
+ LogBuffer& mBuf; \
+ \
+ public: \
+ explicit name##Cmd(LogBuffer* buf); \
+ virtual ~name##Cmd() { \
+ } \
+ int runCommand(SocketClient* c, int argc, char** argv); \
}
LogBufferCmd(Clear);
@@ -63,29 +66,33 @@
LogBufferCmd(SetPruneList);
LogBufferCmd(GetEventTag);
-#define LogCmd(name) \
- class name##Cmd : public LogCommand { \
- public: \
- name##Cmd(); \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient *c, int argc, char ** argv); \
+#define LogCmd(name) \
+ class name##Cmd : public LogCommand { \
+ public: \
+ name##Cmd(); \
+ virtual ~name##Cmd() { \
+ } \
+ int runCommand(SocketClient* c, int argc, char** argv); \
}
LogCmd(Reinit);
-#define LogParentCmd(name) \
- class name##Cmd : public LogCommand { \
- CommandListener &mParent; \
- public: \
- name##Cmd(); \
- explicit name##Cmd(CommandListener *parent); \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient *c, int argc, char ** argv); \
- void release(SocketClient *c) { mParent.release(c); } \
+#define LogParentCmd(name) \
+ class name##Cmd : public LogCommand { \
+ CommandListener& mParent; \
+ \
+ public: \
+ name##Cmd(); \
+ explicit name##Cmd(CommandListener* parent); \
+ virtual ~name##Cmd() { \
+ } \
+ int runCommand(SocketClient* c, int argc, char** argv); \
+ void release(SocketClient* c) { \
+ mParent.release(c); \
+ } \
}
LogParentCmd(Exit);
-
};
#endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 6a26d00..ff6bff8 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -26,20 +26,16 @@
#include "LogTimes.h"
#include "LogUtils.h"
-FlushCommand::FlushCommand(LogReader &reader,
- bool nonBlock,
- unsigned long tail,
- unsigned int logMask,
- pid_t pid,
- uint64_t start,
- uint64_t timeout) :
- mReader(reader),
- mNonBlock(nonBlock),
- mTail(tail),
- mLogMask(logMask),
- mPid(pid),
- mStart(start),
- mTimeout((start > 1) ? timeout : 0) {
+FlushCommand::FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
+ unsigned int logMask, pid_t pid, log_time start,
+ uint64_t timeout)
+ : mReader(reader),
+ mNonBlock(nonBlock),
+ mTail(tail),
+ mLogMask(logMask),
+ mPid(pid),
+ mStart(start),
+ mTimeout((start != log_time::EPOCH) ? timeout : 0) {
}
// runSocketCommand is called once for every open client on the
@@ -51,13 +47,13 @@
// global LogTimeEntry::lock() is used to protect access,
// reference counts are used to ensure that individual
// LogTimeEntry lifetime is managed when not protected.
-void FlushCommand::runSocketCommand(SocketClient *client) {
- LogTimeEntry *entry = NULL;
- LastLogTimes × = mReader.logbuf().mTimes;
+void FlushCommand::runSocketCommand(SocketClient* client) {
+ LogTimeEntry* entry = NULL;
+ LastLogTimes& times = mReader.logbuf().mTimes;
LogTimeEntry::lock();
LastLogTimes::iterator it = times.begin();
- while(it != times.end()) {
+ while (it != times.end()) {
entry = (*it);
if (entry->mClient == client) {
if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
@@ -77,7 +73,7 @@
if (it == times.end()) {
// Create LogTimeEntry in notifyNewLog() ?
- if (mTail == (unsigned long) -1) {
+ if (mTail == (unsigned long)-1) {
LogTimeEntry::unlock();
return;
}
@@ -93,14 +89,14 @@
LogTimeEntry::unlock();
}
-bool FlushCommand::hasReadLogs(SocketClient *client) {
+bool FlushCommand::hasReadLogs(SocketClient* client) {
return clientHasLogCredentials(client);
}
-static bool clientHasSecurityCredentials(SocketClient *client) {
+static bool clientHasSecurityCredentials(SocketClient* client) {
return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM);
}
-bool FlushCommand::hasSecurityLogs(SocketClient *client) {
+bool FlushCommand::hasSecurityLogs(SocketClient* client) {
return clientHasSecurityCredentials(client);
}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 1e7818a..7cdd03f 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -16,7 +16,7 @@
#ifndef _FLUSH_COMMAND_H
#define _FLUSH_COMMAND_H
-#include <android/log.h>
+#include <private/android_logger.h>
#include <sysutils/SocketClientCommand.h>
class LogBufferElement;
@@ -26,26 +26,23 @@
class LogReader;
class FlushCommand : public SocketClientCommand {
- LogReader &mReader;
+ LogReader& mReader;
bool mNonBlock;
unsigned long mTail;
unsigned int mLogMask;
pid_t mPid;
- uint64_t mStart;
+ log_time mStart;
uint64_t mTimeout;
-public:
- explicit FlushCommand(LogReader &mReader,
- bool nonBlock = false,
- unsigned long tail = -1,
- unsigned int logMask = -1,
- pid_t pid = 0,
- uint64_t start = 1,
- uint64_t timeout = 0);
- virtual void runSocketCommand(SocketClient *client);
+ public:
+ explicit FlushCommand(LogReader& mReader, bool nonBlock = false,
+ unsigned long tail = -1, unsigned int logMask = -1,
+ pid_t pid = 0, log_time start = log_time::EPOCH,
+ uint64_t timeout = 0);
+ virtual void runSocketCommand(SocketClient* client);
- static bool hasReadLogs(SocketClient *client);
- static bool hasSecurityLogs(SocketClient *client);
+ static bool hasReadLogs(SocketClient* client);
+ static bool hasSecurityLogs(SocketClient* client);
};
#endif
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 92d957f..2d9024a 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -29,38 +29,52 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include "libaudit.h"
#include "LogAudit.h"
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
#include "LogUtils.h"
+#include "libaudit.h"
-#define KMSG_PRIORITY(PRI) \
- '<', \
- '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
- '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
- '>'
+#define KMSG_PRIORITY(PRI) \
+ '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
+ '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
- SocketListener(mSock = getLogSocket(), false),
- logbuf(buf),
- reader(reader),
- fdDmesg(fdDmesg),
- main(__android_logger_property_get_bool("ro.logd.auditd.main",
+LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
+ : SocketListener(mSock = getLogSocket(), false),
+ logbuf(buf),
+ reader(reader),
+ fdDmesg(fdDmesg),
+ main(__android_logger_property_get_bool("ro.logd.auditd.main",
+ BOOL_DEFAULT_TRUE)),
+ events(__android_logger_property_get_bool("ro.logd.auditd.events",
BOOL_DEFAULT_TRUE)),
- events(__android_logger_property_get_bool("ro.logd.auditd.events",
- BOOL_DEFAULT_TRUE)),
- initialized(false),
- tooFast(false) {
+ initialized(false),
+ tooFast(false) {
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
- 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
- ' ', 's', 't', 'a', 'r', 't', '\n' };
+ 'l',
+ 'o',
+ 'g',
+ 'd',
+ '.',
+ 'a',
+ 'u',
+ 'd',
+ 'i',
+ 't',
+ 'd',
+ ':',
+ ' ',
+ 's',
+ 't',
+ 'a',
+ 'r',
+ 't',
+ '\n' };
write(fdDmesg, auditd_message, sizeof(auditd_message));
}
void LogAudit::checkRateLimit() {
-
// trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
bucket.emplace(android_log_clockid());
@@ -69,8 +83,9 @@
static const size_t upperThreshold =
((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) + 1) /
- 2;
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
+ 1) /
+ 2;
if (bucket.size() >= upperThreshold) {
// Hit peak, slow down source
if (!tooFast) {
@@ -89,8 +104,8 @@
if (!tooFast) return;
- static const size_t lowerThreshold = AUDIT_RATE_LIMIT_BURST_DURATION *
- AUDIT_RATE_LIMIT_MAX;
+ static const size_t lowerThreshold =
+ AUDIT_RATE_LIMIT_BURST_DURATION * AUDIT_RATE_LIMIT_MAX;
if (bucket.size() >= lowerThreshold) return;
@@ -99,7 +114,7 @@
audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
}
-bool LogAudit::onDataAvailable(SocketClient *cli) {
+bool LogAudit::onDataAvailable(SocketClient* cli) {
if (!initialized) {
prctl(PR_SET_NAME, "logd.auditd");
initialized = true;
@@ -123,14 +138,14 @@
return true;
}
-int LogAudit::logPrint(const char *fmt, ...) {
+int LogAudit::logPrint(const char* fmt, ...) {
if (fmt == NULL) {
return -EINVAL;
}
va_list args;
- char *str = NULL;
+ char* str = NULL;
va_start(args, fmt);
int rc = vasprintf(&str, fmt, args);
va_end(args);
@@ -139,7 +154,7 @@
return rc;
}
- char *cp;
+ char* cp;
// Work around kernels missing
// https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
// Such kernels improperly add newlines inside audit messages.
@@ -160,19 +175,19 @@
// Dedupe messages, checking for identical messages starting with avc:
static unsigned count;
- static char *last_str;
+ static char* last_str;
static bool last_info;
if (last_str != NULL) {
static const char avc[] = "): avc: ";
- char *avcl = strstr(last_str, avc);
+ char* avcl = strstr(last_str, avc);
bool skip = false;
if (avcl) {
- char *avcr = strstr(str, avc);
+ char* avcr = strstr(str, avc);
- skip = avcr && !fastcmp<strcmp>(avcl + strlen(avc),
- avcr + strlen(avc));
+ skip = avcr &&
+ !fastcmp<strcmp>(avcl + strlen(avc), avcr + strlen(avc));
if (skip) {
++count;
free(last_str);
@@ -183,19 +198,17 @@
if (!skip) {
static const char resume[] = " duplicate messages suppressed\n";
- iov[0].iov_base = last_info ?
- const_cast<char *>(log_info) :
- const_cast<char *>(log_warning);
- iov[0].iov_len = last_info ?
- sizeof(log_info) :
- sizeof(log_warning);
+ iov[0].iov_base = last_info ? const_cast<char*>(log_info)
+ : const_cast<char*>(log_warning);
+ iov[0].iov_len =
+ last_info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = last_str;
iov[1].iov_len = strlen(last_str);
if (count > 1) {
- iov[2].iov_base = const_cast<char *>(resume);
+ iov[2].iov_base = const_cast<char*>(resume);
iov[2].iov_len = strlen(resume);
} else {
- iov[2].iov_base = const_cast<char *>(newline);
+ iov[2].iov_base = const_cast<char*>(newline);
iov[2].iov_len = strlen(newline);
}
@@ -210,15 +223,12 @@
last_info = info;
}
if (count == 0) {
- iov[0].iov_base = info ?
- const_cast<char *>(log_info) :
- const_cast<char *>(log_warning);
- iov[0].iov_len = info ?
- sizeof(log_info) :
- sizeof(log_warning);
+ iov[0].iov_base = info ? const_cast<char*>(log_info)
+ : const_cast<char*>(log_warning);
+ iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
iov[1].iov_base = str;
iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char *>(newline);
+ iov[2].iov_base = const_cast<char*>(newline);
iov[2].iov_len = strlen(newline);
writev(fdDmesg, iov, arraysize(iov));
@@ -236,10 +246,10 @@
log_time now;
static const char audit_str[] = " audit(";
- char *timeptr = strstr(str, audit_str);
- if (timeptr
- && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
- && (*cp == ':')) {
+ char* timeptr = strstr(str, audit_str);
+ if (timeptr &&
+ ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
+ (*cp == ':')) {
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
if (!isMonotonic()) {
@@ -258,7 +268,7 @@
}
static const char pid_str[] = " pid=";
- char *pidptr = strstr(str, pid_str);
+ char* pidptr = strstr(str, pid_str);
if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
cp = pidptr + sizeof(pid_str) - 1;
pid = 0;
@@ -280,19 +290,19 @@
bool notify = false;
- if (events) { // begin scope for event buffer
+ if (events) { // begin scope for event buffer
uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
- android_log_event_string_t *event
- = reinterpret_cast<android_log_event_string_t *>(buffer);
+ android_log_event_string_t* event =
+ reinterpret_cast<android_log_event_string_t*>(buffer);
event->header.tag = htole32(AUDITD_LOG_TAG);
event->type = EVENT_TYPE_STRING;
event->length = htole32(l);
memcpy(event->data, str, l);
rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
- reinterpret_cast<char *>(event),
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ reinterpret_cast<char*>(event),
+ (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
if (rc >= 0) {
notify = true;
}
@@ -302,9 +312,9 @@
// log to main
static const char comm_str[] = " comm=\"";
- const char *comm = strstr(str, comm_str);
- const char *estr = str + strlen(str);
- const char *commfree = NULL;
+ const char* comm = strstr(str, comm_str);
+ const char* estr = str + strlen(str);
+ const char* commfree = NULL;
if (comm) {
estr = comm;
comm += sizeof(comm_str) - 1;
@@ -320,7 +330,7 @@
}
}
- const char *ecomm = strchr(comm, '"');
+ const char* ecomm = strchr(comm, '"');
if (ecomm) {
++ecomm;
l = ecomm - comm;
@@ -335,7 +345,7 @@
size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
n = b + e + l + 2;
- if (main) { // begin scope for main buffer
+ if (main) { // begin scope for main buffer
char newstr[n];
*newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
@@ -344,7 +354,7 @@
strncpy(newstr + 1 + l + b, ecomm, e);
rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ (n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
if (rc >= 0) {
notify = true;
@@ -352,7 +362,7 @@
// end scope for main buffer
}
- free(const_cast<char *>(commfree));
+ free(const_cast<char*>(commfree));
free(str);
if (notify) {
@@ -365,8 +375,8 @@
return rc;
}
-int LogAudit::log(char *buf, size_t len) {
- char *audit = strstr(buf, " audit(");
+int LogAudit::log(char* buf, size_t len) {
+ char* audit = strstr(buf, " audit(");
if (!audit || (audit >= &buf[len])) {
return 0;
}
@@ -374,7 +384,7 @@
*audit = '\0';
int rc;
- char *type = strstr(buf, "type=");
+ char* type = strstr(buf, "type=");
if (type && (type < &buf[len])) {
rc = logPrint("%s %s", type, audit + 1);
} else {
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 045d631..5947819 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -26,9 +26,9 @@
class LogReader;
class LogAudit : public SocketListener {
- LogBuffer *logbuf;
- LogReader *reader;
- int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
+ LogBuffer* logbuf;
+ LogReader* reader;
+ int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
bool main;
bool events;
bool initialized;
@@ -38,18 +38,20 @@
std::queue<log_time> bucket;
void checkRateLimit();
-public:
- LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
- int log(char *buf, size_t len);
- bool isMonotonic() { return logbuf->isMonotonic(); }
+ public:
+ LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
+ int log(char* buf, size_t len);
+ bool isMonotonic() {
+ return logbuf->isMonotonic();
+ }
-protected:
- virtual bool onDataAvailable(SocketClient *cli);
+ protected:
+ virtual bool onDataAvailable(SocketClient* cli);
-private:
+ private:
static int getLogSocket();
- int logPrint(const char *fmt, ...)
- __attribute__ ((__format__ (__printf__, 2, 3)));
+ int logPrint(const char* fmt, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
};
#endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 7613c1e..1b79e89 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -72,8 +72,8 @@
//
pthread_mutex_lock(&mLogElementsLock);
LogBufferElementCollection::iterator it = mLogElements.begin();
- while((it != mLogElements.end())) {
- LogBufferElement *e = *it;
+ while ((it != mLogElements.end())) {
+ LogBufferElement* e = *it;
if (monotonic) {
if (!android::isMonotonic(e->mRealTime)) {
LogKlog::convertRealToMonotonic(e->mRealTime);
@@ -96,8 +96,8 @@
LogTimeEntry::lock();
LastLogTimes::iterator times = mTimes.begin();
- while(times != mTimes.end()) {
- LogTimeEntry *entry = (*times);
+ while (times != mTimes.end()) {
+ LogTimeEntry* entry = (*times);
if (entry->owned_Locked()) {
entry->triggerReader_Locked();
}
@@ -107,9 +107,8 @@
LogTimeEntry::unlock();
}
-LogBuffer::LogBuffer(LastLogTimes *times):
- monotonic(android_log_clockid() == CLOCK_MONOTONIC),
- mTimes(*times) {
+LogBuffer::LogBuffer(LastLogTimes* times)
+ : monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
log_id_for_each(i) {
@@ -127,28 +126,26 @@
}
}
-enum match_type {
- DIFFERENT,
- SAME,
- SAME_LIBLOG
-};
+enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
-static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) {
+static enum match_type identical(LogBufferElement* elem,
+ LogBufferElement* last) {
// is it mostly identical?
-// if (!elem) return DIFFERENT;
+ // if (!elem) return DIFFERENT;
unsigned short lenl = elem->getMsgLen();
if (!lenl) return DIFFERENT;
-// if (!last) return DIFFERENT;
+ // if (!last) return DIFFERENT;
unsigned short lenr = last->getMsgLen();
if (!lenr) return DIFFERENT;
-// if (elem->getLogId() != last->getLogId()) return DIFFERENT;
+ // if (elem->getLogId() != last->getLogId()) return DIFFERENT;
if (elem->getUid() != last->getUid()) return DIFFERENT;
if (elem->getPid() != last->getPid()) return DIFFERENT;
if (elem->getTid() != last->getTid()) return DIFFERENT;
// last is more than a minute old, stop squashing identical messages
if (elem->getRealTime().nsec() >
- (last->getRealTime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT;
+ (last->getRealTime().nsec() + 60 * NS_PER_SEC))
+ return DIFFERENT;
// Identical message
const char* msgl = elem->getMsg();
@@ -158,47 +155,52 @@
// liblog tagged messages (content gets summed)
if ((elem->getLogId() == LOG_ID_EVENTS) &&
(lenl == sizeof(android_log_event_int_t)) &&
- !fastcmp<memcmp>(msgl, msgr,
- sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
- (elem->getTag() == LIBLOG_LOG_TAG)) return SAME_LIBLOG;
+ !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) -
+ sizeof(int32_t)) &&
+ (elem->getTag() == LIBLOG_LOG_TAG))
+ return SAME_LIBLOG;
}
// audit message (except sequence number) identical?
static const char avc[] = "): avc: ";
if (last->isBinary()) {
- if (fastcmp<memcmp>(msgl, msgr,
- sizeof(android_log_event_string_t) -
- sizeof(int32_t))) return DIFFERENT;
+ if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) -
+ sizeof(int32_t)))
+ return DIFFERENT;
msgl += sizeof(android_log_event_string_t);
lenl -= sizeof(android_log_event_string_t);
msgr += sizeof(android_log_event_string_t);
lenr -= sizeof(android_log_event_string_t);
}
- const char *avcl = android::strnstr(msgl, lenl, avc);
+ const char* avcl = android::strnstr(msgl, lenl, avc);
if (!avcl) return DIFFERENT;
lenl -= avcl - msgl;
- const char *avcr = android::strnstr(msgr, lenr, avc);
+ const char* avcr = android::strnstr(msgr, lenr, avc);
if (!avcr) return DIFFERENT;
lenr -= avcr - msgr;
if (lenl != lenr) return DIFFERENT;
- if (fastcmp<memcmp>(avcl + strlen(avc),
- avcr + strlen(avc), lenl)) return DIFFERENT;
+ // TODO: After b/35468874 is addressed, revisit "lenl > strlen(avc)"
+ // condition, it might become superfluous.
+ if (lenl > strlen(avc) &&
+ fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc),
+ lenl - strlen(avc))) {
+ return DIFFERENT;
+ }
return SAME;
}
-int LogBuffer::log(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len) {
+int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
+ pid_t tid, const char* msg, unsigned short len) {
if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
return -EINVAL;
}
- LogBufferElement *elem = new LogBufferElement(log_id, realtime,
- uid, pid, tid, msg, len);
+ LogBufferElement* elem =
+ new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
if (log_id != LOG_ID_SECURITY) {
int prio = ANDROID_LOG_INFO;
- const char *tag = NULL;
+ const char* tag = NULL;
if (log_id == LOG_ID_EVENTS) {
tag = tagToName(elem->getTag());
} else {
@@ -219,7 +221,7 @@
pthread_mutex_lock(&mLogElementsLock);
LogBufferElement* currentLast = lastLoggedElements[log_id];
if (currentLast) {
- LogBufferElement *dropped = droppedElements[log_id];
+ LogBufferElement* dropped = droppedElements[log_id];
unsigned short count = dropped ? dropped->getDropped() : 0;
//
// State Init
@@ -309,7 +311,7 @@
uint32_t swab = event->payload.data;
unsigned long long total = htole32(swab);
event = reinterpret_cast<android_log_event_int_t*>(
- const_cast<char*>(elem->getMsg()));
+ const_cast<char*>(elem->getMsg()));
swab = event->payload.data;
lastLoggedElements[LOG_ID_EVENTS] = elem;
@@ -346,15 +348,15 @@
pthread_mutex_unlock(&mLogElementsLock);
return len;
}
- if (dropped) { // State 1 or 2
- if (count) { // State 2
- log(dropped); // report chatty
- } else { // State 1
- delete dropped;
+ if (dropped) { // State 1 or 2
+ if (count) { // State 2
+ log(dropped); // report chatty
+ } else { // State 1
+ delete dropped;
}
droppedElements[log_id] = NULL;
- log(currentLast); // report last message in the series
- } else { // State 0
+ log(currentLast); // report last message in the series
+ } else { // State 0
delete currentLast;
}
}
@@ -372,31 +374,26 @@
// NB: if end is region locked, place element at end of list
LogBufferElementCollection::iterator it = mLogElements.end();
LogBufferElementCollection::iterator last = it;
- while (last != mLogElements.begin()) {
- --it;
- if ((*it)->getRealTime() <= elem->getRealTime()) {
- break;
- }
- last = it;
- }
-
- if (last == mLogElements.end()) {
+ if (__predict_true(it != mLogElements.begin())) --it;
+ if (__predict_false(it == mLogElements.begin()) ||
+ __predict_true((*it)->getRealTime() <= elem->getRealTime())) {
mLogElements.push_back(elem);
} else {
- uint64_t end = 1;
+ log_time end = log_time::EPOCH;
bool end_set = false;
bool end_always = false;
LogTimeEntry::lock();
LastLogTimes::iterator times = mTimes.begin();
- while(times != mTimes.end()) {
+ while (times != mTimes.end()) {
LogTimeEntry* entry = (*times);
if (entry->owned_Locked()) {
if (!entry->mNonBlock) {
end_always = true;
break;
}
+ // it passing mEnd is blocked by the following checks.
if (!end_set || (end <= entry->mEnd)) {
end = entry->mEnd;
end_set = true;
@@ -405,13 +402,20 @@
times++;
}
- if (end_always
- || (end_set && (end >= (*last)->getSequence()))) {
+ if (end_always || (end_set && (end > (*it)->getRealTime()))) {
mLogElements.push_back(elem);
} else {
+ // should be short as timestamps are localized near end()
+ do {
+ last = it;
+ if (__predict_false(it == mLogElements.begin())) {
+ break;
+ }
+ --it;
+ } while (((*it)->getRealTime() > elem->getRealTime()) &&
+ (!end_set || (end <= (*it)->getRealTime())));
mLogElements.insert(last, elem);
}
-
LogTimeEntry::unlock();
}
@@ -444,30 +448,31 @@
}
LogBufferElementCollection::iterator LogBuffer::erase(
- LogBufferElementCollection::iterator it, bool coalesce) {
- LogBufferElement *element = *it;
+ LogBufferElementCollection::iterator it, bool coalesce) {
+ LogBufferElement* element = *it;
log_id_t id = element->getLogId();
// Remove iterator references in the various lists that will become stale
// after the element is erased from the main logging list.
- { // start of scope for found iterator
- int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
- element->getTag() : element->getUid();
+ { // start of scope for found iterator
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
+ ? element->getTag()
+ : element->getUid();
LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
if ((found != mLastWorst[id].end()) && (it == found->second)) {
mLastWorst[id].erase(found);
}
}
- { // start of scope for pid found iterator
+ { // start of scope for pid found iterator
// element->getUid() may not be AID_SYSTEM for next-best-watermark.
// will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
// long term code stability, find() check should be fast for those ids.
LogBufferPidIteratorMap::iterator found =
mLastWorstPidOfSystem[id].find(element->getPid());
- if ((found != mLastWorstPidOfSystem[id].end())
- && (it == found->second)) {
+ if ((found != mLastWorstPidOfSystem[id].end()) &&
+ (it == found->second)) {
mLastWorstPidOfSystem[id].erase(found);
}
}
@@ -479,34 +484,35 @@
}
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
LogBufferElementCollection::iterator bad = it;
- int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
- element->getTag() : element->getUid();
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
+ ? element->getTag()
+ : element->getUid();
#endif
it = mLogElements.erase(it);
if (doSetLast) {
log_id_for_each(i) {
if (setLast[i]) {
- if (__predict_false(it == mLogElements.end())) { // impossible
+ if (__predict_false(it == mLogElements.end())) { // impossible
mLastSet[i] = false;
mLast[i] = mLogElements.begin();
} else {
- mLast[i] = it; // push down the road as next-best-watermark
+ mLast[i] = it; // push down the road as next-best-watermark
}
}
}
}
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
log_id_for_each(i) {
- for(auto b : mLastWorst[i]) {
+ for (auto b : mLastWorst[i]) {
if (bad == b.second) {
- android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
- i, b.first, key);
+ android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i,
+ b.first, key);
}
}
- for(auto b : mLastWorstPidOfSystem[i]) {
+ for (auto b : mLastWorstPidOfSystem[i]) {
if (bad == b.second) {
- android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
- i, b.first);
+ android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i,
+ b.first);
}
}
if (mLastSet[i] && (bad == mLast[i])) {
@@ -539,32 +545,29 @@
uint64_t value;
} __packed;
-public:
- LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid):
- uid(uid),
- pid(pid),
- tid(tid)
- {
+ public:
+ LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid)
+ : uid(uid), pid(pid), tid(tid) {
}
- explicit LogBufferElementKey(uint64_t key):value(key) { }
+ explicit LogBufferElementKey(uint64_t key) : value(key) {
+ }
- uint64_t getKey() { return value; }
+ uint64_t getKey() {
+ return value;
+ }
};
class LogBufferElementLast {
-
- typedef std::unordered_map<uint64_t, LogBufferElement *> LogBufferElementMap;
+ typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
LogBufferElementMap map;
-public:
-
- bool coalesce(LogBufferElement *element, unsigned short dropped) {
- LogBufferElementKey key(element->getUid(),
- element->getPid(),
+ public:
+ bool coalesce(LogBufferElement* element, unsigned short dropped) {
+ LogBufferElementKey key(element->getUid(), element->getPid(),
element->getTid());
LogBufferElementMap::iterator it = map.find(key.getKey());
if (it != map.end()) {
- LogBufferElement *found = it->second;
+ LogBufferElement* found = it->second;
unsigned short moreDropped = found->getDropped();
if ((dropped + moreDropped) > USHRT_MAX) {
map.erase(it);
@@ -576,9 +579,8 @@
return false;
}
- void add(LogBufferElement *element) {
- LogBufferElementKey key(element->getUid(),
- element->getPid(),
+ void add(LogBufferElement* element) {
+ LogBufferElementKey key(element->getUid(), element->getPid(),
element->getTid());
map[key.getKey()] = element;
}
@@ -587,20 +589,19 @@
map.clear();
}
- void clear(LogBufferElement *element) {
- uint64_t current = element->getRealTime().nsec()
- - (EXPIRE_RATELIMIT * NS_PER_SEC);
- for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
- LogBufferElement *mapElement = it->second;
- if ((mapElement->getDropped() >= EXPIRE_THRESHOLD)
- && (current > mapElement->getRealTime().nsec())) {
+ void clear(LogBufferElement* element) {
+ log_time current =
+ element->getRealTime() - log_time(EXPIRE_RATELIMIT, 0);
+ for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
+ LogBufferElement* mapElement = it->second;
+ if ((mapElement->getDropped() >= EXPIRE_THRESHOLD) &&
+ (current > mapElement->getRealTime())) {
it = map.erase(it);
} else {
++it;
}
}
}
-
};
// prune "pruneRows" of type "id" from the buffer.
@@ -651,7 +652,7 @@
// mLogElementsLock must be held when this function is called.
//
bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
- LogTimeEntry *oldest = NULL;
+ LogTimeEntry* oldest = NULL;
bool busy = false;
bool clearAll = pruneRows == ULONG_MAX;
@@ -659,13 +660,12 @@
// Region locked?
LastLogTimes::iterator times = mTimes.begin();
- while(times != mTimes.end()) {
- LogTimeEntry *entry = (*times);
- if (entry->owned_Locked() && entry->isWatching(id)
- && (!oldest ||
- (oldest->mStart > entry->mStart) ||
- ((oldest->mStart == entry->mStart) &&
- (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
+ while (times != mTimes.end()) {
+ LogTimeEntry* entry = (*times);
+ if (entry->owned_Locked() && entry->isWatching(id) &&
+ (!oldest || (oldest->mStart > entry->mStart) ||
+ ((oldest->mStart == entry->mStart) &&
+ (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
oldest = entry;
}
times++;
@@ -673,14 +673,15 @@
LogBufferElementCollection::iterator it;
- if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
+ if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
// Only here if clear all request from non system source, so chatty
// filter logistics is not required.
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
while (it != mLogElements.end()) {
- LogBufferElement *element = *it;
+ LogBufferElement* element = *it;
- if ((element->getLogId() != id) || (element->getUid() != caller_uid)) {
+ if ((element->getLogId() != id) ||
+ (element->getUid() != caller_uid)) {
++it;
continue;
}
@@ -690,7 +691,7 @@
mLastSet[id] = true;
}
- if (oldest && (oldest->mStart <= element->getSequence())) {
+ if (oldest && (oldest->mStart <= element->getRealTime().nsec())) {
busy = true;
if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
oldest->triggerReader_Locked();
@@ -713,26 +714,28 @@
bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
while (!clearAll && (pruneRows > 0)) {
// recalculate the worst offender on every batched pass
- int worst = -1; // not valid for getUid() or getKey()
+ int worst = -1; // not valid for getUid() or getKey()
size_t worst_sizes = 0;
size_t second_worst_sizes = 0;
- pid_t worstPid = 0; // POSIX guarantees PID != 0
+ pid_t worstPid = 0; // POSIX guarantees PID != 0
if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
// Calculate threshold as 12.5% of available storage
size_t threshold = log_buffer_size(id) / 8;
if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
- stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
- worst, worst_sizes, second_worst_sizes, threshold);
+ stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
+ .findWorst(worst, worst_sizes, second_worst_sizes,
+ threshold);
// per-pid filter for AID_SYSTEM sources is too complex
} else {
- stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
- worst, worst_sizes, second_worst_sizes, threshold);
+ stats.sort(AID_ROOT, (pid_t)0, 2, id)
+ .findWorst(worst, worst_sizes, second_worst_sizes,
+ threshold);
if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
- stats.sortPids(worst, (pid_t)0, 2, id).findWorst(
- worstPid, worst_sizes, second_worst_sizes);
+ stats.sortPids(worst, (pid_t)0, 2, id)
+ .findWorst(worstPid, worst_sizes, second_worst_sizes);
}
}
}
@@ -751,37 +754,36 @@
// - check age-out of preserved logs
bool gc = pruneRows <= 1;
if (!gc && (worst != -1)) {
- { // begin scope for worst found iterator
- LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
- if ((found != mLastWorst[id].end())
- && (found->second != mLogElements.end())) {
+ { // begin scope for worst found iterator
+ LogBufferIteratorMap::iterator found =
+ mLastWorst[id].find(worst);
+ if ((found != mLastWorst[id].end()) &&
+ (found->second != mLogElements.end())) {
leading = false;
it = found->second;
}
}
- if (worstPid) { // begin scope for pid worst found iterator
+ if (worstPid) { // begin scope for pid worst found iterator
// FYI: worstPid only set if !LOG_ID_EVENTS and
// !LOG_ID_SECURITY, not going to make that assumption ...
- LogBufferPidIteratorMap::iterator found
- = mLastWorstPidOfSystem[id].find(worstPid);
- if ((found != mLastWorstPidOfSystem[id].end())
- && (found->second != mLogElements.end())) {
+ LogBufferPidIteratorMap::iterator found =
+ mLastWorstPidOfSystem[id].find(worstPid);
+ if ((found != mLastWorstPidOfSystem[id].end()) &&
+ (found->second != mLogElements.end())) {
leading = false;
it = found->second;
}
}
}
- static const timespec too_old = {
- EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
- };
+ static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 };
LogBufferElementCollection::iterator lastt;
lastt = mLogElements.end();
--lastt;
LogBufferElementLast last;
while (it != mLogElements.end()) {
- LogBufferElement *element = *it;
+ LogBufferElement* element = *it;
- if (oldest && (oldest->mStart <= element->getSequence())) {
+ if (oldest && (oldest->mStart <= element->getRealTime().nsec())) {
busy = true;
if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
oldest->triggerReader_Locked();
@@ -813,9 +815,9 @@
continue;
}
- int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
- element->getTag() :
- element->getUid();
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
+ ? element->getTag()
+ : element->getUid();
if (hasBlacklist && mPrune.naughty(element)) {
last.clear(element);
@@ -839,32 +841,32 @@
continue;
}
- if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old))
- || (element->getRealTime() > (*lastt)->getRealTime())) {
+ if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old)) ||
+ (element->getRealTime() > (*lastt)->getRealTime())) {
break;
}
if (dropped) {
last.add(element);
- if (worstPid
- && ((!gc && (element->getPid() == worstPid))
- || (mLastWorstPidOfSystem[id].find(element->getPid())
- == mLastWorstPidOfSystem[id].end()))) {
+ if (worstPid &&
+ ((!gc && (element->getPid() == worstPid)) ||
+ (mLastWorstPidOfSystem[id].find(element->getPid()) ==
+ mLastWorstPidOfSystem[id].end()))) {
// element->getUid() may not be AID_SYSTEM, next best
// watermark if current one empty. id is not LOG_ID_EVENTS
// or LOG_ID_SECURITY because of worstPid check.
mLastWorstPidOfSystem[id][element->getPid()] = it;
}
- if ((!gc && !worstPid && (key == worst))
- || (mLastWorst[id].find(key) == mLastWorst[id].end())) {
+ if ((!gc && !worstPid && (key == worst)) ||
+ (mLastWorst[id].find(key) == mLastWorst[id].end())) {
mLastWorst[id][key] = it;
}
++it;
continue;
}
- if ((key != worst)
- || (worstPid && (element->getPid() != worstPid))) {
+ if ((key != worst) ||
+ (worstPid && (element->getPid() != worstPid))) {
leading = false;
last.clear(element);
++it;
@@ -892,16 +894,16 @@
it = erase(it, true);
} else {
last.add(element);
- if (worstPid && (!gc
- || (mLastWorstPidOfSystem[id].find(worstPid)
- == mLastWorstPidOfSystem[id].end()))) {
+ if (worstPid &&
+ (!gc || (mLastWorstPidOfSystem[id].find(worstPid) ==
+ mLastWorstPidOfSystem[id].end()))) {
// element->getUid() may not be AID_SYSTEM, next best
// watermark if current one empty. id is not
// LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
mLastWorstPidOfSystem[id][worstPid] = it;
}
if ((!gc && !worstPid) ||
- (mLastWorst[id].find(worst) == mLastWorst[id].end())) {
+ (mLastWorst[id].find(worst) == mLastWorst[id].end())) {
mLastWorst[id][worst] = it;
}
++it;
@@ -915,15 +917,15 @@
last.clear();
if (!kick || !mPrune.worstUidEnabled()) {
- break; // the following loop will ask bad clients to skip/drop
+ break; // the following loop will ask bad clients to skip/drop
}
}
bool whitelist = false;
bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
- while((pruneRows > 0) && (it != mLogElements.end())) {
- LogBufferElement *element = *it;
+ while ((pruneRows > 0) && (it != mLogElements.end())) {
+ LogBufferElement* element = *it;
if (element->getLogId() != id) {
it++;
@@ -935,7 +937,7 @@
mLastSet[id] = true;
}
- if (oldest && (oldest->mStart <= element->getSequence())) {
+ if (oldest && (oldest->mStart <= element->getRealTime().nsec())) {
busy = true;
if (whitelist) {
break;
@@ -966,8 +968,8 @@
// Do not save the whitelist if we are reader range limited
if (whitelist && (pruneRows > 0)) {
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
- while((it != mLogElements.end()) && (pruneRows > 0)) {
- LogBufferElement *element = *it;
+ while ((it != mLogElements.end()) && (pruneRows > 0)) {
+ LogBufferElement* element = *it;
if (element->getLogId() != id) {
++it;
@@ -979,7 +981,7 @@
mLastSet[id] = true;
}
- if (oldest && (oldest->mStart <= element->getSequence())) {
+ if (oldest && (oldest->mStart <= element->getRealTime().nsec())) {
busy = true;
if (stats.sizes(id) > (2 * log_buffer_size(id))) {
// kick a misbehaving log reader client off the island
@@ -1007,7 +1009,7 @@
bool busy = true;
// If it takes more than 4 tries (seconds) to clear, then kill reader(s)
for (int retry = 4;;) {
- if (retry == 1) { // last pass
+ if (retry == 1) { // last pass
// Check if it is still busy after the sleep, we say prune
// one entry, not another clear run, so we are looking for
// the quick side effect of the return value to tell us if
@@ -1023,7 +1025,7 @@
LogTimeEntry::lock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry *entry = (*times);
+ LogTimeEntry* entry = (*times);
// Killer punch
if (entry->owned_Locked() && entry->isWatching(id)) {
entry->release_Locked();
@@ -1039,7 +1041,7 @@
if (!busy || !--retry) {
break;
}
- sleep (1); // Let reader(s) catch up after notification
+ sleep(1); // Let reader(s) catch up after notification
}
return busy;
}
@@ -1072,38 +1074,43 @@
return retval;
}
-uint64_t LogBuffer::flushTo(
- SocketClient *reader, const uint64_t start,
- bool privileged, bool security,
- int (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+log_time LogBuffer::flushTo(
+ SocketClient* reader, const log_time& start, bool privileged, bool security,
+ int (*filter)(const LogBufferElement* element, void* arg), void* arg) {
LogBufferElementCollection::iterator it;
- uint64_t max = start;
uid_t uid = reader->getUid();
pthread_mutex_lock(&mLogElementsLock);
- if (start <= 1) {
+ if (start == log_time::EPOCH) {
// client wants to start from the beginning
it = mLogElements.begin();
} else {
+ LogBufferElementCollection::iterator last = mLogElements.begin();
+ // 30 second limit to continue search for out-of-order entries.
+ log_time min = start - log_time(30, 0);
// Client wants to start from some specified time. Chances are
// we are better off starting from the end of the time sorted list.
- for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {
+ for (it = mLogElements.end(); it != mLogElements.begin();
+ /* do nothing */) {
--it;
- LogBufferElement *element = *it;
- if (element->getSequence() <= start) {
- it++;
+ LogBufferElement* element = *it;
+ if (element->getRealTime() > start) {
+ last = it;
+ } else if (element->getRealTime() < min) {
break;
}
}
+ it = last;
}
+ log_time max = start;
// Help detect if the valid message before is from the same source so
// we can differentiate chatty filter types.
pid_t lastTid[LOG_ID_MAX] = { 0 };
for (; it != mLogElements.end(); ++it) {
- LogBufferElement *element = *it;
+ LogBufferElement* element = *it;
if (!privileged && (element->getUid() != uid)) {
continue;
@@ -1113,7 +1120,7 @@
continue;
}
- if (element->getSequence() <= start) {
+ if (element->getRealTime() <= start) {
continue;
}
@@ -1134,8 +1141,8 @@
// multiple identical squash. chatty that differs source
// is due to spam filter. chatty to chatty of different
// source is also due to spam filter.
- lastTid[element->getLogId()] = (element->getDropped() && !sameTid) ?
- 0 : element->getTid();
+ lastTid[element->getLogId()] =
+ (element->getDropped() && !sameTid) ? 0 : element->getTid();
pthread_mutex_unlock(&mLogElementsLock);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index da63e12..fcf6b9a 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -27,9 +27,9 @@
#include <sysutils/SocketClient.h>
#include "LogBufferElement.h"
+#include "LogStatistics.h"
#include "LogTags.h"
#include "LogTimes.h"
-#include "LogStatistics.h"
#include "LogWhiteBlackList.h"
//
@@ -41,7 +41,7 @@
//
namespace android {
-static bool isMonotonic(const log_time &mono) {
+static bool isMonotonic(const log_time& mono) {
static const uint32_t EPOCH_PLUS_2_YEARS = 2 * 24 * 60 * 60 * 1461 / 4;
static const uint32_t EPOCH_PLUS_MINUTE = 60;
@@ -70,10 +70,9 @@
/* dividing line half way between monotonic and realtime */
return mono.tv_sec < ((cpu.tv_sec + now.tv_sec) / 2);
}
-
}
-typedef std::list<LogBufferElement *> LogBufferElementCollection;
+typedef std::list<LogBufferElement*> LogBufferElementCollection;
class LogBuffer {
LogBufferElementCollection mLogElements;
@@ -86,14 +85,12 @@
LogBufferElementCollection::iterator mLast[LOG_ID_MAX];
bool mLastSet[LOG_ID_MAX];
// watermark of any worst/chatty uid processing
- typedef std::unordered_map<uid_t,
- LogBufferElementCollection::iterator>
- LogBufferIteratorMap;
+ typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
+ LogBufferIteratorMap;
LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
// watermark of any worst/chatty pid of system processing
- typedef std::unordered_map<pid_t,
- LogBufferElementCollection::iterator>
- LogBufferPidIteratorMap;
+ typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator>
+ LogBufferPidIteratorMap;
LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
unsigned long mMaxSize[LOG_ID_MAX];
@@ -106,21 +103,23 @@
LogBufferElement* droppedElements[LOG_ID_MAX];
void log(LogBufferElement* elem);
-public:
- LastLogTimes &mTimes;
+ public:
+ LastLogTimes& mTimes;
- explicit LogBuffer(LastLogTimes *times);
+ explicit LogBuffer(LastLogTimes* times);
~LogBuffer();
void init();
- bool isMonotonic() { return monotonic; }
+ bool isMonotonic() {
+ return monotonic;
+ }
- int log(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len);
- uint64_t flushTo(SocketClient *writer, const uint64_t start,
+ int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+ const char* msg, unsigned short len);
+ log_time flushTo(SocketClient* writer, const log_time& start,
bool privileged, bool security,
- int (*filter)(const LogBufferElement *element, void *arg) = NULL,
- void *arg = NULL);
+ int (*filter)(const LogBufferElement* element,
+ void* arg) = NULL,
+ void* arg = NULL);
bool clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
@@ -133,24 +132,42 @@
stats.enableStatistics();
}
- int initPrune(const char *cp) { return mPrune.init(cp); }
- std::string formatPrune() { return mPrune.format(); }
+ int initPrune(const char* cp) {
+ return mPrune.init(cp);
+ }
+ std::string formatPrune() {
+ return mPrune.format();
+ }
- std::string formatGetEventTag(uid_t uid,
- const char *name, const char *format) {
+ std::string formatGetEventTag(uid_t uid, const char* name,
+ const char* format) {
return tags.formatGetEventTag(uid, name, format);
}
- const char *tagToName(uint32_t tag) { return tags.tagToName(tag); }
+ std::string formatEntry(uint32_t tag, uid_t uid) {
+ return tags.formatEntry(tag, uid);
+ }
+ const char* tagToName(uint32_t tag) {
+ return tags.tagToName(tag);
+ }
// helper must be protected directly or implicitly by lock()/unlock()
- const char *pidToName(pid_t pid) { return stats.pidToName(pid); }
- uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
- const char *uidToName(uid_t uid) { return stats.uidToName(uid); }
- void lock() { pthread_mutex_lock(&mLogElementsLock); }
- void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
+ const char* pidToName(pid_t pid) {
+ return stats.pidToName(pid);
+ }
+ uid_t pidToUid(pid_t pid) {
+ return stats.pidToUid(pid);
+ }
+ const char* uidToName(uid_t uid) {
+ return stats.uidToName(uid);
+ }
+ void lock() {
+ pthread_mutex_lock(&mLogElementsLock);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&mLogElementsLock);
+ }
-private:
-
+ private:
static constexpr size_t minPrune = 4;
static constexpr size_t maxPrune = 256;
@@ -160,4 +177,4 @@
LogBufferElementCollection::iterator it, bool coalesce = false);
};
-#endif // _LOGD_LOG_BUFFER_H__
+#endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index a651fd4..81356fe 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -30,46 +30,44 @@
#include "LogReader.h"
#include "LogUtils.h"
-const uint64_t LogBufferElement::FLUSH_ERROR(0);
+const log_time LogBufferElement::FLUSH_ERROR((uint32_t)-1, (uint32_t)-1);
atomic_int_fast64_t LogBufferElement::sequence(1);
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len) :
- mUid(uid),
- mPid(pid),
- mTid(tid),
- mSequence(sequence.fetch_add(1, memory_order_relaxed)),
- mRealTime(realtime),
- mMsgLen(len),
- mLogId(log_id) {
+ const char* msg, unsigned short len)
+ : mUid(uid),
+ mPid(pid),
+ mTid(tid),
+ mRealTime(realtime),
+ mMsgLen(len),
+ mLogId(log_id) {
mMsg = new char[len];
memcpy(mMsg, msg, len);
- mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
- le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
- 0;
+ mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t)))
+ ? le32toh(reinterpret_cast<android_event_header_t*>(mMsg)->tag)
+ : 0;
}
-LogBufferElement::LogBufferElement(const LogBufferElement &elem) :
- mTag(elem.mTag),
- mUid(elem.mUid),
- mPid(elem.mPid),
- mTid(elem.mTid),
- mSequence(elem.mSequence),
- mRealTime(elem.mRealTime),
- mMsgLen(elem.mMsgLen),
- mLogId(elem.mLogId) {
+LogBufferElement::LogBufferElement(const LogBufferElement& elem)
+ : mTag(elem.mTag),
+ mUid(elem.mUid),
+ mPid(elem.mPid),
+ mTid(elem.mTid),
+ mRealTime(elem.mRealTime),
+ mMsgLen(elem.mMsgLen),
+ mLogId(elem.mLogId) {
mMsg = new char[mMsgLen];
memcpy(mMsg, elem.mMsg, mMsgLen);
}
LogBufferElement::~LogBufferElement() {
- delete [] mMsg;
+ delete[] mMsg;
}
// caller must own and free character string
-char *android::tidToName(pid_t tid) {
- char *retval = NULL;
+char* android::tidToName(pid_t tid) {
+ char* retval = NULL;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
int fd = open(buffer, O_RDONLY);
@@ -89,7 +87,7 @@
}
// if nothing for comm, check out cmdline
- char *name = android::pidToName(tid);
+ char* name = android::pidToName(tid);
if (!retval) {
retval = name;
name = NULL;
@@ -101,8 +99,8 @@
size_t retval_len = strlen(retval);
size_t name_len = strlen(name);
// KISS: ToDo: Only checks prefix truncated, not suffix, or both
- if ((retval_len < name_len)
- && !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
+ if ((retval_len < name_len) &&
+ !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
free(retval);
retval = name;
} else {
@@ -113,21 +111,20 @@
}
// assumption: mMsg == NULL
-size_t LogBufferElement::populateDroppedMessage(char*& buffer,
- LogBuffer* parent, bool lastSame) {
+size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent,
+ bool lastSame) {
static const char tag[] = "chatty";
- if (!__android_log_is_loggable_len(ANDROID_LOG_INFO,
- tag, strlen(tag),
+ if (!__android_log_is_loggable_len(ANDROID_LOG_INFO, tag, strlen(tag),
ANDROID_LOG_VERBOSE)) {
return 0;
}
static const char format_uid[] = "uid=%u%s%s %s %u line%s";
parent->lock();
- const char *name = parent->uidToName(mUid);
+ const char* name = parent->uidToName(mUid);
parent->unlock();
- const char *commName = android::tidToName(mTid);
+ const char* commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
commName = android::tidToName(mPid);
}
@@ -140,35 +137,35 @@
size_t len = strlen(name + 1);
if (!strncmp(name + 1, commName + 1, len)) {
if (commName[len + 1] == '\0') {
- free(const_cast<char *>(commName));
+ free(const_cast<char*>(commName));
commName = NULL;
} else {
- free(const_cast<char *>(name));
+ free(const_cast<char*>(name));
name = NULL;
}
}
}
if (name) {
- char *buf = NULL;
+ char* buf = NULL;
asprintf(&buf, "(%s)", name);
if (buf) {
- free(const_cast<char *>(name));
+ free(const_cast<char*>(name));
name = buf;
}
}
if (commName) {
- char *buf = NULL;
+ char* buf = NULL;
asprintf(&buf, " %s", commName);
if (buf) {
- free(const_cast<char *>(commName));
+ free(const_cast<char*>(commName));
commName = buf;
}
}
// identical to below to calculate the buffer size required
const char* type = lastSame ? "identical" : "expire";
size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
- commName ? commName : "", type,
- mDropped, (mDropped > 1) ? "s" : "");
+ commName ? commName : "", type, mDropped,
+ (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (isBinary()) {
@@ -177,17 +174,17 @@
hdrLen = 1 + sizeof(tag);
}
- buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
+ buffer = static_cast<char*>(calloc(1, hdrLen + len + 1));
if (!buffer) {
- free(const_cast<char *>(name));
- free(const_cast<char *>(commName));
+ free(const_cast<char*>(name));
+ free(const_cast<char*>(commName));
return 0;
}
size_t retval = hdrLen + len;
if (isBinary()) {
- android_log_event_string_t *event =
- reinterpret_cast<android_log_event_string_t *>(buffer);
+ android_log_event_string_t* event =
+ reinterpret_cast<android_log_event_string_t*>(buffer);
event->header.tag = htole32(CHATTY_LOG_TAG);
event->type = EVENT_TYPE_STRING;
@@ -199,23 +196,22 @@
}
snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
- commName ? commName : "", type,
- mDropped, (mDropped > 1) ? "s" : "");
- free(const_cast<char *>(name));
- free(const_cast<char *>(commName));
+ commName ? commName : "", type, mDropped,
+ (mDropped > 1) ? "s" : "");
+ free(const_cast<char*>(name));
+ free(const_cast<char*>(commName));
return retval;
}
-uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
+log_time LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
bool privileged, bool lastSame) {
struct logger_entry_v4 entry;
memset(&entry, 0, sizeof(struct logger_entry_v4));
- entry.hdr_size = privileged ?
- sizeof(struct logger_entry_v4) :
- sizeof(struct logger_entry_v3);
+ entry.hdr_size = privileged ? sizeof(struct logger_entry_v4)
+ : sizeof(struct logger_entry_v3);
entry.lid = mLogId;
entry.pid = mPid;
entry.tid = mTid;
@@ -227,13 +223,11 @@
iovec[0].iov_base = &entry;
iovec[0].iov_len = entry.hdr_size;
- char *buffer = NULL;
+ char* buffer = NULL;
if (!mMsg) {
entry.len = populateDroppedMessage(buffer, parent, lastSame);
- if (!entry.len) {
- return mSequence;
- }
+ if (!entry.len) return mRealTime;
iovec[1].iov_base = buffer;
} else {
entry.len = mMsgLen;
@@ -241,11 +235,9 @@
}
iovec[1].iov_len = entry.len;
- uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
+ log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
- if (buffer) {
- free(buffer);
- }
+ if (buffer) free(buffer);
return retval;
}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index bd98b9c..814ec87 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -26,69 +26,82 @@
class LogBuffer;
-#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
- // non-chatty UIDs less than this age in hours
-#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
- // chatty for the temporal expire messages
-#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
+#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
+ // non-chatty UIDs less than this age in hours
+#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
+ // chatty for the temporal expire messages
+#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
class LogBufferElement {
-
friend LogBuffer;
// sized to match reality of incoming log packets
- uint32_t mTag; // only valid for isBinary()
+ uint32_t mTag; // only valid for isBinary()
const uint32_t mUid;
const uint32_t mPid;
const uint32_t mTid;
- const uint64_t mSequence;
log_time mRealTime;
- char *mMsg;
+ char* mMsg;
union {
- const uint16_t mMsgLen; // mMSg != NULL
- uint16_t mDropped; // mMsg == NULL
+ const uint16_t mMsgLen; // mMSg != NULL
+ uint16_t mDropped; // mMsg == NULL
};
const uint8_t mLogId;
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
- size_t populateDroppedMessage(char*& buffer,
- LogBuffer* parent,
+ size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
bool lastSame);
-public:
- LogBufferElement(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len);
- LogBufferElement(const LogBufferElement &elem);
+
+ public:
+ LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
+ pid_t tid, const char* msg, unsigned short len);
+ LogBufferElement(const LogBufferElement& elem);
virtual ~LogBufferElement();
bool isBinary(void) const {
return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
}
- log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
- uid_t getUid(void) const { return mUid; }
- pid_t getPid(void) const { return mPid; }
- pid_t getTid(void) const { return mTid; }
- uint32_t getTag() const { return mTag; }
- unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
+ log_id_t getLogId() const {
+ return static_cast<log_id_t>(mLogId);
+ }
+ uid_t getUid(void) const {
+ return mUid;
+ }
+ pid_t getPid(void) const {
+ return mPid;
+ }
+ pid_t getTid(void) const {
+ return mTid;
+ }
+ uint32_t getTag() const {
+ return mTag;
+ }
+ unsigned short getDropped(void) const {
+ return mMsg ? 0 : mDropped;
+ }
unsigned short setDropped(unsigned short value) {
if (mMsg) {
- delete [] mMsg;
+ delete[] mMsg;
mMsg = NULL;
}
return mDropped = value;
}
- unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
- const char* getMsg() const { return mMsg; }
- uint64_t getSequence(void) const { return mSequence; }
- static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
- log_time getRealTime(void) const { return mRealTime; }
+ unsigned short getMsgLen() const {
+ return mMsg ? mMsgLen : 0;
+ }
+ const char* getMsg() const {
+ return mMsg;
+ }
+ log_time getRealTime(void) const {
+ return mRealTime;
+ }
- static const uint64_t FLUSH_ERROR;
- uint64_t flushTo(SocketClient* writer, LogBuffer* parent,
- bool privileged, bool lastSame);
+ static const log_time FLUSH_ERROR;
+ log_time flushTo(SocketClient* writer, LogBuffer* parent, bool privileged,
+ bool lastSame);
};
#endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 3b17576..6d7c0a5 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -24,7 +24,7 @@
#include "LogCommand.h"
#include "LogUtils.h"
-LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
+LogCommand::LogCommand(const char* cmd) : FrameworkCommand(cmd) {
}
// gets a list of supplementary group IDs associated with
@@ -40,8 +40,8 @@
// has open permissions, and one that has restricted
// permissions.
-static bool groupIsLog(char *buf) {
- char *ptr;
+static bool groupIsLog(char* buf) {
+ char* ptr;
static const char ws[] = " \n";
for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
@@ -91,15 +91,14 @@
// doubt, but we expect the falses should be reduced significantly as
// three times is a charm.
//
- for (int retry = 3;
- !(ret = foundGid && foundUid && foundLog) && retry;
- --retry) {
- FILE *file = fopen(filename, "r");
+ for (int retry = 3; !(ret = foundGid && foundUid && foundLog) && retry;
+ --retry) {
+ FILE* file = fopen(filename, "r");
if (!file) {
continue;
}
- char *line = NULL;
+ char* line = NULL;
size_t len = 0;
while (getline(&line, &len, file) > 0) {
static const char groups_string[] = "Groups:\t";
@@ -111,29 +110,25 @@
foundLog = true;
}
} else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
- uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
+ uid_t u[4] = { (uid_t)-1, (uid_t)-1, (uid_t)-1, (uid_t)-1 };
- sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u",
- &u[0], &u[1], &u[2], &u[3]);
+ sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u", &u[0],
+ &u[1], &u[2], &u[3]);
// Protect against PID reuse by checking that UID is the same
- if ((uid == u[0])
- && (uid == u[1])
- && (uid == u[2])
- && (uid == u[3])) {
+ if ((uid == u[0]) && (uid == u[1]) && (uid == u[2]) &&
+ (uid == u[3])) {
foundUid = true;
}
} else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
- gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
+ gid_t g[4] = { (gid_t)-1, (gid_t)-1, (gid_t)-1, (gid_t)-1 };
- sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u",
- &g[0], &g[1], &g[2], &g[3]);
+ sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u", &g[0],
+ &g[1], &g[2], &g[3]);
// Protect against PID reuse by checking that GID is the same
- if ((gid == g[0])
- && (gid == g[1])
- && (gid == g[2])
- && (gid == g[3])) {
+ if ((gid == g[0]) && (gid == g[1]) && (gid == g[2]) &&
+ (gid == g[3])) {
foundGid = true;
}
}
@@ -145,6 +140,6 @@
return ret;
}
-bool clientHasLogCredentials(SocketClient *cli) {
+bool clientHasLogCredentials(SocketClient* cli) {
return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index 0adc2a1..e10ffa0 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -17,13 +17,14 @@
#ifndef _LOGD_COMMAND_H
#define _LOGD_COMMAND_H
-#include <sysutils/SocketClient.h>
#include <sysutils/FrameworkCommand.h>
+#include <sysutils/SocketClient.h>
class LogCommand : public FrameworkCommand {
-public:
- explicit LogCommand(const char *cmd);
- virtual ~LogCommand() {}
+ public:
+ explicit LogCommand(const char* cmd);
+ virtual ~LogCommand() {
+ }
};
#endif
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index f224079..9dfa14e 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -25,25 +25,22 @@
#include <sys/uio.h>
#include <syslog.h>
-#include <private/android_logger.h>
#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogReader.h"
-#define KMSG_PRIORITY(PRI) \
- '<', \
- '0' + (LOG_SYSLOG | (PRI)) / 10, \
- '0' + (LOG_SYSLOG | (PRI)) % 10, \
- '>'
+#define KMSG_PRIORITY(PRI) \
+ '<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
// Parsing is hard
// called if we see a '<', s is the next character, returns pointer after '>'
-static char *is_prio(char *s, size_t len) {
+static char* is_prio(char* s, size_t len) {
if (!len || !isdigit(*s++)) {
return NULL;
}
@@ -60,7 +57,7 @@
}
// called if we see a '[', s is the next character, returns pointer after ']'
-static char *is_timestamp(char *s, size_t len) {
+static char* is_timestamp(char* s, size_t len) {
while (len && (*s == ' ')) {
++s;
--len;
@@ -83,19 +80,20 @@
}
// Like strtok_r with "\r\n" except that we look for log signatures (regex)
-// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[] *[0-9]+[.][0-9]+[]] \)
+// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
+// *[0-9]+[.][0-9]+[]] \)
// and split if we see a second one without a newline.
// We allow nuls in content, monitoring the overall length and sub-length of
// the discovered tokens.
-#define SIGNATURE_MASK 0xF0
+#define SIGNATURE_MASK 0xF0
// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
-#define LESS_THAN_SIG SIGNATURE_MASK
-#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
+#define LESS_THAN_SIG SIGNATURE_MASK
+#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
// space is one more than <digit> of 9
#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
-char *log_strntok_r(char *s, size_t *len, char **last, size_t *sublen) {
+char* log_strntok_r(char* s, size_t* len, char** last, size_t* sublen) {
*sublen = 0;
if (!*len) {
return NULL;
@@ -144,32 +142,24 @@
--*len;
size_t adjust;
switch (c) {
- case '\r':
- case '\n':
- s[-1] = '\0';
- *last = s;
- return tok;
-
- case '<':
- peek = is_prio(s, *len);
- if (!peek) {
- break;
- }
- if (s != (tok + 1)) { // not first?
+ case '\r':
+ case '\n':
s[-1] = '\0';
- *s &= ~SIGNATURE_MASK;
- *s |= LESS_THAN_SIG; // signature for '<'
*last = s;
return tok;
- }
- adjust = peek - s;
- if (adjust > *len) {
- adjust = *len;
- }
- *sublen += adjust;
- *len -= adjust;
- s = peek;
- if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
+
+ case '<':
+ peek = is_prio(s, *len);
+ if (!peek) {
+ break;
+ }
+ if (s != (tok + 1)) { // not first?
+ s[-1] = '\0';
+ *s &= ~SIGNATURE_MASK;
+ *s |= LESS_THAN_SIG; // signature for '<'
+ *last = s;
+ return tok;
+ }
adjust = peek - s;
if (adjust > *len) {
adjust = *len;
@@ -177,33 +167,41 @@
*sublen += adjust;
*len -= adjust;
s = peek;
- }
- break;
-
- case '[':
- peek = is_timestamp(s, *len);
- if (!peek) {
- break;
- }
- if (s != (tok + 1)) { // not first?
- s[-1] = '\0';
- if (*s == ' ') {
- *s = OPEN_BRACKET_SPACE;
- } else {
- *s &= ~SIGNATURE_MASK;
- *s |= OPEN_BRACKET_SIG; // signature for '['
+ if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
+ adjust = peek - s;
+ if (adjust > *len) {
+ adjust = *len;
+ }
+ *sublen += adjust;
+ *len -= adjust;
+ s = peek;
}
- *last = s;
- return tok;
- }
- adjust = peek - s;
- if (adjust > *len) {
- adjust = *len;
- }
- *sublen += adjust;
- *len -= adjust;
- s = peek;
- break;
+ break;
+
+ case '[':
+ peek = is_timestamp(s, *len);
+ if (!peek) {
+ break;
+ }
+ if (s != (tok + 1)) { // not first?
+ s[-1] = '\0';
+ if (*s == ' ') {
+ *s = OPEN_BRACKET_SPACE;
+ } else {
+ *s &= ~SIGNATURE_MASK;
+ *s |= OPEN_BRACKET_SIG; // signature for '['
+ }
+ *last = s;
+ return tok;
+ }
+ adjust = peek - s;
+ if (adjust > *len) {
+ adjust = *len;
+ }
+ *sublen += adjust;
+ *len -= adjust;
+ s = peek;
+ break;
}
++*sublen;
}
@@ -215,22 +213,23 @@
? log_time::EPOCH
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
-LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
- SocketListener(fdRead, false),
- logbuf(buf),
- reader(reader),
- signature(CLOCK_MONOTONIC),
- initialized(false),
- enableLogging(true),
- auditd(auditd) {
+LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
+ bool auditd)
+ : SocketListener(fdRead, false),
+ logbuf(buf),
+ reader(reader),
+ signature(CLOCK_MONOTONIC),
+ initialized(false),
+ enableLogging(true),
+ auditd(auditd) {
static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
- signature.nsec());
+ signature.nsec());
write(fdWrite, buffer, strlen(buffer));
}
-bool LogKlog::onDataAvailable(SocketClient *cli) {
+bool LogKlog::onDataAvailable(SocketClient* cli) {
if (!initialized) {
prctl(PR_SET_NAME, "logd.klogd");
initialized = true;
@@ -240,10 +239,11 @@
char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
size_t len = 0;
- for(;;) {
+ for (;;) {
ssize_t retval = 0;
if ((sizeof(buffer) - 1 - len) > 0) {
- retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
+ retval =
+ read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
}
if ((retval == 0) && (len == 0)) {
break;
@@ -253,12 +253,11 @@
}
len += retval;
bool full = len == (sizeof(buffer) - 1);
- char *ep = buffer + len;
+ char* ep = buffer + len;
*ep = '\0';
size_t sublen;
- for(char *ptr = NULL, *tok = buffer;
- ((tok = log_strntok_r(tok, &len, &ptr, &sublen)));
- tok = NULL) {
+ for (char *ptr = NULL, *tok = buffer;
+ ((tok = log_strntok_r(tok, &len, &ptr, &sublen))); tok = NULL) {
if (((tok + sublen) >= ep) && (retval != 0) && full) {
memmove(buffer, tok, sublen);
len = sublen;
@@ -273,12 +272,10 @@
return true;
}
-
-void LogKlog::calculateCorrection(const log_time &monotonic,
- const char *real_string,
- size_t len) {
+void LogKlog::calculateCorrection(const log_time& monotonic,
+ const char* real_string, size_t len) {
log_time real;
- const char *ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
+ const char* ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
return;
}
@@ -323,10 +320,9 @@
return s;
}
-void LogKlog::sniffTime(log_time &now,
- const char **buf, size_t len,
+void LogKlog::sniffTime(log_time& now, const char** buf, size_t len,
bool reverse) {
- const char *cp = now.strptime(*buf, "[ %s.%q]");
+ const char* cp = now.strptime(*buf, "[ %s.%q]");
if (cp && (cp >= &(*buf)[len])) {
cp = NULL;
}
@@ -346,28 +342,28 @@
}
const char* b;
- if (((b = android::strnstr(cp, len, suspendStr)))
- && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
+ if (((b = android::strnstr(cp, len, suspendStr))) &&
+ ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, resumeStr)))
- && ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
+ } else if (((b = android::strnstr(cp, len, resumeStr))) &&
+ ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
len -= b - cp;
calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, healthd)))
- && ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
- && ((b = android::strnstr(b, len -= b - cp, battery)))
- && ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
+ } else if (((b = android::strnstr(cp, len, healthd))) &&
+ ((size_t)((b += sizeof(healthd) - 1) - cp) < len) &&
+ ((b = android::strnstr(b, len -= b - cp, battery))) &&
+ ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
// NB: healthd is roughly 150us late, so we use it instead to
// trigger a check for ntp-induced or hardware clock drift.
log_time real(CLOCK_REALTIME);
log_time mono(CLOCK_MONOTONIC);
correction = (real < mono) ? log_time::EPOCH : (real - mono);
- } else if (((b = android::strnstr(cp, len, suspendedStr)))
- && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
+ } else if (((b = android::strnstr(cp, len, suspendedStr))) &&
+ ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
len -= b - cp;
log_time real;
- char *endp;
+ char* endp;
real.tv_sec = strtol(b, &endp, 10);
if ((*endp == '.') && ((size_t)(endp - b) < len)) {
unsigned long multiplier = NS_PER_SEC;
@@ -398,14 +394,11 @@
}
}
-pid_t LogKlog::sniffPid(const char **buf, size_t len) {
- const char *cp = *buf;
+pid_t LogKlog::sniffPid(const char** buf, size_t len) {
+ const char* cp = *buf;
// HTC kernels with modified printk "c0 1648 "
- if ((len > 9) &&
- (cp[0] == 'c') &&
- isdigit(cp[1]) &&
- (isdigit(cp[2]) || (cp[2] == ' ')) &&
- (cp[3] == ' ')) {
+ if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
+ (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
bool gotDigit = false;
int i;
for (i = 4; i < 9; ++i) {
@@ -419,7 +412,7 @@
int pid = 0;
char dummy;
if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
- *buf = cp + 10; // skip-it-all
+ *buf = cp + 10; // skip-it-all
return pid;
}
}
@@ -432,7 +425,7 @@
if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
return pid;
}
- break; // Only the first one
+ break; // Only the first one
}
++cp;
--len;
@@ -441,12 +434,12 @@
}
// kernel log prefix, convert to a kernel log priority number
-static int parseKernelPrio(const char **buf, size_t len) {
+static int parseKernelPrio(const char** buf, size_t len) {
int pri = LOG_USER | LOG_INFO;
- const char *cp = *buf;
+ const char* cp = *buf;
if (len && (*cp == '<')) {
pri = 0;
- while(--len && isdigit(*++cp)) {
+ while (--len && isdigit(*++cp)) {
pri = (pri * 10) + *cp - '0';
}
if (len && (*cp == '>')) {
@@ -502,42 +495,42 @@
// Convert kernel log priority number into an Android Logger priority number
static int convertKernelPrioToAndroidPrio(int pri) {
- switch(pri & LOG_PRIMASK) {
- case LOG_EMERG:
+ switch (pri & LOG_PRIMASK) {
+ case LOG_EMERG:
// FALLTHRU
- case LOG_ALERT:
+ case LOG_ALERT:
// FALLTHRU
- case LOG_CRIT:
- return ANDROID_LOG_FATAL;
+ case LOG_CRIT:
+ return ANDROID_LOG_FATAL;
- case LOG_ERR:
- return ANDROID_LOG_ERROR;
+ case LOG_ERR:
+ return ANDROID_LOG_ERROR;
- case LOG_WARNING:
- return ANDROID_LOG_WARN;
+ case LOG_WARNING:
+ return ANDROID_LOG_WARN;
- default:
+ default:
// FALLTHRU
- case LOG_NOTICE:
+ case LOG_NOTICE:
// FALLTHRU
- case LOG_INFO:
- break;
+ case LOG_INFO:
+ break;
- case LOG_DEBUG:
- return ANDROID_LOG_DEBUG;
+ case LOG_DEBUG:
+ return ANDROID_LOG_DEBUG;
}
return ANDROID_LOG_INFO;
}
-static const char *strnrchr(const char *s, size_t len, char c) {
- const char *save = NULL;
- for (;len; ++s, len--) {
- if (*s == c) {
- save = s;
+static const char* strnrchr(const char* s, size_t len, char c) {
+ const char* save = NULL;
+ for (; len; ++s, len--) {
+ if (*s == c) {
+ save = s;
+ }
}
- }
- return save;
+ return save;
}
//
@@ -621,38 +614,41 @@
while ((p < &buf[len]) && (isspace(*p) || !*p)) {
++p;
}
- if (p >= &buf[len]) { // timestamp, no content
+ if (p >= &buf[len]) { // timestamp, no content
return 0;
}
start = p;
- const char *tag = "";
- const char *etag = tag;
+ const char* tag = "";
+ const char* etag = tag;
size_t taglen = len - (p - buf);
- const char *bt = p;
+ const char* bt = p;
static const char infoBrace[] = "[INFO]";
static const size_t infoBraceLen = strlen(infoBrace);
- if ((taglen >= infoBraceLen) && !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
+ if ((taglen >= infoBraceLen) &&
+ !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
bt = p + infoBraceLen;
taglen -= infoBraceLen;
}
- const char *et;
- for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
- // skip ':' within [ ... ]
- if (*et == '[') {
- while (taglen && *et && *et != ']') {
- ++et;
- --taglen;
- }
- if (!taglen) {
- break;
- }
- }
+ const char* et;
+ for (et = bt; taglen && *et && (*et != ':') && !isspace(*et);
+ ++et, --taglen) {
+ // skip ':' within [ ... ]
+ if (*et == '[') {
+ while (taglen && *et && *et != ']') {
+ ++et;
+ --taglen;
+ }
+ if (!taglen) {
+ break;
+ }
+ }
}
- const char *cp;
- for (cp = et; taglen && isspace(*cp); ++cp, --taglen);
+ const char* cp;
+ for (cp = et; taglen && isspace(*cp); ++cp, --taglen) {
+ }
// Validate tag
size_t size = et - bt;
@@ -667,18 +663,20 @@
p = cp + 1;
} else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
// clean up any tag stutter
- if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
+ if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
// <PRI>[<TIME>] <tag> <tag> : message
// <PRI>[<TIME>] <tag> <tag>: message
// <PRI>[<TIME>] <tag> '<tag>.<num>' : message
// <PRI>[<TIME>] <tag> '<tag><num>' : message
// <PRI>[<TIME>] <tag> '<tag><stuff>' : message
- const char *b = cp;
+ const char* b = cp;
cp += size;
taglen -= size;
- while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e;
- for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ while (--taglen && !isspace(*++cp) && (*cp != ':')) {
+ }
+ const char* e;
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
+ }
if (taglen && (*cp == ':')) {
tag = b;
etag = e;
@@ -689,15 +687,17 @@
static const char host[] = "_host";
static const size_t hostlen = strlen(host);
if ((size > hostlen) &&
- !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
- !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
- const char *b = cp;
+ !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
+ !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
+ const char* b = cp;
cp += size - hostlen;
taglen -= size - hostlen;
if (*cp == '.') {
- while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e;
- for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ while (--taglen && !isspace(*++cp) && (*cp != ':')) {
+ }
+ const char* e;
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
+ }
if (taglen && (*cp == ':')) {
tag = b;
etag = e;
@@ -709,10 +709,13 @@
}
}
} else {
- // <PRI>[<TIME>] <tag> <stuff>' : message
-twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e;
- for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ // <PRI>[<TIME>] <tag> <stuff>' : message
+ twoWord:
+ while (--taglen && !isspace(*++cp) && (*cp != ':')) {
+ }
+ const char* e;
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
+ }
// Two words
if (taglen && (*cp == ':')) {
tag = bt;
@@ -720,7 +723,7 @@
p = cp + 1;
}
}
- } // else no tag
+ } // else no tag
static const char cpu[] = "CPU";
static const size_t cpuLen = strlen(cpu);
@@ -732,16 +735,17 @@
static const size_t infoLen = strlen(info);
size = etag - tag;
- if ((size <= 1)
+ if ((size <= 1) ||
// register names like x9
- || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+ ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
// register names like x18 but not driver names like en0
- || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
+ ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
// blacklist
- || ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen))
- || ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen))
- || ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen))
- || ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
+ ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
+ ((size == warningLen) &&
+ !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
+ ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
+ ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
p = start;
etag = tag = "";
}
@@ -750,7 +754,7 @@
// eg: [143:healthd]healthd -> [143:healthd]
taglen = etag - tag;
// Mediatek-special printk induced stutter
- const char *mp = strnrchr(tag, ']', taglen);
+ const char* mp = strnrchr(tag, taglen, ']');
if (mp && (++mp < etag)) {
size_t s = etag - mp;
if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
@@ -767,7 +771,7 @@
}
// truncate trailing space or nuls
size_t b = len - (p - buf);
- while (b && (isspace(p[b-1]) || !p[b-1])) {
+ while (b && (isspace(p[b - 1]) || !p[b - 1])) {
--b;
}
// trick ... allow tag with empty content to be logged. log() drops empty
@@ -796,7 +800,7 @@
// truncating length argument to logbuf->log() below. Gain is protection
// of stack sanity and speedup, loss is truncated long-line content.
char newstr[n];
- char *np = newstr;
+ char* np = newstr;
// Convert priority into single-byte Android logger priority
*np = convertKernelPrioToAndroidPrio(pri);
@@ -828,10 +832,10 @@
unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
- if ((abs1 <= 1) && // last two were in agreement on timezone
- ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
+ if ((abs1 <= 1) && // last two were in agreement on timezone
+ ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
- timezones_seconds;
+ timezones_seconds;
now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
}
}
@@ -839,7 +843,7 @@
// Log message
int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
- (unsigned short) n);
+ (unsigned short)n);
// notify readers
if (!rc) {
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 11d88af..976afc8 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -20,14 +20,14 @@
#include <private/android_logger.h>
#include <sysutils/SocketListener.h>
-char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
+char* log_strntok_r(char* s, size_t* len, char** saveptr, size_t* sublen);
class LogBuffer;
class LogReader;
class LogKlog : public SocketListener {
- LogBuffer *logbuf;
- LogReader *reader;
+ LogBuffer* logbuf;
+ LogReader* reader;
const log_time signature;
// Set once thread is started, separates KLOG_ACTION_READ_ALL
// and KLOG_ACTION_READ phases.
@@ -40,22 +40,28 @@
static log_time correction;
-public:
- LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
- int log(const char *buf, size_t len);
- void synchronize(const char *buf, size_t len);
+ public:
+ LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
+ bool auditd);
+ int log(const char* buf, size_t len);
+ void synchronize(const char* buf, size_t len);
- bool isMonotonic() { return logbuf->isMonotonic(); }
- static void convertMonotonicToReal(log_time &real) { real += correction; }
- static void convertRealToMonotonic(log_time &real) { real -= correction; }
+ bool isMonotonic() {
+ return logbuf->isMonotonic();
+ }
+ static void convertMonotonicToReal(log_time& real) {
+ real += correction;
+ }
+ static void convertRealToMonotonic(log_time& real) {
+ real -= correction;
+ }
-protected:
- void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
- pid_t sniffPid(const char **buf, size_t len);
- void calculateCorrection(const log_time &monotonic,
- const char *real_string, size_t len);
- virtual bool onDataAvailable(SocketClient *cli);
-
+ protected:
+ void sniffTime(log_time& now, const char** buf, size_t len, bool reverse);
+ pid_t sniffPid(const char** buf, size_t len);
+ void calculateCorrection(const log_time& monotonic, const char* real_string,
+ size_t len);
+ virtual bool onDataAvailable(SocketClient* cli);
};
#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 4a30e6d..dadc75f 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -30,32 +30,24 @@
#include "LogListener.h"
#include "LogUtils.h"
-LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
- SocketListener(getLogSocket(), false),
- logbuf(buf),
- reader(reader) {
+LogListener::LogListener(LogBuffer* buf, LogReader* reader)
+ : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {
}
-bool LogListener::onDataAvailable(SocketClient *cli) {
+bool LogListener::onDataAvailable(SocketClient* cli) {
static bool name_set;
if (!name_set) {
prctl(PR_SET_NAME, "logd.writer");
name_set = true;
}
- char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
- + LOGGER_ENTRY_MAX_PAYLOAD];
+ char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) +
+ LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
- NULL,
- 0,
- &iov,
- 1,
- control,
- sizeof(control),
- 0,
+ NULL, 0, &iov, 1, control, sizeof(control), 0,
};
int socket = cli->getSocket();
@@ -68,13 +60,13 @@
return false;
}
- struct ucred *cred = NULL;
+ struct ucred* cred = NULL;
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
while (cmsg != NULL) {
- if (cmsg->cmsg_level == SOL_SOCKET
- && cmsg->cmsg_type == SCM_CREDENTIALS) {
- cred = (struct ucred *)CMSG_DATA(cmsg);
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS) {
+ cred = (struct ucred*)CMSG_DATA(cmsg);
break;
}
cmsg = CMSG_NXTHDR(&hdr, cmsg);
@@ -91,26 +83,29 @@
return false;
}
- android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
- if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
+ android_log_header_t* header =
+ reinterpret_cast<android_log_header_t*>(buffer);
+ if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX ||
+ header->id == LOG_ID_KERNEL) {
return false;
}
if ((header->id == LOG_ID_SECURITY) &&
- (!__android_log_security() ||
- !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
+ (!__android_log_security() ||
+ !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
return false;
}
- char *msg = ((char *)buffer) + sizeof(android_log_header_t);
+ char* msg = ((char*)buffer) + sizeof(android_log_header_t);
n -= sizeof(android_log_header_t);
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
- if (logbuf->log((log_id_t)header->id, header->realtime,
- cred->uid, cred->pid, header->tid, msg,
- ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
+ if (logbuf->log((log_id_t)header->id, header->realtime, cred->uid,
+ cred->pid, header->tid, msg,
+ ((size_t)n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX) >=
+ 0) {
reader->notifyNewLog();
}
@@ -122,9 +117,8 @@
int sock = android_get_control_socket(socketName);
if (sock < 0) {
- sock = socket_local_server(socketName,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_DGRAM);
+ sock = socket_local_server(
+ socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
}
int on = 1;
diff --git a/logd/LogListener.h b/logd/LogListener.h
index 7099e13..2973b8b 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -21,16 +21,16 @@
#include "LogReader.h"
class LogListener : public SocketListener {
- LogBuffer *logbuf;
- LogReader *reader;
+ LogBuffer* logbuf;
+ LogReader* reader;
-public:
- LogListener(LogBuffer *buf, LogReader *reader);
+ public:
+ LogListener(LogBuffer* buf, LogReader* reader);
-protected:
- virtual bool onDataAvailable(SocketClient *cli);
+ protected:
+ virtual bool onDataAvailable(SocketClient* cli);
-private:
+ private:
static int getLogSocket();
};
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 1b50b4e..620d4d0 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -29,9 +29,8 @@
#include "LogReader.h"
#include "LogUtils.h"
-LogReader::LogReader(LogBuffer *logbuf) :
- SocketListener(getLogSocket(), true),
- mLogbuf(*logbuf) {
+LogReader::LogReader(LogBuffer* logbuf)
+ : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
}
// When we are notified a new log entry is available, inform
@@ -41,7 +40,7 @@
runOnEachSocket(&command);
}
-bool LogReader::onDataAvailable(SocketClient *cli) {
+bool LogReader::onDataAvailable(SocketClient* cli) {
static bool name_set;
if (!name_set) {
prctl(PR_SET_NAME, "logd.reader");
@@ -59,7 +58,7 @@
unsigned long tail = 0;
static const char _tail[] = " tail=";
- char *cp = strstr(buffer, _tail);
+ char* cp = strstr(buffer, _tail);
if (cp) {
tail = atol(cp + sizeof(_tail) - 1);
}
@@ -117,54 +116,70 @@
nonBlock = true;
}
- uint64_t sequence = 1;
- // Convert realtime to sequence number
- if (start != log_time::EPOCH) {
- class LogFindStart {
+ log_time sequence = start;
+ //
+ // This somewhat expensive data validation operation is required
+ // for non-blocking, with timeout. The incoming timestamp must be
+ // in range of the list, if not, return immediately. This is
+ // used to prevent us from from getting stuck in timeout processing
+ // with an invalid time.
+ //
+ // Find if time is really present in the logs, monotonic or real, implicit
+ // conversion from monotonic or real as necessary to perform the check.
+ // Exit in the check loop ASAP as you find a transition from older to
+ // newer, but use the last entry found to ensure overlap.
+ //
+ if (nonBlock && (sequence != log_time::EPOCH) && timeout) {
+ class LogFindStart { // A lambda by another name
+ private:
const pid_t mPid;
const unsigned mLogMask;
- bool startTimeSet;
- log_time &start;
- uint64_t &sequence;
- uint64_t last;
- bool isMonotonic;
+ bool mStartTimeSet;
+ log_time mStart;
+ log_time& mSequence;
+ log_time mLast;
+ bool mIsMonotonic;
- public:
- LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence, bool isMonotonic) :
- mPid(pid),
- mLogMask(logMask),
- startTimeSet(false),
- start(start),
- sequence(sequence),
- last(sequence),
- isMonotonic(isMonotonic) {
+ public:
+ LogFindStart(pid_t pid, unsigned logMask, log_time& sequence,
+ bool isMonotonic)
+ : mPid(pid),
+ mLogMask(logMask),
+ mStartTimeSet(false),
+ mStart(sequence),
+ mSequence(sequence),
+ mLast(sequence),
+ mIsMonotonic(isMonotonic) {
}
- static int callback(const LogBufferElement *element, void *obj) {
- LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
- if ((!me->mPid || (me->mPid == element->getPid()))
- && (me->mLogMask & (1 << element->getLogId()))) {
- if (me->start == element->getRealTime()) {
- me->sequence = element->getSequence();
- me->startTimeSet = true;
+ static int callback(const LogBufferElement* element, void* obj) {
+ LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
+ if ((!me->mPid || (me->mPid == element->getPid())) &&
+ (me->mLogMask & (1 << element->getLogId()))) {
+ log_time real = element->getRealTime();
+ if (me->mStart == real) {
+ me->mSequence = real;
+ me->mStartTimeSet = true;
return -1;
- } else if (!me->isMonotonic ||
- android::isMonotonic(element->getRealTime())) {
- if (me->start < element->getRealTime()) {
- me->sequence = me->last;
- me->startTimeSet = true;
+ } else if (!me->mIsMonotonic || android::isMonotonic(real)) {
+ if (me->mStart < real) {
+ me->mSequence = me->mLast;
+ me->mStartTimeSet = true;
return -1;
}
- me->last = element->getSequence();
+ me->mLast = real;
} else {
- me->last = element->getSequence();
+ me->mLast = real;
}
}
return false;
}
- bool found() { return startTimeSet; }
- } logFindStart(logMask, pid, start, sequence,
+ bool found() {
+ return mStartTimeSet;
+ }
+
+ } logFindStart(pid, logMask, sequence,
logbuf().isMonotonic() && android::isMonotonic(start));
logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
@@ -172,11 +187,8 @@
logFindStart.callback, &logFindStart);
if (!logFindStart.found()) {
- if (nonBlock) {
- doSocketDelete(cli);
- return false;
- }
- sequence = LogBufferElement::getCurrentSequence();
+ doSocketDelete(cli);
+ return false;
}
}
@@ -184,18 +196,19 @@
// Set acceptable upper limit to wait for slow reader processing b/27242723
struct timeval t = { LOGD_SNDTIMEO, 0 };
- setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char *)&t, sizeof(t));
+ setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
+ sizeof(t));
command.runSocketCommand(cli);
return true;
}
-void LogReader::doSocketDelete(SocketClient *cli) {
- LastLogTimes × = mLogbuf.mTimes;
+void LogReader::doSocketDelete(SocketClient* cli) {
+ LastLogTimes& times = mLogbuf.mTimes;
LogTimeEntry::lock();
LastLogTimes::iterator it = times.begin();
- while(it != times.end()) {
- LogTimeEntry *entry = (*it);
+ while (it != times.end()) {
+ LogTimeEntry* entry = (*it);
if (entry->mClient == cli) {
times.erase(it);
entry->release_Locked();
@@ -211,9 +224,8 @@
int sock = android_get_control_socket(socketName);
if (sock < 0) {
- sock = socket_local_server(socketName,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
+ sock = socket_local_server(
+ socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
}
return sock;
diff --git a/logd/LogReader.h b/logd/LogReader.h
index fdcedf1..271e08c 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -24,22 +24,23 @@
class LogBuffer;
class LogReader : public SocketListener {
- LogBuffer &mLogbuf;
+ LogBuffer& mLogbuf;
-public:
- explicit LogReader(LogBuffer *logbuf);
+ public:
+ explicit LogReader(LogBuffer* logbuf);
void notifyNewLog();
- LogBuffer &logbuf(void) const { return mLogbuf; }
+ LogBuffer& logbuf(void) const {
+ return mLogbuf;
+ }
-protected:
- virtual bool onDataAvailable(SocketClient *cli);
+ protected:
+ virtual bool onDataAvailable(SocketClient* cli);
-private:
+ private:
static int getLogSocket();
- void doSocketDelete(SocketClient *cli);
-
+ void doSocketDelete(SocketClient* cli);
};
#endif
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 7e0a6b7..cc30f77 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -41,12 +41,14 @@
namespace android {
-size_t sizesTotal() { return LogStatistics::sizesTotal(); }
+size_t sizesTotal() {
+ return LogStatistics::sizesTotal();
+}
// caller must own and free character string
-char *pidToName(pid_t pid) {
- char *retval = NULL;
- if (pid == 0) { // special case from auditd/klogd for kernel
+char* pidToName(pid_t pid) {
+ char* retval = NULL;
+ if (pid == 0) { // special case from auditd/klogd for kernel
retval = strdup("logd");
} else {
char buffer[512];
@@ -55,7 +57,7 @@
if (fd >= 0) {
ssize_t ret = read(fd, buffer, sizeof(buffer));
if (ret > 0) {
- buffer[sizeof(buffer)-1] = '\0';
+ buffer[sizeof(buffer) - 1] = '\0';
// frameworks intermediate state
if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
retval = strdup(buffer);
@@ -66,10 +68,9 @@
}
return retval;
}
-
}
-void LogStatistics::add(LogBufferElement *element) {
+void LogStatistics::add(LogBufferElement* element) {
log_id_t log_id = element->getLogId();
unsigned short size = element->getMsgLen();
mSizes[log_id] += size;
@@ -114,7 +115,7 @@
}
}
-void LogStatistics::subtract(LogBufferElement *element) {
+void LogStatistics::subtract(LogBufferElement* element) {
log_id_t log_id = element->getLogId();
unsigned short size = element->getMsgLen();
mSizes[log_id] -= size;
@@ -151,7 +152,7 @@
// Atomically set an entry to drop
// entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::drop(LogBufferElement *element) {
+void LogStatistics::drop(LogBufferElement* element) {
log_id_t log_id = element->getLogId();
unsigned short size = element->getMsgLen();
mSizes[log_id] -= size;
@@ -180,7 +181,7 @@
}
// caller must own and free character string
-const char *LogStatistics::uidToName(uid_t uid) const {
+const char* LogStatistics::uidToName(uid_t uid) const {
// Local hard coded favourites
if (uid == AID_LOGD) {
return strdup("auditd");
@@ -189,7 +190,7 @@
// Android system
if (uid < AID_APP) {
// in bionic, thread safe as long as we copy the results
- struct passwd *pwd = getpwuid(uid);
+ struct passwd* pwd = getpwuid(uid);
if (pwd) {
return strdup(pwd->pw_name);
}
@@ -197,7 +198,7 @@
// Parse /data/system/packages.list
uid_t userId = uid % AID_USER_OFFSET;
- const char *name = android::uidToName(userId);
+ const char* name = android::uidToName(userId);
if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
}
@@ -207,24 +208,25 @@
// Android application
if (uid >= AID_APP) {
- struct passwd *pwd = getpwuid(uid);
+ struct passwd* pwd = getpwuid(uid);
if (pwd) {
return strdup(pwd->pw_name);
}
}
// report uid -> pid(s) -> pidToName if unique
- for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
- const PidEntry &entry = it->second;
+ for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
+ ++it) {
+ const PidEntry& entry = it->second;
if (entry.getUid() == uid) {
- const char *nameTmp = entry.getName();
+ const char* nameTmp = entry.getName();
if (nameTmp) {
if (!name) {
name = strdup(nameTmp);
} else if (fastcmp<strcmp>(name, nameTmp)) {
- free(const_cast<char *>(name));
+ free(const_cast<char*>(name));
name = NULL;
break;
}
@@ -236,26 +238,24 @@
return name;
}
-std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
+std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
bool isprune = worstUidEnabledForLogid(id);
- return formatLine(android::base::StringPrintf(
- name.c_str(), android_log_id_to_name(id)),
+ return formatLine(android::base::StringPrintf(name.c_str(),
+ android_log_id_to_name(id)),
std::string("Size"),
- std::string(isprune ? "+/- Pruned" : ""))
- + formatLine(std::string("UID PACKAGE"),
- std::string("BYTES"),
+ std::string(isprune ? "+/- Pruned" : "")) +
+ formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
std::string(isprune ? "NUM" : ""));
}
-std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
+std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%u", uid);
- const char *nameTmp = stat.uidToName(uid);
+ const char* nameTmp = stat.uidToName(uid);
if (nameTmp) {
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
- "", nameTmp);
- free(const_cast<char *>(nameTmp));
+ "%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp);
+ free(const_cast<char*>(nameTmp));
}
std::string size = android::base::StringPrintf("%zu", getSizes());
@@ -263,15 +263,16 @@
std::string pruned = "";
if (worstUidEnabledForLogid(id)) {
size_t totalDropped = 0;
- for (LogStatistics::uidTable_t::const_iterator it = stat.uidTable[id].begin();
- it != stat.uidTable[id].end(); ++it) {
+ for (LogStatistics::uidTable_t::const_iterator it =
+ stat.uidTable[id].begin();
+ it != stat.uidTable[id].end(); ++it) {
totalDropped += it->second.getDropped();
}
size_t sizes = stat.sizes(id);
size_t totalSize = stat.sizesTotal(id);
size_t totalElements = stat.elementsTotal(id);
- float totalVirtualSize = (float)sizes + (float)totalDropped * totalSize
- / totalElements;
+ float totalVirtualSize =
+ (float)sizes + (float)totalDropped * totalSize / totalElements;
size_t entrySize = getSizes();
float virtualEntrySize = entrySize;
int realPermille = virtualEntrySize * 1000.0 / sizes;
@@ -281,31 +282,29 @@
virtualEntrySize += (float)dropped * totalSize / totalElements;
}
int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
- int permille = (realPermille - virtualPermille) * 1000L
- / (virtualPermille ?: 1);
+ int permille =
+ (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
if ((permille < -1) || (1 < permille)) {
std::string change;
- const char *units = "%";
- const char *prefix = (permille > 0) ? "+" : "";
+ const char* units = "%";
+ const char* prefix = (permille > 0) ? "+" : "";
if (permille > 999) {
- permille = (permille + 1000) / 100; // Now tenths fold
+ permille = (permille + 1000) / 100; // Now tenths fold
units = "X";
prefix = "";
}
if ((-99 < permille) && (permille < 99)) {
- change = android::base::StringPrintf("%s%d.%u%s",
- prefix,
- permille / 10,
+ change = android::base::StringPrintf(
+ "%s%d.%u%s", prefix, permille / 10,
((permille < 0) ? (-permille % 10) : (permille % 10)),
units);
} else {
- change = android::base::StringPrintf("%s%d%s",
- prefix,
- (permille + 5) / 10, units);
+ change = android::base::StringPrintf(
+ "%s%d%s", prefix, (permille + 5) / 10, units);
}
- ssize_t spaces = EntryBaseConstants::pruned_len
- - 2 - pruned.length() - change.length();
+ ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
+ pruned.length() - change.length();
if ((spaces <= 0) && pruned.length()) {
spaces = 1;
}
@@ -323,8 +322,8 @@
}
static const size_t maximum_sorted_entries = 32;
- std::unique_ptr<const PidEntry *[]> sorted
- = stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
+ std::unique_ptr<const PidEntry* []> sorted =
+ stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
if (!sorted.get()) {
return output;
@@ -333,7 +332,7 @@
size_t index;
bool hasDropped = false;
for (index = 0; index < maximum_sorted_entries; ++index) {
- const PidEntry *entry = sorted[index];
+ const PidEntry* entry = sorted[index];
if (!entry) {
break;
}
@@ -345,43 +344,39 @@
}
byPid += entry->format(stat, id);
}
- if (index > 1) { // print this only if interesting
+ if (index > 1) { // print this only if interesting
std::string ditto("\" ");
- output += formatLine(std::string(" PID/UID COMMAND LINE"),
- ditto, hasDropped ? ditto : std::string(""));
+ output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
+ hasDropped ? ditto : std::string(""));
output += byPid;
}
return output;
}
-std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
- return formatLine(name,
- std::string("Size"),
- std::string("Pruned"))
- + formatLine(std::string(" PID/UID COMMAND LINE"),
- std::string("BYTES"),
- std::string("NUM"));
+std::string PidEntry::formatHeader(const std::string& name,
+ log_id_t /* id */) const {
+ return formatLine(name, std::string("Size"), std::string("Pruned")) +
+ formatLine(std::string(" PID/UID COMMAND LINE"),
+ std::string("BYTES"), std::string("NUM"));
}
-std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+std::string PidEntry::format(const LogStatistics& stat,
+ log_id_t /* id */) const {
uid_t uid = getUid();
pid_t pid = getPid();
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
- const char *nameTmp = getName();
+ const char* nameTmp = getName();
if (nameTmp) {
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
- "", nameTmp);
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
} else if ((nameTmp = stat.uidToName(uid))) {
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
- "", nameTmp);
- free(const_cast<char *>(nameTmp));
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
+ free(const_cast<char*>(nameTmp));
}
- std::string size = android::base::StringPrintf("%zu",
- getSizes());
+ std::string size = android::base::StringPrintf("%zu", getSizes());
std::string pruned = "";
size_t dropped = getDropped();
@@ -392,36 +387,31 @@
return formatLine(name, size, pruned);
}
-std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
- return formatLine(name,
- std::string("Size"),
- std::string("Pruned"))
- + formatLine(std::string(" TID/UID COMM"),
- std::string("BYTES"),
+std::string TidEntry::formatHeader(const std::string& name,
+ log_id_t /* id */) const {
+ return formatLine(name, std::string("Size"), std::string("Pruned")) +
+ formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
std::string("NUM"));
}
-std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+std::string TidEntry::format(const LogStatistics& stat,
+ log_id_t /* id */) const {
uid_t uid = getUid();
- std::string name = android::base::StringPrintf("%5u/%u",
- getTid(), uid);
- const char *nameTmp = getName();
+ std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
+ const char* nameTmp = getName();
if (nameTmp) {
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
- "", nameTmp);
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
} else if ((nameTmp = stat.uidToName(uid))) {
// if we do not have a PID name, lets punt to try UID name?
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
- "", nameTmp);
- free(const_cast<char *>(nameTmp));
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
+ free(const_cast<char*>(nameTmp));
// We tried, better to not have a name at all, we still
// have TID/UID by number to report in any case.
}
- std::string size = android::base::StringPrintf("%zu",
- getSizes());
+ std::string size = android::base::StringPrintf("%zu", getSizes());
std::string pruned = "";
size_t dropped = getDropped();
@@ -432,35 +422,30 @@
return formatLine(name, size, pruned);
}
-std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
+std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
bool isprune = worstUidEnabledForLogid(id);
- return formatLine(name,
- std::string("Size"),
- std::string(isprune ? "Prune" : ""))
- + formatLine(std::string(" TAG/UID TAGNAME"),
- std::string("BYTES"),
- std::string(isprune ? "NUM" : ""));
+ return formatLine(name, std::string("Size"),
+ std::string(isprune ? "Prune" : "")) +
+ formatLine(std::string(" TAG/UID TAGNAME"),
+ std::string("BYTES"), std::string(isprune ? "NUM" : ""));
}
-std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
+std::string TagEntry::format(const LogStatistics& /* stat */,
+ log_id_t /* id */) const {
std::string name;
uid_t uid = getUid();
if (uid == (uid_t)-1) {
- name = android::base::StringPrintf("%7u",
- getKey());
+ name = android::base::StringPrintf("%7u", getKey());
} else {
- name = android::base::StringPrintf("%7u/%u",
- getKey(), uid);
+ name = android::base::StringPrintf("%7u/%u", getKey(), uid);
}
- const char *nameTmp = getName();
+ const char* nameTmp = getName();
if (nameTmp) {
name += android::base::StringPrintf(
- "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
- "", nameTmp);
+ "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
}
- std::string size = android::base::StringPrintf("%zu",
- getSizes());
+ std::string size = android::base::StringPrintf("%zu", getSizes());
std::string pruned = "";
size_t dropped = getDropped();
@@ -506,11 +491,13 @@
totalSize += szs;
size_t els = elementsTotal(id);
totalEls += els;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
+ output +=
+ android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
spaces += spaces_total + oldLength - output.length();
}
if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
+ output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
+ totalEls);
static const char NowStr[] = "\nNow";
spaces = 10 - strlen(NowStr);
@@ -528,13 +515,15 @@
size_t szs = sizes(id);
totalSize += szs;
totalEls += els;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
+ output +=
+ android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
spaces -= output.length() - oldLength;
}
spaces += spaces_total;
}
if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
+ output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
+ totalEls);
static const char OverheadStr[] = "\nOverhead";
spaces = 10 - strlen(OverheadStr);
@@ -551,7 +540,7 @@
// estimate the std::list overhead.
static const size_t overhead =
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
- -sizeof(uint64_t)) +
+ -sizeof(uint64_t)) +
sizeof(std::list<LogBufferElement*>);
size_t szs = sizes(id) + els * overhead;
totalSize += szs;
@@ -572,16 +561,14 @@
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
- name = (uid == AID_ROOT)
- ? "Chattiest UIDs in %s log buffer:"
- : "Logging for your UID in %s log buffer:";
+ name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
+ : "Logging for your UID in %s log buffer:";
output += uidTable[id].format(*this, uid, pid, name, id);
}
if (enable) {
- name = ((uid == AID_ROOT) && !pid)
- ? "Chattiest PIDs:"
- : "Logging for this PID:";
+ name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
+ : "Logging for this PID:";
output += pidTable.format(*this, uid, pid, name);
name = "Chattiest TIDs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
@@ -600,7 +587,8 @@
name = "Chattiest security log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
+ output +=
+ securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
}
return output;
@@ -611,7 +599,7 @@
uid_t pidToUid(pid_t pid) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
- FILE *fp = fopen(buffer, "r");
+ FILE* fp = fopen(buffer, "r");
if (fp) {
while (fgets(buffer, sizeof(buffer), fp)) {
int uid;
@@ -622,9 +610,8 @@
}
fclose(fp);
}
- return AID_LOGD; // associate this with the logger
+ return AID_LOGD; // associate this with the logger
}
-
}
uid_t LogStatistics::pidToUid(pid_t pid) {
@@ -632,10 +619,10 @@
}
// caller must free character string
-const char *LogStatistics::pidToName(pid_t pid) const {
+const char* LogStatistics::pidToName(pid_t pid) const {
// An inconvenient truth ... getName() can alter the object
- pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
- const char *name = writablePidTable.add(pid)->second.getName();
+ pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
+ const char* name = writablePidTable.add(pid)->second.getName();
if (!name) {
return NULL;
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 777dc33..066b7de 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -21,26 +21,25 @@
#include <stdlib.h>
#include <sys/types.h>
-#include <algorithm> // std::max
+#include <algorithm> // std::max
#include <memory>
-#include <string> // std::string
+#include <string> // std::string
#include <unordered_map>
-#include <android/log.h>
#include <android-base/stringprintf.h>
+#include <android/log.h>
#include <private/android_filesystem_config.h>
#include "LogBufferElement.h"
#include "LogUtils.h"
#define log_id_for_each(i) \
- for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
+ for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
class LogStatistics;
template <typename TKey, typename TEntry>
class LogHashtable {
-
std::unordered_map<TKey, TEntry> map;
size_t bucket_size() const {
@@ -58,9 +57,10 @@
static const size_t unordered_map_per_entry_overhead = sizeof(void*);
static const size_t unordered_map_bucket_overhead = sizeof(void*);
-public:
-
- size_t size() const { return map.size(); }
+ public:
+ size_t size() const {
+ return map.size();
+ }
// Estimate unordered_map memory usage.
size_t sizeOf() const {
@@ -70,20 +70,21 @@
}
typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
- typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
+ typedef
+ typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
- std::unique_ptr<const TEntry *[]> sort(uid_t uid, pid_t pid,
+ std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
size_t len) const {
if (!len) {
- std::unique_ptr<const TEntry *[]> sorted(NULL);
+ std::unique_ptr<const TEntry* []> sorted(NULL);
return sorted;
}
- const TEntry **retval = new const TEntry* [len];
+ const TEntry** retval = new const TEntry*[len];
memset(retval, 0, sizeof(*retval) * len);
- for(const_iterator it = map.begin(); it != map.end(); ++it) {
- const TEntry &entry = it->second;
+ for (const_iterator it = map.begin(); it != map.end(); ++it) {
+ const TEntry& entry = it->second;
if ((uid != AID_ROOT) && (uid != entry.getUid())) {
continue;
@@ -94,8 +95,8 @@
size_t sizes = entry.getSizes();
ssize_t index = len - 1;
- while ((!retval[index] || (sizes > retval[index]->getSizes()))
- && (--index >= 0))
+ while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
+ (--index >= 0))
;
if (++index < (ssize_t)len) {
size_t num = len - index - 1;
@@ -106,11 +107,11 @@
retval[index] = &entry;
}
}
- std::unique_ptr<const TEntry *[]> sorted(retval);
+ std::unique_ptr<const TEntry* []> sorted(retval);
return sorted;
}
- inline iterator add(TKey key, LogBufferElement *element) {
+ inline iterator add(TKey key, LogBufferElement* element) {
iterator it = map.find(key);
if (it == map.end()) {
it = map.insert(std::make_pair(key, TEntry(element))).first;
@@ -130,41 +131,46 @@
return it;
}
- void subtract(TKey key, LogBufferElement *element) {
+ void subtract(TKey key, LogBufferElement* element) {
iterator it = map.find(key);
if ((it != map.end()) && it->second.subtract(element)) {
map.erase(it);
}
}
- inline void drop(TKey key, LogBufferElement *element) {
+ inline void drop(TKey key, LogBufferElement* element) {
iterator it = map.find(key);
if (it != map.end()) {
it->second.drop(element);
}
}
- inline iterator begin() { return map.begin(); }
- inline const_iterator begin() const { return map.begin(); }
- inline iterator end() { return map.end(); }
- inline const_iterator end() const { return map.end(); }
+ inline iterator begin() {
+ return map.begin();
+ }
+ inline const_iterator begin() const {
+ return map.begin();
+ }
+ inline iterator end() {
+ return map.end();
+ }
+ inline const_iterator end() const {
+ return map.end();
+ }
- std::string format(
- const LogStatistics &stat,
- uid_t uid,
- pid_t pid,
- const std::string &name = std::string(""),
- log_id_t id = LOG_ID_MAX) const {
+ std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
+ const std::string& name = std::string(""),
+ log_id_t id = LOG_ID_MAX) const {
static const size_t maximum_sorted_entries = 32;
std::string output;
- std::unique_ptr<const TEntry *[]> sorted = sort(uid, pid,
- maximum_sorted_entries);
+ std::unique_ptr<const TEntry* []> sorted =
+ sort(uid, pid, maximum_sorted_entries);
if (!sorted.get()) {
return output;
}
bool headerPrinted = false;
for (size_t index = 0; index < maximum_sorted_entries; ++index) {
- const TEntry *entry = sorted[index];
+ const TEntry* entry = sorted[index];
if (!entry) {
break;
}
@@ -180,42 +186,45 @@
}
return output;
}
-
};
namespace EntryBaseConstants {
- static constexpr size_t pruned_len = 14;
- static constexpr size_t total_len = 80;
+static constexpr size_t pruned_len = 14;
+static constexpr size_t total_len = 80;
}
struct EntryBase {
size_t size;
- EntryBase():size(0) { }
- explicit EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
+ EntryBase() : size(0) {
+ }
+ explicit EntryBase(LogBufferElement* element) : size(element->getMsgLen()) {
+ }
- size_t getSizes() const { return size; }
+ size_t getSizes() const {
+ return size;
+ }
- inline void add(LogBufferElement *element) { size += element->getMsgLen(); }
- inline bool subtract(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
+ size += element->getMsgLen();
+ }
+ inline bool subtract(LogBufferElement* element) {
size -= element->getMsgLen();
return !size;
}
- static std::string formatLine(
- const std::string &name,
- const std::string &size,
- const std::string &pruned) {
- ssize_t drop_len = std::max(pruned.length() + 1,
- EntryBaseConstants::pruned_len);
- ssize_t size_len = std::max(size.length() + 1,
- EntryBaseConstants::total_len
- - name.length() - drop_len - 1);
+ static std::string formatLine(const std::string& name,
+ const std::string& size,
+ const std::string& pruned) {
+ ssize_t drop_len =
+ std::max(pruned.length() + 1, EntryBaseConstants::pruned_len);
+ ssize_t size_len =
+ std::max(size.length() + 1, EntryBaseConstants::total_len -
+ name.length() - drop_len - 1);
- std::string ret = android::base::StringPrintf("%s%*s%*s",
- name.c_str(),
- (int)size_len, size.c_str(),
- (int)drop_len, pruned.c_str());
+ std::string ret = android::base::StringPrintf(
+ "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
+ (int)drop_len, pruned.c_str());
// remove any trailing spaces
size_t pos = ret.size();
size_t len = 0;
@@ -228,23 +237,25 @@
struct EntryBaseDropped : public EntryBase {
size_t dropped;
- EntryBaseDropped():dropped(0) { }
- explicit EntryBaseDropped(LogBufferElement *element):
- EntryBase(element),
- dropped(element->getDropped()) {
+ EntryBaseDropped() : dropped(0) {
+ }
+ explicit EntryBaseDropped(LogBufferElement* element)
+ : EntryBase(element), dropped(element->getDropped()) {
}
- size_t getDropped() const { return dropped; }
+ size_t getDropped() const {
+ return dropped;
+ }
- inline void add(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
dropped += element->getDropped();
EntryBase::add(element);
}
- inline bool subtract(LogBufferElement *element) {
+ inline bool subtract(LogBufferElement* element) {
dropped -= element->getDropped();
return EntryBase::subtract(element) && !dropped;
}
- inline void drop(LogBufferElement *element) {
+ inline void drop(LogBufferElement* element) {
dropped += 1;
EntryBase::subtract(element);
}
@@ -254,25 +265,31 @@
const uid_t uid;
pid_t pid;
- explicit UidEntry(LogBufferElement *element):
- EntryBaseDropped(element),
- uid(element->getUid()),
- pid(element->getPid()) {
+ explicit UidEntry(LogBufferElement* element)
+ : EntryBaseDropped(element),
+ uid(element->getUid()),
+ pid(element->getPid()) {
}
- inline const uid_t&getKey() const { return uid; }
- inline const uid_t&getUid() const { return getKey(); }
- inline const pid_t&getPid() const { return pid; }
+ inline const uid_t& getKey() const {
+ return uid;
+ }
+ inline const uid_t& getUid() const {
+ return getKey();
+ }
+ inline const pid_t& getPid() const {
+ return pid;
+ }
- inline void add(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
if (pid != element->getPid()) {
pid = -1;
}
EntryBaseDropped::add(element);
}
- std::string formatHeader(const std::string &name, log_id_t id) const;
- std::string format(const LogStatistics &stat, log_id_t id) const;
+ std::string formatHeader(const std::string& name, log_id_t id) const;
+ std::string format(const LogStatistics& stat, log_id_t id) const;
};
namespace android {
@@ -282,32 +299,42 @@
struct PidEntry : public EntryBaseDropped {
const pid_t pid;
uid_t uid;
- char *name;
+ char* name;
- explicit PidEntry(pid_t pid):
- EntryBaseDropped(),
- pid(pid),
- uid(android::pidToUid(pid)),
- name(android::pidToName(pid)) {
+ explicit PidEntry(pid_t pid)
+ : EntryBaseDropped(),
+ pid(pid),
+ uid(android::pidToUid(pid)),
+ name(android::pidToName(pid)) {
}
- explicit PidEntry(LogBufferElement *element):
- EntryBaseDropped(element),
- pid(element->getPid()),
- uid(element->getUid()),
- name(android::pidToName(pid)) {
+ explicit PidEntry(LogBufferElement* element)
+ : EntryBaseDropped(element),
+ pid(element->getPid()),
+ uid(element->getUid()),
+ name(android::pidToName(pid)) {
}
- PidEntry(const PidEntry &element):
- EntryBaseDropped(element),
- pid(element.pid),
- uid(element.uid),
- name(element.name ? strdup(element.name) : NULL) {
+ PidEntry(const PidEntry& element)
+ : EntryBaseDropped(element),
+ pid(element.pid),
+ uid(element.uid),
+ name(element.name ? strdup(element.name) : NULL) {
}
- ~PidEntry() { free(name); }
+ ~PidEntry() {
+ free(name);
+ }
- const pid_t&getKey() const { return pid; }
- const pid_t&getPid() const { return getKey(); }
- const uid_t&getUid() const { return uid; }
- const char*getName() const { return name; }
+ const pid_t& getKey() const {
+ return pid;
+ }
+ const pid_t& getPid() const {
+ return getKey();
+ }
+ const uid_t& getUid() const {
+ return uid;
+ }
+ const char* getName() const {
+ return name;
+ }
inline void add(pid_t newPid) {
if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
@@ -319,7 +346,7 @@
}
}
- inline void add(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
uid_t incomingUid = element->getUid();
if (getUid() != incomingUid) {
uid = incomingUid;
@@ -331,44 +358,56 @@
EntryBaseDropped::add(element);
}
- std::string formatHeader(const std::string &name, log_id_t id) const;
- std::string format(const LogStatistics &stat, log_id_t id) const;
+ std::string formatHeader(const std::string& name, log_id_t id) const;
+ std::string format(const LogStatistics& stat, log_id_t id) const;
};
struct TidEntry : public EntryBaseDropped {
const pid_t tid;
pid_t pid;
uid_t uid;
- char *name;
+ char* name;
- TidEntry(pid_t tid, pid_t pid):
- EntryBaseDropped(),
- tid(tid),
- pid(pid),
- uid(android::pidToUid(tid)),
- name(android::tidToName(tid)) {
+ TidEntry(pid_t tid, pid_t pid)
+ : EntryBaseDropped(),
+ tid(tid),
+ pid(pid),
+ uid(android::pidToUid(tid)),
+ name(android::tidToName(tid)) {
}
- explicit TidEntry(LogBufferElement *element):
- EntryBaseDropped(element),
- tid(element->getTid()),
- pid(element->getPid()),
- uid(element->getUid()),
- name(android::tidToName(tid)) {
+ explicit TidEntry(LogBufferElement* element)
+ : EntryBaseDropped(element),
+ tid(element->getTid()),
+ pid(element->getPid()),
+ uid(element->getUid()),
+ name(android::tidToName(tid)) {
}
- TidEntry(const TidEntry &element):
- EntryBaseDropped(element),
- tid(element.tid),
- pid(element.pid),
- uid(element.uid),
- name(element.name ? strdup(element.name) : NULL) {
+ TidEntry(const TidEntry& element)
+ : EntryBaseDropped(element),
+ tid(element.tid),
+ pid(element.pid),
+ uid(element.uid),
+ name(element.name ? strdup(element.name) : NULL) {
}
- ~TidEntry() { free(name); }
+ ~TidEntry() {
+ free(name);
+ }
- const pid_t&getKey() const { return tid; }
- const pid_t&getTid() const { return getKey(); }
- const pid_t&getPid() const { return pid; }
- const uid_t&getUid() const { return uid; }
- const char*getName() const { return name; }
+ const pid_t& getKey() const {
+ return tid;
+ }
+ const pid_t& getTid() const {
+ return getKey();
+ }
+ const pid_t& getPid() const {
+ return pid;
+ }
+ const uid_t& getUid() const {
+ return uid;
+ }
+ const char* getName() const {
+ return name;
+ }
inline void add(pid_t incomingTid) {
if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
@@ -380,7 +419,7 @@
}
}
- inline void add(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
uid_t incomingUid = element->getUid();
pid_t incomingPid = element->getPid();
if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
@@ -394,8 +433,8 @@
EntryBaseDropped::add(element);
}
- std::string formatHeader(const std::string &name, log_id_t id) const;
- std::string format(const LogStatistics &stat, log_id_t id) const;
+ std::string formatHeader(const std::string& name, log_id_t id) const;
+ std::string format(const LogStatistics& stat, log_id_t id) const;
};
struct TagEntry : public EntryBaseDropped {
@@ -403,19 +442,27 @@
pid_t pid;
uid_t uid;
- explicit TagEntry(LogBufferElement *element):
- EntryBaseDropped(element),
- tag(element->getTag()),
- pid(element->getPid()),
- uid(element->getUid()) {
+ explicit TagEntry(LogBufferElement* element)
+ : EntryBaseDropped(element),
+ tag(element->getTag()),
+ pid(element->getPid()),
+ uid(element->getUid()) {
}
- const uint32_t&getKey() const { return tag; }
- const pid_t&getPid() const { return pid; }
- const uid_t&getUid() const { return uid; }
- const char*getName() const { return android::tagToName(tag); }
+ const uint32_t& getKey() const {
+ return tag;
+ }
+ const pid_t& getPid() const {
+ return pid;
+ }
+ const uid_t& getUid() const {
+ return uid;
+ }
+ const char* getName() const {
+ return android::tagToName(tag);
+ }
- inline void add(LogBufferElement *element) {
+ inline void add(LogBufferElement* element) {
if (uid != element->getUid()) {
uid = -1;
}
@@ -425,27 +472,27 @@
EntryBaseDropped::add(element);
}
- std::string formatHeader(const std::string &name, log_id_t id) const;
- std::string format(const LogStatistics &stat, log_id_t id) const;
+ std::string formatHeader(const std::string& name, log_id_t id) const;
+ std::string format(const LogStatistics& stat, log_id_t id) const;
};
template <typename TEntry>
class LogFindWorst {
- std::unique_ptr<const TEntry *[]> sorted;
+ std::unique_ptr<const TEntry* []> sorted;
-public:
+ public:
+ explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
+ : sorted(std::move(sorted)) {
+ }
- explicit LogFindWorst(std::unique_ptr<const TEntry *[]> &&sorted) : sorted(std::move(sorted)) { }
-
- void findWorst(int &worst,
- size_t &worst_sizes, size_t &second_worst_sizes,
- size_t threshold) {
+ void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
+ size_t threshold) {
if (sorted.get() && sorted[0] && sorted[1]) {
worst_sizes = sorted[0]->getSizes();
if ((worst_sizes > threshold)
// Allow time horizon to extend roughly tenfold, assume
// average entry length is 100 characters.
- && (worst_sizes > (10 * sorted[0]->getDropped()))) {
+ && (worst_sizes > (10 * sorted[0]->getDropped()))) {
worst = sorted[0]->getKey();
second_worst_sizes = sorted[1]->getSizes();
if (second_worst_sizes < threshold) {
@@ -455,13 +502,11 @@
}
}
- void findWorst(int &worst,
- size_t worst_sizes, size_t &second_worst_sizes) {
+ void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
if (sorted.get() && sorted[0] && sorted[1]) {
worst = sorted[0]->getKey();
- second_worst_sizes = worst_sizes
- - sorted[0]->getSizes()
- + sorted[1]->getSizes();
+ second_worst_sizes =
+ worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
}
}
};
@@ -506,11 +551,11 @@
tagTable.sizeOf() + securityTagTable.sizeOf() +
(pidTable.size() * sizeof(pidTable_t::iterator)) +
(tagTable.size() * sizeof(tagTable_t::iterator));
- for(auto it : pidTable) {
+ for (auto it : pidTable) {
const char* name = it.second.getName();
if (name) size += strlen(name) + 1;
}
- for(auto it : tidTable) {
+ for (auto it : tidTable) {
const char* name = it.second.getName();
if (name) size += strlen(name) + 1;
}
@@ -518,23 +563,25 @@
size += uidTable[id].sizeOf();
size += uidTable[id].size() * sizeof(uidTable_t::iterator);
size += pidSystemTable[id].sizeOf();
- size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
+ size +=
+ pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
}
return size;
}
-public:
-
+ public:
LogStatistics();
- void enableStatistics() { enable = true; }
+ void enableStatistics() {
+ enable = true;
+ }
- void add(LogBufferElement *entry);
- void subtract(LogBufferElement *entry);
+ void add(LogBufferElement* entry);
+ void subtract(LogBufferElement* entry);
// entry->setDropped(1) must follow this call
- void drop(LogBufferElement *entry);
+ void drop(LogBufferElement* entry);
// Correct for coalescing two entries referencing dropped content
- void erase(LogBufferElement *element) {
+ void erase(LogBufferElement* element) {
log_id_t log_id = element->getLogId();
--mElements[log_id];
--mDroppedElements[log_id];
@@ -543,7 +590,8 @@
LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
}
- LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len, log_id id) {
+ LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
+ log_id id) {
return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
}
LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
@@ -551,21 +599,31 @@
}
// fast track current value by id only
- size_t sizes(log_id_t id) const { return mSizes[id]; }
- size_t elements(log_id_t id) const { return mElements[id]; }
+ size_t sizes(log_id_t id) const {
+ return mSizes[id];
+ }
+ size_t elements(log_id_t id) const {
+ return mElements[id];
+ }
size_t realElements(log_id_t id) const {
return mElements[id] - mDroppedElements[id];
}
- size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
- size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
- static size_t sizesTotal() { return SizesTotal; }
+ size_t sizesTotal(log_id_t id) const {
+ return mSizesTotal[id];
+ }
+ size_t elementsTotal(log_id_t id) const {
+ return mElementsTotal[id];
+ }
+ static size_t sizesTotal() {
+ return SizesTotal;
+ }
std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
// helper (must be locked directly or implicitly by mLogElementsLock)
- const char *pidToName(pid_t pid) const;
+ const char* pidToName(pid_t pid) const;
uid_t pidToUid(pid_t pid);
- const char *uidToName(uid_t uid) const;
+ const char* uidToName(uid_t uid) const;
};
-#endif // _LOGD_LOG_STATISTICS_H__
+#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index a109592..67649b1 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -50,11 +50,13 @@
if (!comment) return AID_ROOT;
if (*comment == '#') ++comment;
- while ((comment < endp) && (*comment != '\n') && isspace(*comment)) ++comment;
+ while ((comment < endp) && (*comment != '\n') && isspace(*comment))
+ ++comment;
static const char uid_str[] = "uid=";
if (((comment + strlen(uid_str)) >= endp) ||
- fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
- !isdigit(comment[strlen(uid_str)])) return AID_ROOT;
+ fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
+ !isdigit(comment[strlen(uid_str)]))
+ return AID_ROOT;
char* cp;
unsigned long Uid = strtoul(comment + 4, &cp, 10);
if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
@@ -86,34 +88,32 @@
}
// dump what we already know back into the file?
- fd = TEMP_FAILURE_RETRY(open(filename,
- O_WRONLY | O_TRUNC | O_CLOEXEC |
- O_NOFOLLOW | O_BINARY));
+ fd = TEMP_FAILURE_RETRY(open(
+ filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd >= 0) {
time_t now = time(NULL);
struct tm tm;
localtime_r(&now, &tm);
char timebuf[20];
- size_t len = strftime(timebuf, sizeof(timebuf),
- "%Y-%m-%d %H:%M:%S", &tm);
+ size_t len =
+ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
android::base::WriteStringToFd(
android::base::StringPrintf(
"# Rebuilt %.20s, content owned by logd\n", timebuf),
fd);
for (const auto& it : tag2total) {
- android::base::WriteStringToFd(formatEntry_locked(it.first,
- AID_ROOT),
- fd);
+ android::base::WriteStringToFd(
+ formatEntry_locked(it.first, AID_ROOT), fd);
}
TEMP_FAILURE_RETRY(close(fd));
}
}
if (warn) {
- android::prdebug(((fd < 0) ?
- "%s failed to rebuild" :
- "%s missing, damaged or truncated; rebuilt"),
- filename);
+ android::prdebug(
+ ((fd < 0) ? "%s failed to rebuild"
+ : "%s missing, damaged or truncated; rebuilt"),
+ filename);
}
if (fd >= 0) {
@@ -126,10 +126,9 @@
return true;
}
-void LogTags::AddEventLogTags(uint32_t tag, uid_t uid,
- const std::string& Name,
- const std::string& Format,
- const char* source, bool warn) {
+void LogTags::AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
+ const std::string& Format, const char* source,
+ bool warn) {
std::string Key = Name;
if (Format.length()) Key += "+" + Format;
@@ -178,8 +177,8 @@
WritePersistEventLogTags(tag, uid, source);
} else if (warn && !newOne && source) {
// For the files, we want to report dupes.
- android::prdebug("Multiple tag %" PRIu32 " %s %s %s", tag,
- Name.c_str(), Format.c_str(), source);
+ android::prdebug("Multiple tag %" PRIu32 " %s %s %s", tag, Name.c_str(),
+ Format.c_str(), source);
}
}
@@ -193,7 +192,7 @@
}
std::string content;
if (android::base::ReadFileToString(filename, &content)) {
- char* cp = (char*) content.c_str();
+ char* cp = (char*)content.c_str();
char* endp = cp + content.length();
{
@@ -228,16 +227,19 @@
std::string Name(name, cp - name);
#ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
static const size_t maximum_official_tag_name_size = 24;
- if (warn && (Name.length() > maximum_official_tag_name_size)) {
- android::prdebug("tag name too long %s", Name.c_str());
+ if (warn &&
+ (Name.length() > maximum_official_tag_name_size)) {
+ android::prdebug("tag name too long %s", Name.c_str());
}
#endif
- if (hasAlpha && ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
+ if (hasAlpha &&
+ ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
if (Tag > emptyTag) {
if (*cp != '\n') lineStart = NULL;
continue;
}
- while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
+ while ((cp < endp) && (*cp != '\n') && isspace(*cp))
+ ++cp;
const char* format = cp;
uid_t uid = AID_ROOT;
while ((cp < endp) && (*cp != '\n')) {
@@ -263,7 +265,9 @@
}
lineStart = NULL;
}
- } else if (!isspace(*cp)) break;
+ } else if (!isspace(*cp)) {
+ break;
+ }
}
cp++;
}
@@ -273,8 +277,7 @@
}
// Extract a 4-byte value from a byte stream.
-static inline uint32_t get4LE(const char* msg)
-{
+static inline uint32_t get4LE(const char* msg) {
const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
@@ -284,8 +287,8 @@
// database with any found.
void LogTags::ReadPersistEventLogTags() {
struct logger_list* logger_list = android_logger_list_alloc(
- ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK,
- 0, (pid_t)0);
+ ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0,
+ (pid_t)0);
if (!logger_list) return;
struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
@@ -305,8 +308,9 @@
if (log_msg.entry.len <= sizeof(uint32_t)) continue;
uint32_t Tag = get4LE(msg);
if (Tag != TAG_DEF_LOG_TAG) continue;
- uid_t uid = (log_msg.entry.hdr_size >= sizeof(logger_entry_v4)) ?
- log_msg.entry.uid : AID_ROOT;
+ uid_t uid = (log_msg.entry.hdr_size >= sizeof(logger_entry_v4))
+ ? log_msg.entry.uid
+ : AID_ROOT;
std::string Name;
std::string Format;
@@ -433,8 +437,7 @@
// writer lock. We use this call to invent a new deterministically
// random tag, unique is cleared if no conflicts. If format is NULL,
// we are in readonly mode.
-uint32_t LogTags::nameToTag_locked(const std::string& name,
- const char* format,
+uint32_t LogTags::nameToTag_locked(const std::string& name, const char* format,
bool& unique) {
key2tag_const_iterator ik;
@@ -462,7 +465,7 @@
size_t Hash = key2tag.hash_function()(Key);
uint32_t Tag = Hash;
// This sets an upper limit on the conflics we are allowed to deal with.
- for (unsigned i = 0; i < 256; ) {
+ for (unsigned i = 0; i < 256;) {
tag2name_const_iterator it = tag2name.find(Tag);
if (it == tag2name.end()) return Tag;
std::string localKey(it->second);
@@ -471,15 +474,14 @@
localKey += "+" + iform->second;
}
unique = !!it->second.compare(localKey);
- if (!unique) return Tag; // unlikely except in a race
+ if (!unique) return Tag; // unlikely except in a race
++i;
// Algorithm to convert hash to next tag
if (i < 32) {
Tag = (Hash >> i);
// size_t is 32 bits, or upper word zero, rotate
- if ((sizeof(Hash) <= 4) ||
- ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
+ if ((sizeof(Hash) <= 4) || ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
Tag |= Hash << (32 - i);
}
} else {
@@ -501,7 +503,7 @@
android::RWLock::AutoRLock readLock(rwlock);
tag2total_const_iterator itot = tag2total.find(tag);
- if (itot == tag2total.end()) return; // source is a static entry
+ if (itot == tag2total.end()) return; // source is a static entry
size_t lastTotal = itot->second;
@@ -525,7 +527,7 @@
__android_log_event_list ctx(TAG_DEF_LOG_TAG);
ctx << tag << Name << Format;
std::string buffer(ctx);
- if (buffer.length() <= 0) return; // unlikely
+ if (buffer.length() <= 0) return; // unlikely
/*
* struct {
@@ -562,18 +564,17 @@
android_pmsg_log_header_t pmsgHeader = {
.magic = LOGGER_MAGIC,
- .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) +
- sizeof(outTag) + buffer.length()),
+ .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) + sizeof(outTag) +
+ buffer.length()),
.uid = (uint16_t)AID_ROOT,
.pid = (uint16_t)getpid(),
};
- struct iovec Vec[] = {
- { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
- { (unsigned char*)&header, sizeof(header) },
- { (unsigned char*)&outTag, sizeof(outTag) },
- { (unsigned char*)const_cast<char*>(buffer.data()), buffer.length() }
- };
+ struct iovec Vec[] = { { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
+ { (unsigned char*)&header, sizeof(header) },
+ { (unsigned char*)&outTag, sizeof(outTag) },
+ { (unsigned char*)const_cast<char*>(buffer.data()),
+ buffer.length() } };
tag2uid_const_iterator ut = tag2uid.find(tag);
if (ut == tag2uid.end()) {
@@ -582,7 +583,7 @@
pmsgHeader.uid = (uint16_t)uid;
TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
} else {
- for (auto &it : ut->second) {
+ for (auto& it : ut->second) {
pmsgHeader.uid = (uint16_t)it;
TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
}
@@ -590,8 +591,8 @@
}
void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode = O_WRONLY | O_APPEND |
- O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+ static const int mode =
+ O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = openFile(dynamic_event_log_tags, mode, true);
if (fd < 0) return;
@@ -612,8 +613,8 @@
}
void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode = O_WRONLY | O_APPEND |
- O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+ static const int mode =
+ O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
static bool one = true;
int fd = openFile(debug_event_log_tags, mode, one);
@@ -636,16 +637,14 @@
}
// How we maintain some runtime or reboot stickiness
-void LogTags::WritePersistEventLogTags(uint32_t tag,
- uid_t uid, const char* source) {
+void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
+ const char* source) {
// very unlikely
bool etc = source && !strcmp(source, system_event_log_tags);
if (etc) return;
bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
- bool debug = (!dynamic &&
- source &&
- !strcmp(source, debug_event_log_tags)) ||
+ bool debug = (!dynamic && source && !strcmp(source, debug_event_log_tags)) ||
!__android_log_is_debuggable();
WritePmsgEventLogTags(tag, uid);
@@ -658,7 +657,7 @@
if (itot != tag2total.end()) lastTotal = itot->second;
}
- if (lastTotal == 0) { // denotes first time for this one
+ if (lastTotal == 0) { // denotes first time for this one
if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
WriteDynamicEventLogTags(tag, uid);
}
@@ -694,9 +693,9 @@
tag2uid_const_iterator ut = tag2uid.find(Tag);
if (updateUid) {
if ((ut != tag2uid.end()) &&
- (ut->second.find(uid) == ut->second.end())) {
- unique = write; // write passthrough to update uid counts
- if (!write) Tag = emptyTag; // deny read access
+ (ut->second.find(uid) == ut->second.end())) {
+ unique = write; // write passthrough to update uid counts
+ if (!write) Tag = emptyTag; // deny read access
}
} else {
unique = write && (ut != tag2uid.end());
@@ -705,7 +704,7 @@
}
if (Tag == emptyTag) return Tag;
- WritePmsgEventLogTags(Tag, uid); // record references periodically
+ WritePmsgEventLogTags(Tag, uid); // record references periodically
if (!unique) return Tag;
bool updateWrite = false;
@@ -728,7 +727,9 @@
if (updateUid) {
// Add it to the uid list
if ((ut == tag2uid.end()) ||
- (ut->second.find(uid) != ut->second.end())) return Tag;
+ (ut->second.find(uid) != ut->second.end())) {
+ return Tag;
+ }
const_cast<uid_list&>(ut->second).emplace(uid);
updateWrite = true;
} else {
@@ -791,8 +792,7 @@
return Tag;
}
-std::string LogTags::formatEntry(uint32_t tag, uid_t uid,
- const char* name,
+std::string LogTags::formatEntry(uint32_t tag, uid_t uid, const char* name,
const char* format) {
if (!format || !format[0]) {
return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
@@ -802,9 +802,8 @@
if (len > strlen(tabs)) len = strlen(tabs);
std::string Uid;
if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
- return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n",
- tag, name, &tabs[len], format,
- Uid.c_str());
+ return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n", tag, name,
+ &tabs[len], format, Uid.c_str());
}
std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
@@ -830,14 +829,19 @@
// Show all, one for each registered uid (we are group root)
std::string ret;
- for (auto &it : ut->second) {
+ for (auto& it : ut->second) {
ret += formatEntry(tag, it, name, format);
}
return ret;
}
-std::string LogTags::formatGetEventTag(uid_t uid,
- const char* name, const char* format) {
+std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
+ android::RWLock::AutoRLock readLock(rwlock);
+ return formatEntry_locked(tag, uid);
+}
+
+std::string LogTags::formatGetEventTag(uid_t uid, const char* name,
+ const char* format) {
bool all = name && (name[0] == '*') && !name[1];
bool list = !name || all;
std::string ret;
@@ -859,7 +863,7 @@
// first uid in list so as to manufacture an accurate reference
tag2uid_const_iterator ut = tag2uid.find(tag);
if ((ut != tag2uid.end()) &&
- (ut->second.begin() != ut->second.end())) {
+ (ut->second.begin() != ut->second.end())) {
uid = *(ut->second.begin());
}
}
diff --git a/logd/LogTags.h b/logd/LogTags.h
index 37a6d96..203318d 100644
--- a/logd/LogTags.h
+++ b/logd/LogTags.h
@@ -17,9 +17,9 @@
#ifndef _LOGD_LOG_TAGS_H__
#define _LOGD_LOG_TAGS_H__
+#include <string>
#include <unordered_map>
#include <unordered_set>
-#include <string>
#include <utils/RWLock.h>
@@ -35,64 +35,70 @@
// key is Name + "+" + Format
std::unordered_map<std::string, uint32_t> key2tag;
- typedef std::unordered_map<std::string, uint32_t>::const_iterator key2tag_const_iterator;
+ typedef std::unordered_map<std::string, uint32_t>::const_iterator
+ key2tag_const_iterator;
// Allows us to manage access permissions based on uid registrants
// Global entries are specifically erased.
typedef std::unordered_set<uid_t> uid_list;
std::unordered_map<uint32_t, uid_list> tag2uid;
- typedef std::unordered_map<uint32_t, uid_list>::const_iterator tag2uid_const_iterator;
+ typedef std::unordered_map<uint32_t, uid_list>::const_iterator
+ tag2uid_const_iterator;
std::unordered_map<uint32_t, std::string> tag2name;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2name_const_iterator;
+ typedef std::unordered_map<uint32_t, std::string>::const_iterator
+ tag2name_const_iterator;
std::unordered_map<uint32_t, std::string> tag2format;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2format_const_iterator;
+ typedef std::unordered_map<uint32_t, std::string>::const_iterator
+ tag2format_const_iterator;
- static const size_t max_per_uid = 256; // Put a cap on the tags per uid
+ static const size_t max_per_uid = 256; // Put a cap on the tags per uid
std::unordered_map<uid_t, size_t> uid2count;
- typedef std::unordered_map<uid_t, size_t>::const_iterator uid2count_const_iterator;
+ typedef std::unordered_map<uid_t, size_t>::const_iterator
+ uid2count_const_iterator;
// Dynamic entries are assigned
std::unordered_map<uint32_t, size_t> tag2total;
- typedef std::unordered_map<uint32_t, size_t>::const_iterator tag2total_const_iterator;
+ typedef std::unordered_map<uint32_t, size_t>::const_iterator
+ tag2total_const_iterator;
// emplace unique tag
uint32_t nameToTag(uid_t uid, const char* name, const char* format);
// find unique or associated tag
- uint32_t nameToTag_locked(const std::string& name, const char* format, bool &unique);
+ uint32_t nameToTag_locked(const std::string& name, const char* format,
+ bool& unique);
// Record expected file watermarks to detect corruption.
std::unordered_map<std::string, size_t> file2watermark;
- typedef std::unordered_map<std::string, size_t>::const_iterator file2watermark_const_iterator;
+ typedef std::unordered_map<std::string, size_t>::const_iterator
+ file2watermark_const_iterator;
void ReadPersistEventLogTags();
// format helpers
// format a single entry, does not need object data
- static std::string formatEntry(uint32_t tag, uid_t uid,
- const char* name, const char* format);
+ static std::string formatEntry(uint32_t tag, uid_t uid, const char* name,
+ const char* format);
// caller locks, database lookup, authenticate against uid
std::string formatEntry_locked(uint32_t tag, uid_t uid,
bool authenticate = true);
bool RebuildFileEventLogTags(const char* filename, bool warn = true);
- void AddEventLogTags(uint32_t tag, uid_t uid,
- const std::string& Name, const std::string& Format,
- const char* source = NULL, bool warn = false);
+ void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
+ const std::string& Format, const char* source = NULL,
+ bool warn = false);
void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
// push tag details to persistent storage
- void WritePersistEventLogTags(uint32_t tag,
- uid_t uid = AID_ROOT,
+ void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
const char* source = NULL);
static const uint32_t emptyTag = uint32_t(-1);
-public:
-
+ public:
static const char system_event_log_tags[];
static const char dynamic_event_log_tags[];
// Only for userdebug and eng
@@ -106,13 +112,13 @@
// reverse lookup from tag
const char* tagToName(uint32_t tag) const;
const char* tagToFormat(uint32_t tag) const;
+ std::string formatEntry(uint32_t tag, uid_t uid);
// find associated tag
uint32_t nameToTag(const char* name) const;
// emplace tag if necessary, provide event-log-tag formated output in string
- std::string formatGetEventTag(uid_t uid,
- const char* name,
+ std::string formatGetEventTag(uid_t uid, const char* name,
const char* format);
};
-#endif // _LOGD_LOG_TAGS_H__
+#endif // _LOGD_LOG_TAGS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 2a04880..04e531f 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -17,32 +17,34 @@
#include <errno.h>
#include <sys/prctl.h>
+#include <private/android_logger.h>
+
#include "FlushCommand.h"
#include "LogBuffer.h"
-#include "LogTimes.h"
#include "LogReader.h"
+#include "LogTimes.h"
pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
-LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
+LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
bool nonBlock, unsigned long tail,
- unsigned int logMask, pid_t pid,
- uint64_t start, uint64_t timeout) :
- mRefCount(1),
- mRelease(false),
- mError(false),
- threadRunning(false),
- leadingDropped(false),
- mReader(reader),
- mLogMask(logMask),
- mPid(pid),
- mCount(0),
- mTail(tail),
- mIndex(0),
- mClient(client),
- mStart(start),
- mNonBlock(nonBlock),
- mEnd(LogBufferElement::getCurrentSequence()) {
+ unsigned int logMask, pid_t pid, log_time start,
+ uint64_t timeout)
+ : mRefCount(1),
+ mRelease(false),
+ mError(false),
+ threadRunning(false),
+ leadingDropped(false),
+ mReader(reader),
+ mLogMask(logMask),
+ mPid(pid),
+ mCount(0),
+ mTail(tail),
+ mIndex(0),
+ mClient(client),
+ mStart(start),
+ mNonBlock(nonBlock),
+ mEnd(log_time(android_log_clockid())) {
mTimeout.tv_sec = timeout / NS_PER_SEC;
mTimeout.tv_nsec = timeout % NS_PER_SEC;
pthread_cond_init(&threadTriggeredCondition, NULL);
@@ -56,8 +58,8 @@
if (!pthread_attr_init(&attr)) {
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
- if (!pthread_create(&mThread, &attr,
- LogTimeEntry::threadStart, this)) {
+ if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
+ this)) {
pthread_attr_destroy(&attr);
return;
}
@@ -71,8 +73,8 @@
decRef_Locked();
}
-void LogTimeEntry::threadStop(void *obj) {
- LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+void LogTimeEntry::threadStop(void* obj) {
+ LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
lock();
@@ -80,14 +82,14 @@
me->error_Locked();
}
- SocketClient *client = me->mClient;
+ SocketClient* client = me->mClient;
if (me->isError_Locked()) {
- LogReader &reader = me->mReader;
- LastLogTimes × = reader.logbuf().mTimes;
+ LogReader& reader = me->mReader;
+ LastLogTimes& times = reader.logbuf().mTimes;
LastLogTimes::iterator it = times.begin();
- while(it != times.end()) {
+ while (it != times.end()) {
if (*it == me) {
times.erase(it);
me->release_nodelete_Locked();
@@ -110,20 +112,20 @@
unlock();
}
-void *LogTimeEntry::threadStart(void *obj) {
+void* LogTimeEntry::threadStart(void* obj) {
prctl(PR_SET_NAME, "logd.reader.per");
- LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+ LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
pthread_cleanup_push(threadStop, obj);
- SocketClient *client = me->mClient;
+ SocketClient* client = me->mClient;
if (!client) {
me->error();
return NULL;
}
- LogBuffer &logbuf = me->mReader.logbuf();
+ LogBuffer& logbuf = me->mReader.logbuf();
bool privileged = FlushCommand::hasReadLogs(client);
bool security = FlushCommand::hasSecurityLogs(client);
@@ -132,14 +134,12 @@
lock();
- uint64_t start = me->mStart;
+ log_time start = me->mStart;
while (me->threadRunning && !me->isError_Locked()) {
-
if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
if (pthread_cond_timedwait(&me->threadTriggeredCondition,
- ×Lock,
- &me->mTimeout) == ETIMEDOUT) {
+ ×Lock, &me->mTimeout) == ETIMEDOUT) {
me->mTimeout.tv_sec = 0;
me->mTimeout.tv_nsec = 0;
}
@@ -151,10 +151,12 @@
unlock();
if (me->mTail) {
- logbuf.flushTo(client, start, privileged, security, FilterFirstPass, me);
+ logbuf.flushTo(client, start, privileged, security, FilterFirstPass,
+ me);
me->leadingDropped = true;
}
- start = logbuf.flushTo(client, start, privileged, security, FilterSecondPass, me);
+ start = logbuf.flushTo(client, start, privileged, security,
+ FilterSecondPass, me);
lock();
@@ -163,7 +165,7 @@
break;
}
- me->mStart = start + 1;
+ me->mStart = start + log_time(0, 1);
if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
break;
@@ -184,8 +186,8 @@
}
// A first pass to count the number of elements
-int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
- LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
+ LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
LogTimeEntry::lock();
@@ -198,11 +200,11 @@
}
if (me->mCount == 0) {
- me->mStart = element->getSequence();
+ me->mStart = element->getRealTime();
}
- if ((!me->mPid || (me->mPid == element->getPid()))
- && (me->isWatching(element->getLogId()))) {
+ if ((!me->mPid || (me->mPid == element->getPid())) &&
+ (me->isWatching(element->getLogId()))) {
++me->mCount;
}
@@ -212,12 +214,12 @@
}
// A second pass to send the selected elements
-int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
- LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
+ LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
LogTimeEntry::lock();
- me->mStart = element->getSequence();
+ me->mStart = element->getRealTime();
if (me->skipAhead[element->getLogId()]) {
me->skipAhead[element->getLogId()]--;
@@ -267,7 +269,7 @@
LogTimeEntry::unlock();
return true;
}
- // FALLTHRU
+// FALLTHRU
skip:
LogTimeEntry::unlock();
@@ -279,7 +281,7 @@
}
void LogTimeEntry::cleanSkip_Locked(void) {
- for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) {
+ for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t)(i + 1)) {
skipAhead[i] = 0;
}
}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 12df994..9a3ddab 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -18,8 +18,8 @@
#define _LOGD_LOG_TIMES_H__
#include <pthread.h>
-#include <time.h>
#include <sys/types.h>
+#include <time.h>
#include <list>
@@ -38,9 +38,9 @@
bool leadingDropped;
pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
- LogReader &mReader;
- static void *threadStart(void *me);
- static void threadStop(void *me);
+ LogReader& mReader;
+ static void* threadStart(void* me);
+ static void threadStop(void* me);
const unsigned int mLogMask;
const pid_t mPid;
unsigned int skipAhead[LOG_ID_MAX];
@@ -48,20 +48,24 @@
unsigned long mTail;
unsigned long mIndex;
-public:
- LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
+ public:
+ LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock,
unsigned long tail, unsigned int logMask, pid_t pid,
- uint64_t start, uint64_t timeout);
+ log_time start, uint64_t timeout);
- SocketClient *mClient;
- uint64_t mStart;
+ SocketClient* mClient;
+ log_time mStart;
struct timespec mTimeout;
const bool mNonBlock;
- const uint64_t mEnd; // only relevant if mNonBlock
+ const log_time mEnd; // only relevant if mNonBlock
// Protect List manipulations
- static void lock(void) { pthread_mutex_lock(×Lock); }
- static void unlock(void) { pthread_mutex_unlock(×Lock); }
+ static void lock(void) {
+ pthread_mutex_lock(×Lock);
+ }
+ static void unlock(void) {
+ pthread_mutex_unlock(×Lock);
+ }
void startReader_Locked(void);
@@ -72,7 +76,9 @@
pthread_cond_signal(&threadTriggeredCondition);
}
- void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; }
+ void triggerSkip_Locked(log_id_t id, unsigned int skip) {
+ skipAhead[id] = skip;
+ }
void cleanSkip_Locked(void);
// These called after LogTimeEntry removed from list, lock implicitly held
@@ -93,16 +99,28 @@
}
// Called to mark socket in jeopardy
- void error_Locked(void) { mError = true; }
- void error(void) { lock(); error_Locked(); unlock(); }
+ void error_Locked(void) {
+ mError = true;
+ }
+ void error(void) {
+ lock();
+ error_Locked();
+ unlock();
+ }
- bool isError_Locked(void) const { return mRelease || mError; }
+ bool isError_Locked(void) const {
+ return mRelease || mError;
+ }
// Mark Used
// Locking implied, grabbed when protection around loop iteration
- void incRef_Locked(void) { ++mRefCount; }
+ void incRef_Locked(void) {
+ ++mRefCount;
+ }
- bool owned_Locked(void) const { return mRefCount != 0; }
+ bool owned_Locked(void) const {
+ return mRefCount != 0;
+ }
void decRef_Locked(void) {
if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
@@ -111,12 +129,14 @@
// No one else is holding a reference to this
delete this;
}
- bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; }
+ bool isWatching(log_id_t id) {
+ return (mLogMask & (1 << id)) != 0;
+ }
// flushTo filter callbacks
- static int FilterFirstPass(const LogBufferElement *element, void *me);
- static int FilterSecondPass(const LogBufferElement *element, void *me);
+ static int FilterFirstPass(const LogBufferElement* element, void* me);
+ static int FilterSecondPass(const LogBufferElement* element, void* me);
};
-typedef std::list<LogTimeEntry *> LastLogTimes;
+typedef std::list<LogTimeEntry*> LastLogTimes;
-#endif // _LOGD_LOG_TIMES_H__
+#endif // _LOGD_LOG_TIMES_H__
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index f044b27..93d2a79 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,9 +20,9 @@
#include <sys/cdefs.h>
#include <sys/types.h>
-#include <utils/FastStrcmp.h>
#include <private/android_logger.h>
#include <sysutils/SocketClient.h>
+#include <utils/FastStrcmp.h>
// Hijack this header as a common include file used by most all sources
// to report some utilities defined here and there.
@@ -30,31 +30,30 @@
namespace android {
// Furnished in main.cpp. Caller must own and free returned value
-char *uidToName(uid_t uid);
-void prdebug(const char *fmt, ...) __printflike(1, 2);
+char* uidToName(uid_t uid);
+void prdebug(const char* fmt, ...) __printflike(1, 2);
// Furnished in LogStatistics.cpp.
size_t sizesTotal();
// Caller must own and free returned value
-char *pidToName(pid_t pid);
-char *tidToName(pid_t tid);
+char* pidToName(pid_t pid);
+char* tidToName(pid_t tid);
// Furnished in LogTags.cpp. Thread safe.
-const char *tagToName(uint32_t tag);
+const char* tagToName(uint32_t tag);
void ReReadEventLogTags();
// Furnished by LogKlog.cpp.
const char* strnstr(const char* s, size_t len, const char* needle);
-
}
// Furnished in LogCommand.cpp
bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
-bool clientHasLogCredentials(SocketClient *cli);
+bool clientHasLogCredentials(SocketClient* cli);
static inline bool worstUidEnabledForLogid(log_id_t id) {
return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
- (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
+ (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
}
-#endif // _LOGD_LOG_UTILS_H__
+#endif // _LOGD_LOG_UTILS_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index ae933b5..4b8b080 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -64,7 +64,7 @@
}
}
-int PruneList::init(const char *str) {
+int PruneList::init(const char* str) {
mWorstUidEnabled = true;
mWorstPidOfSystemEnabled = true;
PruneCollection::iterator it;
@@ -113,13 +113,13 @@
mWorstUidEnabled = false;
mWorstPidOfSystemEnabled = false;
- for(str = filter.c_str(); *str; ++str) {
+ for (str = filter.c_str(); *str; ++str) {
if (isspace(*str)) {
continue;
}
- PruneCollection *list;
- if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
+ PruneCollection* list;
+ if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
++str;
// special case, translates to worst UID at priority in blacklist
if (*str == '!') {
@@ -184,7 +184,7 @@
// insert sequentially into list
PruneCollection::iterator it = list->begin();
while (it != list->end()) {
- Prune &p = *it;
+ Prune& p = *it;
int m = uid - p.mUid;
if (m == 0) {
if (p.mPid == p.pid_all) {
@@ -198,14 +198,14 @@
}
if (m <= 0) {
if (m < 0) {
- list->insert(it, Prune(uid,pid));
+ list->insert(it, Prune(uid, pid));
}
break;
}
++it;
}
if (it == list->end()) {
- list->push_back(Prune(uid,pid));
+ list->push_back(Prune(uid, pid));
}
if (!*str) {
break;
@@ -217,7 +217,7 @@
std::string PruneList::format() {
static const char nice_format[] = " %s";
- const char *fmt = nice_format + 1;
+ const char* fmt = nice_format + 1;
std::string string;
@@ -250,7 +250,7 @@
// If there is scaling issues, resort to a better algorithm than linear
// based on these assumptions.
-bool PruneList::naughty(LogBufferElement *element) {
+bool PruneList::naughty(LogBufferElement* element) {
PruneCollection::iterator it;
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
if (!(*it).cmp(element)) {
@@ -260,7 +260,7 @@
return false;
}
-bool PruneList::nice(LogBufferElement *element) {
+bool PruneList::nice(LogBufferElement* element) {
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end(); ++it) {
if (!(*it).cmp(element)) {
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 8b8e02f..6e9893b 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -19,8 +19,8 @@
#include <sys/types.h>
-#include <list>
#include <string.h>
+#include <list>
#include "LogBufferElement.h"
@@ -33,16 +33,22 @@
const pid_t mPid;
int cmp(uid_t uid, pid_t pid) const;
-public:
- static const uid_t uid_all = (uid_t) -1;
- static const pid_t pid_all = (pid_t) -1;
+ public:
+ static const uid_t uid_all = (uid_t)-1;
+ static const pid_t pid_all = (pid_t)-1;
Prune(uid_t uid, pid_t pid);
- uid_t getUid() const { return mUid; }
- pid_t getPid() const { return mPid; }
+ uid_t getUid() const {
+ return mUid;
+ }
+ pid_t getPid() const {
+ return mPid;
+ }
- int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
+ int cmp(LogBufferElement* e) const {
+ return cmp(e->getUid(), e->getPid());
+ }
std::string format();
};
@@ -55,20 +61,28 @@
bool mWorstUidEnabled;
bool mWorstPidOfSystemEnabled;
-public:
+ public:
PruneList();
~PruneList();
- int init(const char *str);
+ int init(const char* str);
- bool naughty(LogBufferElement *element);
- bool naughty(void) { return !mNaughty.empty(); }
- bool nice(LogBufferElement *element);
- bool nice(void) { return !mNice.empty(); }
- bool worstUidEnabled() const { return mWorstUidEnabled; }
- bool worstPidOfSystemEnabled() const { return mWorstPidOfSystemEnabled; }
+ bool naughty(LogBufferElement* element);
+ bool naughty(void) {
+ return !mNaughty.empty();
+ }
+ bool nice(LogBufferElement* element);
+ bool nice(void) {
+ return !mNice.empty();
+ }
+ bool worstUidEnabled() const {
+ return mWorstUidEnabled;
+ }
+ bool worstPidOfSystemEnabled() const {
+ return mWorstPidOfSystemEnabled;
+ }
std::string format();
};
-#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
+#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 216f1a1..dfd56f2 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -31,8 +31,7 @@
* @return
* This function returns 0 on success, else -errno.
*/
-static int get_ack(int fd)
-{
+static int get_ack(int fd) {
int rc;
struct audit_message rep;
@@ -48,7 +47,7 @@
if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
- rc = ((struct nlmsgerr *)rep.data)->error;
+ rc = ((struct nlmsgerr*)rep.data)->error;
if (rc) {
return -rc;
}
@@ -70,8 +69,7 @@
* @return
* This function returns a positive sequence number on success, else -errno.
*/
-static int audit_send(int fd, int type, const void *data, size_t size)
-{
+static int audit_send(int fd, int type, const void* data, size_t size) {
int rc;
static int16_t sequence = 0;
struct audit_message req;
@@ -123,13 +121,13 @@
/* While failing and its due to interrupts */
rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0,
- (struct sockaddr*) &addr, sizeof(addr)));
+ (struct sockaddr*)&addr, sizeof(addr)));
/* Not all the bytes were sent */
if (rc < 0) {
rc = -errno;
goto out;
- } else if ((uint32_t) rc != req.nlh.nlmsg_len) {
+ } else if ((uint32_t)rc != req.nlh.nlmsg_len) {
rc = -EPROTO;
goto out;
}
@@ -138,7 +136,7 @@
rc = get_ack(fd);
/* If the ack failed, return the error, else return the sequence number */
- rc = (rc == 0) ? (int) sequence : rc;
+ rc = (rc == 0) ? (int)sequence : rc;
out:
/* Don't let sequence roll to negative */
@@ -149,8 +147,7 @@
return rc;
}
-int audit_setup(int fd, pid_t pid)
-{
+int audit_setup(int fd, pid_t pid) {
int rc;
struct audit_message rep;
struct audit_status status;
@@ -186,8 +183,7 @@
return 0;
}
-int audit_rate_limit(int fd, unsigned rate_limit)
-{
+int audit_rate_limit(int fd, unsigned rate_limit) {
int rc;
struct audit_message rep;
struct audit_status status;
@@ -207,13 +203,11 @@
return 0;
}
-int audit_open()
-{
+int audit_open() {
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
-int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
-{
+int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
ssize_t len;
int flags;
int rc = 0;
@@ -235,7 +229,7 @@
* however, can be returned.
*/
len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags,
- (struct sockaddr*) &nladdr, &nladdrlen));
+ (struct sockaddr*)&nladdr, &nladdrlen));
/*
* EAGAIN should be re-tried until success or another error manifests.
@@ -266,7 +260,6 @@
return rc;
}
-void audit_close(int fd)
-{
+void audit_close(int fd) {
close(fd);
}
diff --git a/logd/libaudit.h b/logd/libaudit.h
index 9865d43..a2afe47 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -25,17 +25,14 @@
#include <sys/socket.h>
#include <sys/types.h>
-#include <linux/netlink.h>
#include <linux/audit.h>
+#include <linux/netlink.h>
__BEGIN_DECLS
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
+#define MAX_AUDIT_MESSAGE_LENGTH 8970
-typedef enum {
- GET_REPLY_BLOCKING = 0,
- GET_REPLY_NONBLOCKING
-} reply_t;
+typedef enum { GET_REPLY_BLOCKING = 0, GET_REPLY_NONBLOCKING } reply_t;
/* type == AUDIT_SIGNAL_INFO */
struct audit_sig_info {
@@ -46,7 +43,7 @@
struct audit_message {
struct nlmsghdr nlh;
- char data[MAX_AUDIT_MESSAGE_LENGTH];
+ char data[MAX_AUDIT_MESSAGE_LENGTH];
};
/**
@@ -78,7 +75,7 @@
* @return
* This function returns 0 on success, else -errno.
*/
-extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block,
+extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
int peek);
/**
@@ -105,7 +102,7 @@
/* Guidelines to follow for dynamic rate_limit */
#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
-#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
+#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
extern int audit_rate_limit(int fd, unsigned rate_limit);
diff --git a/logd/main.cpp b/logd/main.cpp
index 2551f2e..3334506 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -48,17 +48,15 @@
#include <utils/threads.h>
#include "CommandListener.h"
-#include "LogBuffer.h"
-#include "LogListener.h"
#include "LogAudit.h"
+#include "LogBuffer.h"
#include "LogKlog.h"
+#include "LogListener.h"
#include "LogUtils.h"
-#define KMSG_PRIORITY(PRI) \
- '<', \
- '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
- '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \
- '>'
+#define KMSG_PRIORITY(PRI) \
+ '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
+ '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'
//
// The service is designed to be run by init, it does not respond well
@@ -92,7 +90,8 @@
static int drop_privs(bool klogd, bool auditd) {
// Tricky, if ro.build.type is "eng" then this is true because of the
// side effect that ro.debuggable == 1 as well, else it is false.
- bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
+ bool eng =
+ __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
struct sched_param param;
memset(¶m, 0, sizeof(param));
@@ -102,7 +101,7 @@
if (!eng) return -1;
}
- if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
+ if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
android::prdebug("failed to set batch scheduler");
if (!eng) return -1;
}
@@ -122,21 +121,24 @@
if (!eng) return -1;
}
- std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
+ std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
+ cap_free);
if (cap_clear(caps.get()) < 0) return -1;
- cap_value_t cap_value[] = {
- CAP_SETGID, // must be first for below
- klogd ? CAP_SYSLOG : CAP_SETGID,
- auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
- };
- if (cap_set_flag(caps.get(), CAP_PERMITTED,
- arraysize(cap_value), cap_value,
- CAP_SET) < 0) return -1;
- if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
- arraysize(cap_value), cap_value,
- CAP_SET) < 0) return -1;
+ cap_value_t cap_value[] = { CAP_SETGID, // must be first for below
+ klogd ? CAP_SYSLOG : CAP_SETGID,
+ auditd ? CAP_AUDIT_CONTROL : CAP_SETGID };
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value,
+ CAP_SET) < 0) {
+ return -1;
+ }
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
+ CAP_SET) < 0) {
+ return -1;
+ }
if (cap_set_proc(caps.get()) < 0) {
- android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
+ android::prdebug(
+ "failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)",
+ errno);
if (!eng) return -1;
}
@@ -157,8 +159,12 @@
if (!eng) return -1;
}
- if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
- if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
+ return -1;
+ }
+ if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
+ return -1;
+ }
if (cap_set_proc(caps.get()) < 0) {
android::prdebug("failed to clear CAP_SETGID (%d)", errno);
if (!eng) return -1;
@@ -168,8 +174,8 @@
}
// Property helper
-static bool check_flag(const char *prop, const char *flag) {
- const char *cp = strcasestr(prop, flag);
+static bool check_flag(const char* prop, const char* flag) {
+ const char* cp = strcasestr(prop, flag);
if (!cp) {
return false;
}
@@ -183,7 +189,7 @@
}
static int fdDmesg = -1;
-void android::prdebug(const char *fmt, ...) {
+void android::prdebug(const char* fmt, ...) {
if (fdDmesg < 0) {
return;
}
@@ -211,14 +217,13 @@
static sem_t uidName;
static uid_t uid;
-static char *name;
+static char* name;
static sem_t reinit;
static bool reinit_running = false;
-static LogBuffer *logBuf = NULL;
+static LogBuffer* logBuf = NULL;
-static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) {
-
+static bool package_list_parser_cb(pkg_info* info, void* /* userdata */) {
bool rc = true;
if (info->uid == uid) {
name = strdup(info->name);
@@ -230,7 +235,7 @@
return rc;
}
-static void *reinit_thread_start(void * /*obj*/) {
+static void* reinit_thread_start(void* /*obj*/) {
prctl(PR_SET_NAME, "logd.daemon");
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
@@ -243,11 +248,10 @@
// If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
// anything else, we have even lesser privileges and accept our fate. Not
// worth checking for error returns setting this thread's privileges.
- (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
- (void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
+ (void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
+ (void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
-
// uidToName Privileged Worker
if (uid) {
name = NULL;
@@ -261,8 +265,26 @@
if (fdDmesg >= 0) {
static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
- 'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':',
- ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' };
+ 'l',
+ 'o',
+ 'g',
+ 'd',
+ '.',
+ 'd',
+ 'a',
+ 'e',
+ 'm',
+ 'o',
+ 'n',
+ ':',
+ ' ',
+ 'r',
+ 'e',
+ 'i',
+ 'n',
+ 'i',
+ 't',
+ '\n' };
write(fdDmesg, reinit_message, sizeof(reinit_message));
}
@@ -279,7 +301,7 @@
static sem_t sem_name;
-char *android::uidToName(uid_t u) {
+char* android::uidToName(uid_t u) {
if (!u || !reinit_running) {
return NULL;
}
@@ -292,7 +314,7 @@
name = NULL;
sem_post(&reinit);
sem_wait(&uidName);
- char *ret = name;
+ char* ret = name;
sem_post(&sem_name);
@@ -305,7 +327,7 @@
sem_post(&reinit);
}
-static void readDmesg(LogAudit *al, LogKlog *kl) {
+static void readDmesg(LogAudit* al, LogKlog* kl) {
if (!al && !kl) {
return;
}
@@ -315,8 +337,8 @@
return;
}
- size_t len = rc + 1024; // Margin for additional input race or trailing nul
- std::unique_ptr<char []> buf(new char[len]);
+ size_t len = rc + 1024; // Margin for additional input race or trailing nul
+ std::unique_ptr<char[]> buf(new char[len]);
rc = klogctl(KLOG_READ_ALL, buf.get(), len);
if (rc <= 0) {
@@ -351,10 +373,8 @@
(void)cap_set_proc(caps);
(void)cap_free(caps);
- int sock = TEMP_FAILURE_RETRY(
- socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM));
+ int sock = TEMP_FAILURE_RETRY(socket_local_client(
+ "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
if (sock < 0) return -errno;
static const char reinitStr[] = "reinit";
@@ -384,7 +404,7 @@
// controlling the user space logger, and for any additional
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
// issue reinit command. KISS argument parsing.
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
return issueReinit();
@@ -397,17 +417,15 @@
}
int fdPmesg = -1;
- bool klogd = __android_logger_property_get_bool("logd.kernel",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST |
- BOOL_DEFAULT_FLAG_ENG |
- BOOL_DEFAULT_FLAG_SVELTE);
+ bool klogd = __android_logger_property_get_bool(
+ "logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
+ BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
if (klogd) {
static const char proc_kmsg[] = "/proc/kmsg";
fdPmesg = android_get_control_file(proc_kmsg);
if (fdPmesg < 0) {
- fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
- O_RDONLY | O_NDELAY | O_CLOEXEC));
+ fdPmesg = TEMP_FAILURE_RETRY(
+ open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
}
if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
}
@@ -423,8 +441,7 @@
memset(¶m, 0, sizeof(param));
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
- if (!pthread_attr_setdetachstate(&attr,
- PTHREAD_CREATE_DETACHED)) {
+ if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
pthread_t thread;
reinit_running = true;
if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) {
@@ -434,8 +451,8 @@
pthread_attr_destroy(&attr);
}
- bool auditd = __android_logger_property_get_bool("ro.logd.auditd",
- BOOL_DEFAULT_TRUE);
+ bool auditd =
+ __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
if (drop_privs(klogd, auditd) != 0) {
return -1;
}
@@ -444,7 +461,7 @@
// socket connection, and as a reader lock on a range of log
// entries.
- LastLogTimes *times = new LastLogTimes();
+ LastLogTimes* times = new LastLogTimes();
// LogBuffer is the object which is responsible for holding all
// log entries.
@@ -453,18 +470,17 @@
signal(SIGHUP, reinit_signal_handler);
- if (__android_logger_property_get_bool("logd.statistics",
- BOOL_DEFAULT_TRUE |
- BOOL_DEFAULT_FLAG_PERSIST |
- BOOL_DEFAULT_FLAG_ENG |
- BOOL_DEFAULT_FLAG_SVELTE)) {
+ if (__android_logger_property_get_bool(
+ "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
+ BOOL_DEFAULT_FLAG_ENG |
+ BOOL_DEFAULT_FLAG_SVELTE)) {
logBuf->enableStatistics();
}
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
- LogReader *reader = new LogReader(logBuf);
+ LogReader* reader = new LogReader(logBuf);
if (reader->startListener()) {
exit(1);
}
@@ -473,7 +489,7 @@
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
- LogListener *swl = new LogListener(logBuf, reader);
+ LogListener* swl = new LogListener(logBuf, reader);
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
if (swl->startListener(600)) {
exit(1);
@@ -482,7 +498,7 @@
// Command listener listens on /dev/socket/logd for incoming logd
// administrative commands.
- CommandListener *cl = new CommandListener(logBuf, reader, swl);
+ CommandListener* cl = new CommandListener(logBuf, reader, swl);
if (cl->startListener()) {
exit(1);
}
@@ -491,17 +507,16 @@
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
- LogAudit *al = NULL;
+ LogAudit* al = NULL;
if (auditd) {
al = new LogAudit(logBuf, reader,
__android_logger_property_get_bool(
- "ro.logd.auditd.dmesg",
- BOOL_DEFAULT_TRUE)
- ? fdDmesg
- : -1);
+ "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
+ ? fdDmesg
+ : -1);
}
- LogKlog *kl = NULL;
+ LogKlog* kl = NULL;
if (klogd) {
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
}
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index adf583b..ddff393 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -20,8 +20,8 @@
#include <signal.h>
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <string>
@@ -36,13 +36,11 @@
#include <selinux/selinux.h>
#endif
-#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
-#include "../LogReader.h" // pickup LOGD_SNDTIMEO
+#include "../LogReader.h" // pickup LOGD_SNDTIMEO
+#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
-static void send_to_control(char* buf, size_t len)
-{
- int sock = socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
+static void send_to_control(char* buf, size_t len) {
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (sock >= 0) {
if (write(sock, buf, strlen(buf) + 1) > 0) {
@@ -54,11 +52,7 @@
len -= ret;
buf += ret;
- struct pollfd p = {
- .fd = sock,
- .events = POLLIN,
- .revents = 0
- };
+ struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
ret = poll(&p, 1, 20);
if ((ret <= 0) || !(p.revents & POLLIN)) {
@@ -73,25 +67,23 @@
/*
* returns statistics
*/
-static void my_android_logger_get_statistics(char *buf, size_t len)
-{
+static void my_android_logger_get_statistics(char* buf, size_t len) {
snprintf(buf, len, "getStatistics 0 1 2 3 4");
send_to_control(buf, len);
}
-static void alloc_statistics(char **buffer, size_t *length)
-{
+static void alloc_statistics(char** buffer, size_t* length) {
size_t len = 8192;
- char *buf;
+ char* buf;
- for(int retry = 32; (retry >= 0); delete [] buf, --retry) {
- buf = new char [len];
+ for (int retry = 32; (retry >= 0); delete[] buf, --retry) {
+ buf = new char[len];
my_android_logger_get_statistics(buf, len);
- buf[len-1] = '\0';
+ buf[len - 1] = '\0';
size_t ret = atol(buf) + 1;
if (ret < 4) {
- delete [] buf;
+ delete[] buf;
buf = NULL;
break;
}
@@ -100,14 +92,13 @@
if (check) {
break;
}
- len += len / 8; // allow for some slop
+ len += len / 8; // allow for some slop
}
*buffer = buf;
*length = len;
}
-static char *find_benchmark_spam(char *cp)
-{
+static char* find_benchmark_spam(char* cp) {
// liblog_benchmarks has been run designed to SPAM. The signature of
// a noisiest UID statistics is:
//
@@ -115,7 +106,7 @@
// UID PACKAGE BYTES LINES
// 0 root 54164 147569
//
- char *benchmark = NULL;
+ char* benchmark = NULL;
do {
static const char signature[] = "\n0 root ";
@@ -129,7 +120,7 @@
}
benchmark = cp;
#ifdef DEBUG
- char *end = strstr(benchmark, "\n");
+ char* end = strstr(benchmark, "\n");
if (end == NULL) {
end = benchmark + strlen(benchmark);
}
@@ -145,8 +136,8 @@
}
// optional +/- field?
if ((*cp == '-') || (*cp == '+')) {
- while (isdigit(*++cp) ||
- (*cp == '.') || (*cp == '%') || (*cp == 'X')) {
+ while (isdigit(*++cp) || (*cp == '.') || (*cp == '%') ||
+ (*cp == 'X')) {
;
}
while (isspace(*cp)) {
@@ -169,14 +160,14 @@
TEST(logd, statistics) {
size_t len;
- char *buf;
+ char* buf;
alloc_statistics(&buf, &len);
ASSERT_TRUE(NULL != buf);
// remove trailing FF
- char *cp = buf + len - 1;
+ char* cp = buf + len - 1;
*cp = '\0';
bool truncated = *--cp != '\f';
if (!truncated) {
@@ -197,105 +188,107 @@
EXPECT_EQ(0, truncated);
- char *main_logs = strstr(cp, "\nChattiest UIDs in main ");
+ char* main_logs = strstr(cp, "\nChattiest UIDs in main ");
EXPECT_TRUE(NULL != main_logs);
- char *radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
- if (!radio_logs) GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
- "Actual: false\n"
- "Expected: false\n";
+ char* radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
+ if (!radio_logs)
+ GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
+ "Actual: false\n"
+ "Expected: false\n";
- char *system_logs = strstr(cp, "\nChattiest UIDs in system ");
+ char* system_logs = strstr(cp, "\nChattiest UIDs in system ");
EXPECT_TRUE(NULL != system_logs);
- char *events_logs = strstr(cp, "\nChattiest UIDs in events ");
+ char* events_logs = strstr(cp, "\nChattiest UIDs in events ");
EXPECT_TRUE(NULL != events_logs);
- delete [] buf;
+ delete[] buf;
}
-static void caught_signal(int /* signum */) { }
+static void caught_signal(int /* signum */) {
+}
-static void dump_log_msg(const char *prefix,
- log_msg *msg, unsigned int version, int lid) {
+static void dump_log_msg(const char* prefix, log_msg* msg, unsigned int version,
+ int lid) {
std::cout << std::flush;
std::cerr << std::flush;
fflush(stdout);
fflush(stderr);
- switch(msg->entry.hdr_size) {
- case 0:
- version = 1;
- break;
+ switch (msg->entry.hdr_size) {
+ case 0:
+ version = 1;
+ break;
- case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
- if (version == 0) {
- version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
- }
- break;
+ case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
+ if (version == 0) {
+ version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
+ }
+ break;
- case sizeof(msg->entry_v4):
- if (version == 0) {
- version = 4;
- }
- break;
+ case sizeof(msg->entry_v4):
+ if (version == 0) {
+ version = 4;
+ }
+ break;
}
fprintf(stderr, "%s: v%u[%u] ", prefix, version, msg->len());
if (version != 1) {
fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
}
- fprintf(stderr, "pid=%u tid=%u %u.%09u ",
- msg->entry.pid, msg->entry.tid, msg->entry.sec, msg->entry.nsec);
- switch(version) {
- case 1:
- break;
- case 2:
- fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
- break;
- case 3:
- default:
- lid = msg->entry.lid;
- break;
+ fprintf(stderr, "pid=%u tid=%u %u.%09u ", msg->entry.pid, msg->entry.tid,
+ msg->entry.sec, msg->entry.nsec);
+ switch (version) {
+ case 1:
+ break;
+ case 2:
+ fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
+ break;
+ case 3:
+ default:
+ lid = msg->entry.lid;
+ break;
}
- switch(lid) {
- case 0:
- fprintf(stderr, "lid=main ");
- break;
- case 1:
- fprintf(stderr, "lid=radio ");
- break;
- case 2:
- fprintf(stderr, "lid=events ");
- break;
- case 3:
- fprintf(stderr, "lid=system ");
- break;
- case 4:
- fprintf(stderr, "lid=crash ");
- break;
- case 5:
- fprintf(stderr, "lid=security ");
- break;
- case 6:
- fprintf(stderr, "lid=kernel ");
- break;
- default:
- if (lid >= 0) {
- fprintf(stderr, "lid=%d ", lid);
- }
+ switch (lid) {
+ case 0:
+ fprintf(stderr, "lid=main ");
+ break;
+ case 1:
+ fprintf(stderr, "lid=radio ");
+ break;
+ case 2:
+ fprintf(stderr, "lid=events ");
+ break;
+ case 3:
+ fprintf(stderr, "lid=system ");
+ break;
+ case 4:
+ fprintf(stderr, "lid=crash ");
+ break;
+ case 5:
+ fprintf(stderr, "lid=security ");
+ break;
+ case 6:
+ fprintf(stderr, "lid=kernel ");
+ break;
+ default:
+ if (lid >= 0) {
+ fprintf(stderr, "lid=%d ", lid);
+ }
}
unsigned int len = msg->entry.len;
fprintf(stderr, "msg[%u]={", len);
- unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
+ unsigned char* cp = reinterpret_cast<unsigned char*>(msg->msg());
if (!cp) {
static const unsigned char garbage[] = "<INVALID>";
- cp = const_cast<unsigned char *>(garbage);
- len = strlen(reinterpret_cast<const char *>(garbage));
+ cp = const_cast<unsigned char*>(garbage);
+ len = strlen(reinterpret_cast<const char*>(garbage));
}
- while(len) {
- unsigned char *p = cp;
+ while (len) {
+ unsigned char* p = cp;
while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
++p;
}
@@ -330,8 +323,7 @@
bool user_logger_available = false;
bool user_logger_content = false;
- int fd = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
+ int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
if (fd >= 0) {
struct sigaction ignore, old_sigaction;
@@ -360,10 +352,9 @@
bool kernel_logger_available = false;
bool kernel_logger_content = false;
- static const char *loggers[] = {
- "/dev/log/main", "/dev/log_main",
- "/dev/log/radio", "/dev/log_radio",
- "/dev/log/events", "/dev/log_events",
+ static const char* loggers[] = {
+ "/dev/log/main", "/dev/log_main", "/dev/log/radio",
+ "/dev/log_radio", "/dev/log/events", "/dev/log_events",
"/dev/log/system", "/dev/log_system",
};
@@ -389,10 +380,9 @@
"user %-13s%s\n"
"kernel %-13s%s\n"
" status %-11s%s\n",
- (user_logger_available) ? yes : no,
- (user_logger_content) ? yes : no,
+ (user_logger_available) ? yes : no, (user_logger_content) ? yes : no,
(kernel_logger_available) ? yes : no,
- (kernel_logger_content) ? yes : no,
+ (kernel_logger_content) ? yes : no,
(user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
(user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
@@ -415,39 +405,37 @@
//
TEST(logd, benchmark) {
size_t len;
- char *buf;
+ char* buf;
alloc_statistics(&buf, &len);
bool benchmark_already_run = buf && find_benchmark_spam(buf);
- delete [] buf;
+ delete[] buf;
if (benchmark_already_run) {
- fprintf(stderr, "WARNING: spam already present and too much history\n"
- " false OK for prune by worst UID check\n");
+ fprintf(stderr,
+ "WARNING: spam already present and too much history\n"
+ " false OK for prune by worst UID check\n");
}
- FILE *fp;
+ FILE* fp;
// Introduce some extreme spam for the worst UID filter
- ASSERT_TRUE(NULL != (fp = popen(
- "/data/nativetest/liblog-benchmarks/liblog-benchmarks"
- " BM_log_maximum_retry"
- " BM_log_maximum"
- " BM_clock_overhead"
- " BM_log_overhead"
- " BM_log_latency"
- " BM_log_delay",
- "r")));
+ ASSERT_TRUE(
+ NULL !=
+ (fp = popen("/data/nativetest/liblog-benchmarks/liblog-benchmarks"
+ " BM_log_maximum_retry"
+ " BM_log_maximum"
+ " BM_clock_overhead"
+ " BM_log_overhead"
+ " BM_log_latency"
+ " BM_log_delay",
+ "r")));
char buffer[5120];
- static const char *benchmarks[] = {
- "BM_log_maximum_retry ",
- "BM_log_maximum ",
- "BM_clock_overhead ",
- "BM_log_overhead ",
- "BM_log_latency ",
- "BM_log_delay "
+ static const char* benchmarks[] = {
+ "BM_log_maximum_retry ", "BM_log_maximum ", "BM_clock_overhead ",
+ "BM_log_overhead ", "BM_log_latency ", "BM_log_delay "
};
static const unsigned int log_maximum_retry = 0;
static const unsigned int log_maximum = 1;
@@ -462,7 +450,7 @@
while (fgets(buffer, sizeof(buffer), fp)) {
for (unsigned i = 0; i < arraysize(ns); ++i) {
- char *cp = strstr(buffer, benchmarks[i]);
+ char* cp = strstr(buffer, benchmarks[i]);
if (!cp) {
continue;
}
@@ -480,17 +468,18 @@
return;
}
- EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
+ EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
- EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
+ EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
- EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
+ EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
- EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
+ EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
- EXPECT_GE(10000000UL, ns[log_latency]); // 1453559 user space (background cgroup)
+ EXPECT_GE(10000000UL,
+ ns[log_latency]); // 1453559 user space (background cgroup)
- EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
+ EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
for (unsigned i = 0; i < arraysize(ns); ++i) {
EXPECT_NE(0UL, ns[i]);
@@ -503,7 +492,7 @@
ASSERT_TRUE(NULL != buf);
- char *benchmark_statistics_found = find_benchmark_spam(buf);
+ char* benchmark_statistics_found = find_benchmark_spam(buf);
ASSERT_TRUE(benchmark_statistics_found != NULL);
// Check how effective the SPAM filter is, parse out Now size.
@@ -512,13 +501,12 @@
unsigned long nowSpamSize = atol(benchmark_statistics_found);
- delete [] buf;
+ delete[] buf;
ASSERT_NE(0UL, nowSpamSize);
// Determine if we have the spam filter enabled
- int sock = socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
ASSERT_TRUE(sock >= 0);
@@ -528,26 +516,27 @@
char buffer[80];
memset(buffer, 0, sizeof(buffer));
read(sock, buffer, sizeof(buffer));
- char *cp = strchr(buffer, '\n');
+ char* cp = strchr(buffer, '\n');
if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
close(sock);
fprintf(stderr,
"WARNING: "
- "Logger has SPAM filtration turned off \"%s\"\n", buffer);
+ "Logger has SPAM filtration turned off \"%s\"\n",
+ buffer);
return;
}
} else {
int save_errno = errno;
close(sock);
- FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
+ FAIL() << "Can not send " << getPruneList << " to logger -- "
+ << strerror(save_errno);
}
static const unsigned long expected_absolute_minimum_log_size = 65536UL;
unsigned long totalSize = expected_absolute_minimum_log_size;
- static const char getSize[] = {
- 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
- LOG_ID_MAIN + '0', '\0'
- };
+ static const char getSize[] = { 'g', 'e', 't', 'L', 'o', 'g',
+ 'S', 'i', 'z', 'e', ' ', LOG_ID_MAIN + '0',
+ '\0' };
if (write(sock, getSize, sizeof(getSize)) > 0) {
char buffer[80];
memset(buffer, 0, sizeof(buffer));
@@ -556,21 +545,22 @@
if (totalSize < expected_absolute_minimum_log_size) {
fprintf(stderr,
"WARNING: "
- "Logger had unexpected referenced size \"%s\"\n", buffer);
+ "Logger had unexpected referenced size \"%s\"\n",
+ buffer);
totalSize = expected_absolute_minimum_log_size;
}
}
close(sock);
// logd allows excursions to 110% of total size
- totalSize = (totalSize * 11 ) / 10;
+ totalSize = (totalSize * 11) / 10;
// 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
ASSERT_GT(totalSize, nowSpamSize * 2);
}
// b/26447386 confirm fixed
-void timeout_negative(const char *command) {
+void timeout_negative(const char* command) {
log_msg msg_wrap, msg_timeout;
bool content_wrap = false, content_timeout = false, written = false;
unsigned int alarm_wrap = 0, alarm_timeout = 0;
@@ -579,8 +569,7 @@
int i = 3;
while (--i) {
- int fd = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
+ int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
ASSERT_LT(0, fd);
@@ -609,15 +598,16 @@
// alarm triggers at 133% of the --wrap time out
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
+ if (!content_timeout) { // make sure we hit dumpAndClose
+ content_timeout =
+ recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
}
- alarm_timeout = alarm((old_alarm <= 0)
- ? old_alarm
- : (old_alarm > (1 + 3 - alarm_wrap))
- ? old_alarm - 3 + alarm_wrap
- : 2);
+ alarm_timeout =
+ alarm((old_alarm <= 0) ? old_alarm
+ : (old_alarm > (1 + 3 - alarm_wrap))
+ ? old_alarm - 3 + alarm_wrap
+ : 2);
sigaction(SIGALRM, &old_sigaction, NULL);
close(fd);
@@ -647,7 +637,8 @@
}
TEST(logd, timeout_start_epoch) {
- timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
+ timeout_negative(
+ "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
}
// b/26447386 refined behavior
@@ -672,18 +663,17 @@
// content providers being active during the test.
int i = 5;
log_time now(android_log_clockid());
- now.tv_sec -= 30; // reach back a moderate period of time
+ now.tv_sec -= 30; // reach back a moderate period of time
while (--i) {
- int fd = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
+ int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
EXPECT_LT(0, fd);
if (fd < 0) _exit(fd);
std::string ask = android::base::StringPrintf(
- "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%"
- PRIu32 ".%09" PRIu32,
+ "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
+ ".%09" PRIu32,
now.tv_sec, now.tv_nsec);
struct sigaction ignore, old_sigaction;
@@ -709,15 +699,16 @@
// alarm triggers at 133% of the --wrap time out
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
+ if (!content_timeout) { // make sure we hit dumpAndClose
+ content_timeout =
+ recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
}
- alarm_timeout = alarm((old_alarm <= 0)
- ? old_alarm
- : (old_alarm > (1 + 3 - alarm_wrap))
- ? old_alarm - 3 + alarm_wrap
- : 2);
+ alarm_timeout =
+ alarm((old_alarm <= 0) ? old_alarm
+ : (old_alarm > (1 + 3 - alarm_wrap))
+ ? old_alarm - 3 + alarm_wrap
+ : 2);
sigaction(SIGALRM, &old_sigaction, NULL);
close(fd);
@@ -742,7 +733,7 @@
}
}
} else {
- now.tv_sec -= 120; // inactive, reach further back!
+ now.tv_sec -= 120; // inactive, reach further back!
}
}
@@ -755,8 +746,8 @@
}
if (content_wrap || !content_timeout) {
- fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n",
- now.tv_sec, now.tv_nsec);
+ fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n", now.tv_sec,
+ now.tv_nsec);
}
EXPECT_TRUE(written);
@@ -765,20 +756,22 @@
EXPECT_TRUE(content_timeout);
EXPECT_NE(0U, alarm_timeout);
- _exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout);
+ _exit(!written + content_wrap + alarm_wrap + !content_timeout +
+ !alarm_timeout);
}
// b/27242723 confirmed fixed
TEST(logd, SNDTIMEO) {
- static const unsigned sndtimeo = LOGD_SNDTIMEO; // <sigh> it has to be done!
+ static const unsigned sndtimeo =
+ LOGD_SNDTIMEO; // <sigh> it has to be done!
static const unsigned sleep_time = sndtimeo + 3;
static const unsigned alarm_time = sleep_time + 5;
int fd;
- ASSERT_TRUE((fd = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET)) > 0);
+ ASSERT_TRUE(
+ (fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET)) > 0);
struct sigaction ignore, old_sigaction;
memset(&ignore, 0, sizeof(ignore));
@@ -787,7 +780,7 @@
sigaction(SIGALRM, &ignore, &old_sigaction);
unsigned int old_alarm = alarm(alarm_time);
- static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
+ static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
EXPECT_TRUE(reader_requested);
@@ -799,7 +792,7 @@
dump_log_msg("user", &msg, 3, -1);
}
- fprintf (stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
+ fprintf(stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
sleep(sleep_time);
// flush will block if we did not trigger. if it did, last entry returns 0
@@ -828,7 +821,7 @@
snprintf(buffer, sizeof(buffer), "getEventTag name=*");
send_to_control(buffer, sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
- char *cp;
+ char* cp;
long ret = strtol(buffer, &cp, 10);
EXPECT_GT(ret, 4096);
#else
@@ -836,6 +829,23 @@
#endif
}
+TEST(logd, getEventTag_42) {
+#ifdef __ANDROID__
+ char buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ snprintf(buffer, sizeof(buffer), "getEventTag id=42");
+ send_to_control(buffer, sizeof(buffer));
+ buffer[sizeof(buffer) - 1] = '\0';
+ char* cp;
+ long ret = strtol(buffer, &cp, 10);
+ EXPECT_GT(ret, 16);
+ EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != NULL);
+ EXPECT_TRUE(strstr(buffer, "answer") != NULL);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
TEST(logd, getEventTag_newentry) {
#ifdef __ANDROID__
char buffer[256];
@@ -843,24 +853,23 @@
log_time now(CLOCK_MONOTONIC);
char name[64];
snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer),
- "getEventTag name=%s format=\"(new|1)\"", name);
+ snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
+ name);
send_to_control(buffer, sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
- char *cp;
+ char* cp;
long ret = strtol(buffer, &cp, 10);
EXPECT_GT(ret, 16);
EXPECT_TRUE(strstr(buffer, "\t(new|1)") != NULL);
EXPECT_TRUE(strstr(buffer, name) != NULL);
- // ToDo: also look for this in /data/misc/logd/event-log-tags and
- // /dev/event-log-tags.
+// ToDo: also look for this in /data/misc/logd/event-log-tags and
+// /dev/event-log-tags.
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
-static inline int32_t get4LE(const char* src)
-{
+static inline int32_t get4LE(const char* src) {
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
@@ -877,10 +886,12 @@
if (pid == 0) {
// child
for (int i = count; i; --i) {
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+ ASSERT_LT(
+ 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
usleep(100);
}
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+ ASSERT_LT(0,
+ __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
usleep(1000000);
_exit(0);
@@ -890,9 +901,11 @@
ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
ASSERT_EQ(0, info.si_status);
- struct logger_list *logger_list;
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)));
+ struct logger_list* logger_list;
+ ASSERT_TRUE(NULL !=
+ (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ 0, pid)));
int expected_count = (count < 2) ? count : 2;
int expected_chatty_count = (count <= 2) ? 0 : 1;
@@ -909,16 +922,17 @@
log_msg log_msg;
if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
- if ((log_msg.entry.pid != pid) ||
- (log_msg.entry.len < (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) continue;
+ if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS))
+ continue;
- char *eventData = log_msg.msg();
+ char* eventData = log_msg.msg();
if (!eventData) continue;
uint32_t tag = get4LE(eventData);
- if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
+ if ((eventData[4] == EVENT_TYPE_LONG) &&
+ (log_msg.entry.len == (4 + 1 + 8))) {
if (tag != 0) continue;
log_time tx(eventData + 4 + 1);
@@ -932,7 +946,7 @@
++chatty_count;
// int len = get4LE(eventData + 4 + 1);
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
- const char *cp;
+ const char* cp;
if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) {
unsigned val = 0;
sscanf(cp, " identical %u lines", &val);
@@ -987,8 +1001,8 @@
int save_errno = errno;
security_context_t context;
getcon(&context);
- fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
- context, strerror(save_errno));
+ fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n", context,
+ strerror(save_errno));
freecon(context);
_exit(-1);
// NOTREACHED
@@ -1035,22 +1049,20 @@
if (pid == 0) return count;
- struct logger_list *logger_list;
- if (!(logger_list = android_logger_list_open(LOG_ID_EVENTS,
- ANDROID_LOG_RDONLY |
- ANDROID_LOG_NONBLOCK,
- 0,
- pid))) return count;
+ struct logger_list* logger_list;
+ if (!(logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)))
+ return count;
for (;;) {
log_msg log_msg;
if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
- if ((log_msg.entry.pid != pid) ||
- (log_msg.entry.len < (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) continue;
+ if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
+ (log_msg.id() != LOG_ID_EVENTS))
+ continue;
- char *eventData = log_msg.msg();
+ char* eventData = log_msg.msg();
if (!eventData) continue;
uint32_t tag = get4LE(eventData);
@@ -1060,7 +1072,7 @@
// int len = get4LE(eventData + 4 + 1);
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
- const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
+ const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
if (!cp) continue;
++count;
@@ -1086,10 +1098,11 @@
TEST(logd, sepolicy_rate_limiter_sub_burst) {
#ifdef __ANDROID__
// maximum period below half way between sustainable and burst rate.
- static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT +
- AUDIT_RATE_LIMIT_MAX)) +
- 1) / 2;
+ static const int threshold =
+ ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
+ 1) /
+ 2;
static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
@@ -1101,24 +1114,25 @@
TEST(logd, sepolicy_rate_limiter_spam) {
#ifdef __ANDROID__
// maximum period of double the maximum burst rate
- static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT +
- AUDIT_RATE_LIMIT_MAX)) +
- 1) / 2;
+ static const int threshold =
+ ((AUDIT_RATE_LIMIT_BURST_DURATION *
+ (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
+ 1) /
+ 2;
static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
- EXPECT_GE(((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) /
- 100, // +15% margin
- count_avc(sepolicy_rate(rate, rate * duration)));
+ EXPECT_GE(
+ ((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
+ count_avc(sepolicy_rate(rate, rate * duration)));
// give logd another 3 seconds to react to the burst before checking
sepolicy_rate(rate, rate * 3);
// maximum period at double the maximum burst rate (spam filter kicked in)
- EXPECT_GE(threshold * 2,
- count_avc(sepolicy_rate(rate,
- rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
+ EXPECT_GE(
+ threshold * 2,
+ count_avc(sepolicy_rate(rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
// cool down, and check unspammy rate still works
sleep(2);
- EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
+ EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/qemu_pipe/Android.mk b/qemu_pipe/Android.mk
new file mode 100644
index 0000000..6e0144c
--- /dev/null
+++ b/qemu_pipe/Android.mk
@@ -0,0 +1,19 @@
+# Copyright 2011 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+common_static_libraries := \
+ libbase
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+LOCAL_SRC_FILES:= \
+ qemu_pipe.cpp
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ system/base/include
+LOCAL_MODULE:= libqemu_pipe
+LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
+include $(BUILD_STATIC_LIBRARY)
diff --git a/qemu_pipe/include/qemu_pipe.h b/qemu_pipe/include/qemu_pipe.h
new file mode 100644
index 0000000..0987498
--- /dev/null
+++ b/qemu_pipe/include/qemu_pipe.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+#define ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+// For backward compatibility, the 'pipe:' prefix can be omitted, and in
+// that case, qemu_pipe_open will add it for you.
+
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+int qemu_pipe_open(const char* pipeName);
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len);
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_CORE_INCLUDE_QEMU_PIPE_H */
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp
new file mode 100644
index 0000000..beeccb0
--- /dev/null
+++ b/qemu_pipe/qemu_pipe.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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 "qemu_pipe.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <android-base/file.h>
+
+using android::base::ReadFully;
+using android::base::WriteFully;
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+# define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+int qemu_pipe_open(const char* pipeName) {
+ // Sanity check.
+ if (!pipeName) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+ strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ if (WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+
+ // now, add 'pipe:' prefix and try again
+ // Note: host side will wait for the trailing '\0' to start
+ // service lookup.
+ const char pipe_prefix[] = "pipe:";
+ if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) &&
+ WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+ QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s",
+ __FUNCTION__, pipeName, strerror(errno));
+ close(fd);
+ return -1;
+}
+
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04zx", len);
+ if (!WriteFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ if (!WriteFully(fd, buff, len)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ if (!ReadFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+ len);
+ return -1;
+ }
+ if (!ReadFully(fd, buff, size)) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+ strerror(errno));
+ return -1;
+ }
+ return size;
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 7d0c87d..86fec6a 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -53,7 +53,7 @@
# Pretty comprehensive set of native services. This list is helpful if all that's to be checked is an
# app.
-ifeq ($(SANITIZE_LITE),true)
+ifeq ($(SANITIZE_LITE_SERVICES),true)
SANITIZE_ASAN_OPTIONS_FOR := \
adbd \
ATFWD-daemon \
@@ -116,6 +116,12 @@
EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES)
endif
+
+EXPORT_GLOBAL_GCOV_OPTIONS :=
+ifeq ($(NATIVE_COVERAGE),true)
+ EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
+endif
+
# Put it here instead of in init.rc module definition,
# because init.rc is conditionally included.
#
@@ -163,6 +169,7 @@
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
+ $(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
bcp_md5 :=
bcp_dep :=
diff --git a/rootdir/init-debug.rc b/rootdir/init-debug.rc
index 44d34d8..435d4cb 100644
--- a/rootdir/init-debug.rc
+++ b/rootdir/init-debug.rc
@@ -6,6 +6,3 @@
on property:persist.mmc.cache_size=*
write /sys/block/mmcblk0/cache_size ${persist.mmc.cache_size}
-
-on early-init
- mount debugfs debugfs /sys/kernel/debug
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 32817fa..2e2ab74 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -10,3 +10,4 @@
export BOOTCLASSPATH %BOOTCLASSPATH%
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
%EXPORT_GLOBAL_ASAN_OPTIONS%
+ %EXPORT_GLOBAL_GCOV_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9ab2333..25cea7f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -244,6 +244,10 @@
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
+ # This allows the ledtrig-transient properties to be created here so
+ # that they can be chown'd to system:system later on boot
+ write /sys/class/leds/vibrator/trigger "transient"
+
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
@@ -290,6 +294,9 @@
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data
+ # Now we can start zygote for devices with file based encryption
+ trigger zygote-start
+
# Load persist properties and override properties (if enabled) from /data.
trigger load_persist_props_action
@@ -402,11 +409,13 @@
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
+ mkdir /data/misc/reboot 0700 root root
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
mkdir /data/misc/profiles/ref 0771 system system
mkdir /data/misc/profman 0770 system shell
+ mkdir /data/misc/gcov 0770 root root
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
@@ -488,6 +497,13 @@
# Set indication (checked by vold) that we have finished this action
#setprop vold.post_fs_data_done 1
+# This trigger will be triggered before 'zygote-start' since there is no zygote-start defined in
+# current init.rc. It is recommended to put unnecessary data/ initialization from post-fs-data
+# to start-zygote to unblock zygote start.
+on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
+ start netd
+ start zygote
+
on boot
# basic network init
ifup lo
@@ -551,6 +567,11 @@
chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
chmod 0660 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
+ chown system system /sys/class/leds/vibrator/trigger
+ chown system system /sys/class/leds/vibrator/activate
+ chown system system /sys/class/leds/vibrator/brightness
+ chown system system /sys/class/leds/vibrator/duration
+ chown system system /sys/class/leds/vibrator/state
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/class/leds/keyboard-backlight/brightness
chown system system /sys/class/leds/lcd-backlight/brightness
@@ -562,7 +583,6 @@
chown system system /sys/class/leds/red/device/grpfreq
chown system system /sys/class/leds/red/device/grppwm
chown system system /sys/class/leds/red/device/blink
- chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/module/sco/parameters/disable_esco
chown system system /sys/kernel/ipv4/tcp_wmem_min
chown system system /sys/kernel/ipv4/tcp_wmem_def
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index ed11164..80bb673 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 66e7750..36bb443 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index fb5c84b..769f0f5 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,26 +30,48 @@
#include "android-base/logging.h"
-static const char* BUNDLE_VERSION_FILENAME = "/bundle_version";
-// bundle_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
-// AAA.BBB is the major/minor version of the bundle format (e.g. 001.001),
+// The name of the file containing the distro version information.
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char* DISTRO_VERSION_FILENAME = "/distro_version";
+
+// distro_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
+// AAA.BBB is the major/minor version of the distro format (e.g. 001.001),
// CCCCC is the rules version (e.g. 2016g)
-// DDD is the android revision for this rules version to allow for bundle corrections (e.g. 001)
+// DDD is the android revision for this rules version to allow for distro corrections (e.g. 001)
// We only need the first 13 to determine if it is suitable for the device.
-static const int BUNDLE_VERSION_LENGTH = 13;
-// The major version of the bundle format supported by this code as a null-terminated char[].
-static const char REQUIRED_BUNDLE_VERSION[] = "001";
-static const size_t REQUIRED_BUNDLE_VERSION_LEN = sizeof(REQUIRED_BUNDLE_VERSION) - 1; // exclude \0
+static const int DISTRO_VERSION_LENGTH = 13;
+
+// The major version of the distro format supported by this code as a null-terminated char[].
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char SUPPORTED_DISTRO_MAJOR_VERSION[] = "001";
+
+// The length of the distro format major version excluding the \0
+static const size_t SUPPORTED_DISTRO_MAJOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MAJOR_VERSION) - 1;
+
+// The minor version of the distro format supported by this code as a null-terminated char[].
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char SUPPORTED_DISTRO_MINOR_VERSION[] = "001";
+
+// The length of the distro format minor version excluding the \0
+static const size_t SUPPORTED_DISTRO_MINOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MINOR_VERSION) - 1;
+
+// The length of the distro format version. e.g. 001.001
+static const size_t SUPPORTED_DISTRO_VERSION_LEN =
+ SUPPORTED_DISTRO_MAJOR_VERSION_LEN + SUPPORTED_DISTRO_MINOR_VERSION_LEN + 1;
+
// The length of the IANA rules version bytes. e.g. 2016a
static const size_t RULES_VERSION_LEN = 5;
-// Bundle version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
-static const size_t BUNDLE_VERSION_RULES_IDX = 8;
+// Distro version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
+static const size_t DISTRO_VERSION_RULES_IDX = 8;
+
+// See also libcore.tzdata.update2.TimeZoneDistro.
static const char* TZDATA_FILENAME = "/tzdata";
+
// tzdata file header (as much as we need for the version):
// byte[11] tzdata_version -- e.g. "tzdata2012f"
static const int TZ_HEADER_LENGTH = 11;
-// The major version of the bundle format supported by this code as a null-terminated char[].
+
static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
@@ -57,7 +79,7 @@
static void usage() {
std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
"\n"
- "Checks whether any timezone update bundle in DATA_TZ_DIR is compatible with the\n"
+ "Checks whether any timezone update distro in DATA_TZ_DIR is compatible with the\n"
"current Android release and better than or the same as base system timezone rules in\n"
"SYSTEM_TZ_DIR. If the timezone rules in SYSTEM_TZ_DIR are a higher version than the\n"
"one in DATA_TZ_DIR the DATA_TZ_DIR is renamed and then deleted.\n";
@@ -108,8 +130,8 @@
return true;
}
-static bool checkValidBundleVersion(const char* buffer) {
- // See BUNDLE_VERSION_LENGTH comments above for a description of the format.
+static bool checkValidDistroVersion(const char* buffer) {
+ // See DISTRO_VERSION_LENGTH comments above for a description of the format.
size_t i = 0;
if (!checkDigits(buffer, 3, &i)) {
return false;
@@ -246,13 +268,13 @@
}
/*
- * Deletes the timezone update bundle directory.
+ * Deletes the timezone update distro directory.
*/
-static void deleteUpdateBundleDir(std::string& bundleDirName) {
- LOG(INFO) << "Removing: " << bundleDirName;
- bool deleted = deleteDir(bundleDirName);
+static void deleteUpdateDistroDir(std::string& distroDirName) {
+ LOG(INFO) << "Removing: " << distroDirName;
+ bool deleted = deleteDir(distroDirName);
if (!deleted) {
- LOG(WARNING) << "Deletion of bundle dir " << bundleDirName << " was not successful";
+ LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
}
}
@@ -278,60 +300,83 @@
const char* systemZoneInfoDir = argv[1];
const char* dataZoneInfoDir = argv[2];
- // Check the bundle directory exists. If it does not, exit quickly: nothing to do.
+ // Check the distro directory exists. If it does not, exit quickly: nothing to do.
std::string dataCurrentDirName(dataZoneInfoDir);
dataCurrentDirName += "/current";
int dataCurrentDirStatus = checkPath(dataCurrentDirName);
if (dataCurrentDirStatus == NONE) {
- LOG(INFO) << "timezone bundle dir " << dataCurrentDirName
+ LOG(INFO) << "timezone distro dir " << dataCurrentDirName
<< " does not exist. No action required.";
return 0;
}
- // If the bundle directory path is not a directory or we can't stat() the path, exit with a
+ // If the distro directory path is not a directory or we can't stat() the path, exit with a
// warning: either there's a problem accessing storage or the world is not as it should be;
// nothing to do.
if (dataCurrentDirStatus != IS_DIR) {
- LOG(WARNING) << "Current bundle dir " << dataCurrentDirName
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
<< " could not be accessed or is not a directory. result=" << dataCurrentDirStatus;
return 2;
}
- // Check the installed bundle version.
- std::string bundleVersionFileName(dataCurrentDirName);
- bundleVersionFileName += BUNDLE_VERSION_FILENAME;
- std::vector<char> bundleVersion;
- bundleVersion.reserve(BUNDLE_VERSION_LENGTH);
- bool bundleVersionReadOk =
- readBytes(bundleVersionFileName, bundleVersion.data(), BUNDLE_VERSION_LENGTH);
- if (!bundleVersionReadOk) {
- LOG(WARNING) << "bundle version file " << bundleVersionFileName
- << " does not exist or is too short. Deleting bundle dir.";
+ // Check the installed distro version.
+ std::string distroVersionFileName(dataCurrentDirName);
+ distroVersionFileName += DISTRO_VERSION_FILENAME;
+ std::vector<char> distroVersion;
+ distroVersion.reserve(DISTRO_VERSION_LENGTH);
+ bool distroVersionReadOk =
+ readBytes(distroVersionFileName, distroVersion.data(), DISTRO_VERSION_LENGTH);
+ if (!distroVersionReadOk) {
+ LOG(WARNING) << "distro version file " << distroVersionFileName
+ << " does not exist or is too short. Deleting distro dir.";
// Implies the contents of the data partition is corrupt in some way. Try to clean up.
deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
- deleteUpdateBundleDir(dataCurrentDirName);
+ deleteUpdateDistroDir(dataCurrentDirName);
return 3;
}
- if (!checkValidBundleVersion(bundleVersion.data())) {
- LOG(WARNING) << "bundle version file " << bundleVersionFileName
- << " is not valid. Deleting bundle dir.";
+ if (!checkValidDistroVersion(distroVersion.data())) {
+ LOG(WARNING) << "distro version file " << distroVersionFileName
+ << " is not valid. Deleting distro dir.";
// Implies the contents of the data partition is corrupt in some way. Try to clean up.
deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
- deleteUpdateBundleDir(dataCurrentDirName);
+ deleteUpdateDistroDir(dataCurrentDirName);
return 4;
}
- // Check the first 3 bytes of the bundleVersionHeader: these are the major version (e.g. 001).
- // It must match exactly to be ok. The minor version is currently ignored.
- if (strncmp(&bundleVersion[0], REQUIRED_BUNDLE_VERSION, REQUIRED_BUNDLE_VERSION_LEN) != 0) {
- LOG(INFO) << "bundle version file " << bundleVersionFileName
- << " is not the required version " << REQUIRED_BUNDLE_VERSION
- << ". Deleting bundle dir.";
- // This shouldn't happen with 001, but it in future, this will imply there has been an OTA
- // and the installed bundle is not compatible with the new version of Android. Remove the
- // installed bundle.
+ std::string actualDistroVersion =
+ std::string(distroVersion.data(), SUPPORTED_DISTRO_VERSION_LEN);
+ // Check the first 3 bytes of the distro version: these are the major version (e.g. 001).
+ // It must match the one we support exactly to be ok.
+ if (strncmp(
+ &distroVersion[0],
+ SUPPORTED_DISTRO_MAJOR_VERSION,
+ SUPPORTED_DISTRO_MAJOR_VERSION_LEN) != 0) {
+
+ LOG(INFO) << "distro version file " << distroVersionFileName
+ << " major version is not the required version " << SUPPORTED_DISTRO_MAJOR_VERSION
+ << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
+ // This implies there has been an OTA and the installed distro is not compatible with the
+ // new version of Android. Remove the installed distro.
deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
- deleteUpdateBundleDir(dataCurrentDirName);
+ deleteUpdateDistroDir(dataCurrentDirName);
+ return 5;
+ }
+
+ // Check the last 3 bytes of the distro version: these are the minor version (e.g. 001).
+ // If the version in the distro is < the minor version required by this device it cannot be
+ // used.
+ if (strncmp(
+ &distroVersion[4],
+ SUPPORTED_DISTRO_MINOR_VERSION,
+ SUPPORTED_DISTRO_MINOR_VERSION_LEN) < 0) {
+
+ LOG(INFO) << "distro version file " << distroVersionFileName
+ << " minor version is not the required version " << SUPPORTED_DISTRO_MINOR_VERSION
+ << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
+ // This implies there has been an OTA and the installed distro is not compatible with the
+ // new version of Android. Remove the installed distro.
+ deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+ deleteUpdateDistroDir(dataCurrentDirName);
return 5;
}
@@ -353,22 +398,22 @@
return 7;
}
- // Compare the bundle rules version against the system rules version.
+ // Compare the distro rules version against the system rules version.
if (strncmp(
&systemTzDataHeader[TZ_DATA_HEADER_PREFIX_LEN],
- &bundleVersion[BUNDLE_VERSION_RULES_IDX],
+ &distroVersion[DISTRO_VERSION_RULES_IDX],
RULES_VERSION_LEN) <= 0) {
- LOG(INFO) << "Found an installed bundle but it is valid. No action taken.";
+ LOG(INFO) << "Found an installed distro but it is valid. No action taken.";
// Implies there is an installed update, but it is good.
return 0;
}
// Implies there has been an OTA and the system version of the timezone rules is now newer
- // than the version installed in /data. Remove the installed bundle.
- LOG(INFO) << "timezone bundle in " << dataCurrentDirName << " is older than data in "
+ // than the version installed in /data. Remove the installed distro.
+ LOG(INFO) << "timezone distro in " << dataCurrentDirName << " is older than data in "
<< systemTzDataFileName << "; fixing...";
deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
- deleteUpdateBundleDir(dataCurrentDirName);
+ deleteUpdateDistroDir(dataCurrentDirName);
return 0;
}