Merge "init_kill_services_test: also reboot after"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index e562f8b..d66d400 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -310,7 +310,7 @@
const auto start = clock::now();
int first_apk = -1;
int last_apk = -1;
- std::vector<std::string_view> args = {"package"sv};
+ incremental::Args passthrough_args = {};
for (int i = 0; i < argc; ++i) {
const auto arg = std::string_view(argv[i]);
if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
@@ -318,12 +318,11 @@
if (first_apk == -1) {
first_apk = i;
}
- } else if (arg.starts_with("install-"sv)) {
+ } else if (arg.starts_with("install"sv)) {
// incremental installation command on the device is the same for all its variations in
// the adb, e.g. install-multiple or install-multi-package
- args.push_back("install"sv);
} else {
- args.push_back(arg);
+ passthrough_args.push_back(arg);
}
}
@@ -344,7 +343,7 @@
}
printf("Performing Incremental Install\n");
- auto server_process = incremental::install(files, silent);
+ auto server_process = incremental::install(files, passthrough_args, silent);
if (!server_process) {
return -1;
}
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index 2814932..a8b0ab3 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -93,12 +93,10 @@
// Send install-incremental to the device along with properly configured file descriptors in
// streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, bool silent) {
+static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
std::vector<std::string> command_args{"package", "install-incremental"};
+ command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
- // fd's with positions at the beginning of fs-verity
- std::vector<unique_fd> signature_fds;
- signature_fds.reserve(files.size());
for (int i = 0, size = files.size(); i < size; ++i) {
const auto& file = files[i];
@@ -118,8 +116,6 @@
auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
(long long)st.st_size, i, signature.c_str());
command_args.push_back(std::move(file_desc));
-
- signature_fds.push_back(std::move(signature_fd));
}
std::string error;
@@ -150,8 +146,8 @@
return true;
}
-std::optional<Process> install(const Files& files, bool silent) {
- auto connection_fd = start_install(files, silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
+ auto connection_fd = start_install(files, passthrough_args, silent);
if (connection_fd < 0) {
if (!silent) {
fprintf(stderr, "adb: failed to initiate installation on device.\n");
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 1fb1e0b..40e928a 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -26,9 +26,10 @@
namespace incremental {
using Files = std::vector<std::string>;
+using Args = std::vector<std::string_view>;
bool can_install(const Files& files);
-std::optional<Process> install(const Files& files, bool silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent);
enum class Result { Success, Failure, None };
Result wait_for_installation(int read_fd);
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 6b49fc7..bdb786c 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -117,8 +117,10 @@
"device/main.cpp",
"device/usb.cpp",
"device/usb_client.cpp",
+ "device/tcp_client.cpp",
"device/utility.cpp",
"device/variables.cpp",
+ "socket.cpp",
],
shared_libs: [
@@ -143,6 +145,7 @@
],
static_libs: [
+ "libgtest_prod",
"libhealthhalutils",
"libsnapshot_nobinder",
"update_metadata-protos",
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index bb085c5..1b0859f 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -19,6 +19,7 @@
#include <algorithm>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/fastboot/1.0/IFastboot.h>
@@ -28,6 +29,7 @@
#include "constants.h"
#include "flashing.h"
+#include "tcp_client.h"
#include "usb_client.h"
using android::fs_mgr::EnsurePathUnmounted;
@@ -60,11 +62,16 @@
{FB_CMD_GSI, GsiHandler},
{FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
}),
- transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()),
health_hal_(get_health_service()),
fastboot_hal_(IFastboot::getService()),
active_slot_("") {
+ if (android::base::GetProperty("fastbootd.protocol", "usb") == "tcp") {
+ transport_ = std::make_unique<ClientTcpTransport>();
+ } else {
+ transport_ = std::make_unique<ClientUsbTransport>();
+ }
+
if (boot_control_hal_) {
boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
}
diff --git a/fastboot/device/tcp_client.cpp b/fastboot/device/tcp_client.cpp
new file mode 100644
index 0000000..ec5e1e3
--- /dev/null
+++ b/fastboot/device/tcp_client.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 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 "tcp_client.h"
+#include "constants.h"
+
+#include <android-base/errors.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+static constexpr int kDefaultPort = 5554;
+static constexpr int kProtocolVersion = 1;
+static constexpr int kHandshakeTimeoutMs = 2000;
+static constexpr size_t kHandshakeLength = 4;
+
+// Extract the big-endian 8-byte message length into a 64-bit number.
+static uint64_t ExtractMessageLength(const void* buffer) {
+ uint64_t ret = 0;
+ for (int i = 0; i < 8; ++i) {
+ ret |= uint64_t{reinterpret_cast<const uint8_t*>(buffer)[i]} << (56 - i * 8);
+ }
+ return ret;
+}
+
+// Encode the 64-bit number into a big-endian 8-byte message length.
+static void EncodeMessageLength(uint64_t length, void* buffer) {
+ for (int i = 0; i < 8; ++i) {
+ reinterpret_cast<uint8_t*>(buffer)[i] = length >> (56 - i * 8);
+ }
+}
+
+ClientTcpTransport::ClientTcpTransport() {
+ service_ = Socket::NewServer(Socket::Protocol::kTcp, kDefaultPort);
+
+ // A workaround to notify recovery to continue its work.
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+}
+
+ssize_t ClientTcpTransport::Read(void* data, size_t len) {
+ if (len > SSIZE_MAX) {
+ return -1;
+ }
+
+ size_t total_read = 0;
+ do {
+ // Read a new message
+ while (message_bytes_left_ == 0) {
+ if (socket_ == nullptr) {
+ ListenFastbootSocket();
+ }
+
+ char buffer[8];
+ if (socket_->ReceiveAll(buffer, 8, 0) == 8) {
+ message_bytes_left_ = ExtractMessageLength(buffer);
+ } else {
+ // If connection is closed by host, Receive will return 0 immediately.
+ socket_.reset(nullptr);
+ // In DATA phase, return error.
+ if (downloading_) {
+ return -1;
+ }
+ }
+ }
+
+ size_t read_length = len - total_read;
+ if (read_length > message_bytes_left_) {
+ read_length = message_bytes_left_;
+ }
+ ssize_t bytes_read =
+ socket_->ReceiveAll(reinterpret_cast<char*>(data) + total_read, read_length, 0);
+ if (bytes_read == -1) {
+ socket_.reset(nullptr);
+ return -1;
+ } else {
+ message_bytes_left_ -= bytes_read;
+ total_read += bytes_read;
+ }
+ // There are more than one DATA phases if the downloading buffer is too
+ // large, like a very big system image. All of data phases should be
+ // received until the whole buffer is filled in that case.
+ } while (downloading_ && total_read < len);
+
+ return total_read;
+}
+
+ssize_t ClientTcpTransport::Write(const void* data, size_t len) {
+ if (socket_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+
+ // Use multi-buffer writes for better performance.
+ char header[8];
+ EncodeMessageLength(len, header);
+
+ if (!socket_->Send(std::vector<cutils_socket_buffer_t>{{header, 8}, {data, len}})) {
+ socket_.reset(nullptr);
+ return -1;
+ }
+
+ // In DATA phase
+ if (android::base::StartsWith(reinterpret_cast<const char*>(data), RESPONSE_DATA)) {
+ downloading_ = true;
+ } else {
+ downloading_ = false;
+ }
+
+ return len;
+}
+
+int ClientTcpTransport::Close() {
+ if (socket_ == nullptr) {
+ return -1;
+ }
+ socket_.reset(nullptr);
+
+ return 0;
+}
+
+int ClientTcpTransport::Reset() {
+ return Close();
+}
+
+void ClientTcpTransport::ListenFastbootSocket() {
+ while (true) {
+ socket_ = service_->Accept();
+
+ // Handshake
+ char buffer[kHandshakeLength + 1];
+ buffer[kHandshakeLength] = '\0';
+ if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) !=
+ kHandshakeLength) {
+ PLOG(ERROR) << "No Handshake message received";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ if (memcmp(buffer, "FB", 2) != 0) {
+ PLOG(ERROR) << "Unrecognized initialization message";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ int version = 0;
+ if (!android::base::ParseInt(buffer + 2, &version) || version < kProtocolVersion) {
+ LOG(ERROR) << "Unknown TCP protocol version " << buffer + 2
+ << ", our version: " << kProtocolVersion;
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ std::string handshake_message(android::base::StringPrintf("FB%02d", kProtocolVersion));
+ if (!socket_->Send(handshake_message.c_str(), kHandshakeLength)) {
+ PLOG(ERROR) << "Failed to send initialization message";
+ socket_.reset(nullptr);
+ continue;
+ }
+
+ break;
+ }
+}
diff --git a/fastboot/device/tcp_client.h b/fastboot/device/tcp_client.h
new file mode 100644
index 0000000..32e9834
--- /dev/null
+++ b/fastboot/device/tcp_client.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+
+#include "socket.h"
+#include "transport.h"
+
+class ClientTcpTransport : public Transport {
+ public:
+ ClientTcpTransport();
+ ~ClientTcpTransport() override = default;
+
+ ssize_t Read(void* data, size_t len) override;
+ ssize_t Write(const void* data, size_t len) override;
+ int Close() override;
+ int Reset() override;
+
+ private:
+ void ListenFastbootSocket();
+
+ std::unique_ptr<Socket> service_;
+ std::unique_ptr<Socket> socket_;
+ uint64_t message_bytes_left_ = 0;
+ bool downloading_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientTcpTransport);
+};
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index e56ffcf..5a14b63 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -54,7 +54,9 @@
while (total < length) {
ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
- if (bytes == -1) {
+ // Returns 0 only when the peer has disconnected because our requested length is not 0. So
+ // we return immediately to avoid dead loop here.
+ if (bytes <= 0) {
if (total == 0) {
return -1;
}
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 4505382..2288674 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -124,6 +124,64 @@
return true;
}
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
+ bool found = false;
+ const uint8_t* desc_partition_name;
+ auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
+
+ for (const auto& vbmeta : vbmeta_images) {
+ size_t num_descriptors;
+ std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
+ avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+ if (!descriptors || num_descriptors < 1) {
+ continue;
+ }
+
+ for (size_t n = 0; n < num_descriptors && !found; n++) {
+ AvbDescriptor desc;
+ if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+ LWARNING << "Descriptor[" << n << "] is invalid";
+ continue;
+ }
+ if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
+ desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
+ if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
+ hash_desc.get())) {
+ continue;
+ }
+ if (hash_desc->partition_name_len != partition_name.length()) {
+ continue;
+ }
+ // Notes that desc_partition_name is not NUL-terminated.
+ std::string hash_partition_name((const char*)desc_partition_name,
+ hash_desc->partition_name_len);
+ if (hash_partition_name == partition_name) {
+ found = true;
+ }
+ }
+ }
+
+ if (found) break;
+ }
+
+ if (!found) {
+ LERROR << "Hash descriptor not found: " << partition_name;
+ return nullptr;
+ }
+
+ hash_desc->partition_name = partition_name;
+
+ const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
+ hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
+
+ const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
+ hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
+
+ return hash_desc;
+}
+
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
bool found = false;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 09c786a..e8f7c39 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -40,6 +40,9 @@
std::string GetAvbPropertyDescriptor(const std::string& key,
const std::vector<VBMetaData>& vbmeta_images);
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
+
// AvbHashtreeDescriptor to dm-verity table setup.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
index f82f83d..1c14cc0 100644
--- a/fs_mgr/libfs_avb/fs_avb_util.cpp
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -74,5 +74,15 @@
return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
}
+// Given a path, loads and verifies the vbmeta, to extract the Avb Hash descriptor.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+ VBMetaData&& vbmeta) {
+ if (!vbmeta.size()) return nullptr;
+
+ std::vector<VBMetaData> vbmeta_images;
+ vbmeta_images.emplace_back(std::move(vbmeta));
+ return GetHashDescriptor(avb_partition_name, vbmeta_images);
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
index ec8badb..3f37bd7 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -32,9 +32,20 @@
std::string* out_avb_partition_name,
VBMetaVerifyResult* out_verify_result);
+// Loads the single vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+ const std::string& image_path, const std::string& partition_name,
+ const std::string& expected_public_key_blob, bool allow_verification_error,
+ bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
+ bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result);
+
// Gets the hashtree descriptor for avb_partition_name from the vbmeta.
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
const std::string& avb_partition_name, VBMetaData&& vbmeta);
+// Gets the hash descriptor for avb_partition_name from the vbmeta.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+ VBMetaData&& vbmeta);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/types.h b/fs_mgr/libfs_avb/include/fs_avb/types.h
index bd638e6..f2aa7cc 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/types.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/types.h
@@ -55,6 +55,12 @@
std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
+struct FsAvbHashDescriptor : AvbHashDescriptor {
+ std::string partition_name;
+ std::string salt;
+ std::string digest;
+};
+
struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
std::string partition_name;
std::string salt;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index e916693..c191102 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -289,7 +289,7 @@
canonical_path_from_root: false,
local_include_dirs: ["."],
},
-
+ corpus: ["corpus/*"],
fuzz_config: {
cc: ["android-virtual-ab+bugs@google.com"],
componentid: 30545,
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
index 91fbb60..a55b42a 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
@@ -64,6 +64,7 @@
bool has_metadata_device_object = 1;
bool metadata_mounted = 2;
}
+ reserved 18 to 9999;
oneof value {
NoArgs begin_update = 1;
NoArgs cancel_update = 2;
@@ -82,6 +83,9 @@
NoArgs dump = 15;
NoArgs ensure_metadata_mounted = 16;
NoArgs get_snapshot_merge_stats_instance = 17;
+
+ // Test directives that has nothing to do with ISnapshotManager API surface.
+ NoArgs switch_slot = 10000;
}
}
@@ -97,7 +101,10 @@
bool is_super_metadata_valid = 3;
chromeos_update_engine.DeltaArchiveManifest super_data = 4;
+ // Whether the directory that mocks /metadata/ota/snapshot is created.
+ bool has_metadata_snapshots_dir = 5;
+
// More data used to prep the test before running actions.
- reserved 5 to 9999;
+ reserved 6 to 9999;
repeated SnapshotManagerActionProto actions = 10000;
}
diff --git a/fs_mgr/libsnapshot/corpus/launch_device.txt b/fs_mgr/libsnapshot/corpus/launch_device.txt
new file mode 100644
index 0000000..55a7f2c
--- /dev/null
+++ b/fs_mgr/libsnapshot/corpus/launch_device.txt
@@ -0,0 +1,161 @@
+device_info_data {
+ slot_suffix_is_a: true
+ is_overlayfs_setup: false
+ allow_set_boot_control_merge_status: true
+ allow_set_slot_as_unbootable: true
+ is_recovery: false
+}
+manager_data {
+ is_local_image_manager: false
+}
+is_super_metadata_valid: true
+super_data {
+ partitions {
+ partition_name: "sys_a"
+ new_partition_info {
+ size: 3145728
+ }
+ }
+ partitions {
+ partition_name: "vnd_a"
+ new_partition_info {
+ size: 3145728
+ }
+ }
+ partitions {
+ partition_name: "prd_a"
+ new_partition_info {
+ size: 3145728
+ }
+ }
+ dynamic_partition_metadata {
+ groups {
+ name: "group_google_dp_a"
+ size: 15728640
+ partition_names: "sys_a"
+ partition_names: "vnd_a"
+ partition_names: "prd_a"
+ }
+ }
+}
+has_metadata_snapshots_dir: true
+actions {
+ begin_update {
+ }
+}
+actions {
+ create_update_snapshots {
+ partitions {
+ partition_name: "sys"
+ new_partition_info {
+ size: 3878912
+ }
+ operations {
+ type: ZERO,
+ dst_extents {
+ start_block: 0
+ num_blocks: 947
+ }
+ }
+ }
+ partitions {
+ partition_name: "vnd"
+ new_partition_info {
+ size: 3878912
+ }
+ operations {
+ type: ZERO,
+ dst_extents {
+ start_block: 0
+ num_blocks: 947
+ }
+ }
+ }
+ partitions {
+ partition_name: "prd"
+ new_partition_info {
+ size: 3878912
+ }
+ operations {
+ type: ZERO,
+ dst_extents {
+ start_block: 0
+ num_blocks: 947
+ }
+ }
+ }
+ dynamic_partition_metadata {
+ groups {
+ name: "group_google_dp"
+ size: 15728640
+ partition_names: "sys"
+ partition_names: "vnd"
+ partition_names: "prd"
+ }
+ }
+ }
+}
+actions {
+ map_update_snapshot {
+ use_correct_super: true
+ has_metadata_slot: true
+ metadata_slot: 1
+ partition_name: "sys_b"
+ force_writable: true
+ timeout_millis: 3000
+ }
+}
+actions {
+ map_update_snapshot {
+ use_correct_super: true
+ has_metadata_slot: true
+ metadata_slot: 1
+ partition_name: "vnd_b"
+ force_writable: true
+ timeout_millis: 3000
+ }
+}
+actions {
+ map_update_snapshot {
+ use_correct_super: true
+ has_metadata_slot: true
+ metadata_slot: 1
+ partition_name: "prd_b"
+ force_writable: true
+ timeout_millis: 3000
+ }
+}
+actions {
+ finished_snapshot_writes: false
+}
+actions {
+ unmap_update_snapshot: "sys_b"
+}
+actions {
+ unmap_update_snapshot: "vnd_b"
+}
+actions {
+ unmap_update_snapshot: "prd_b"
+}
+actions {
+ switch_slot {
+ }
+}
+actions {
+ need_snapshots_in_first_stage_mount {
+ }
+}
+actions {
+ create_logical_and_snapshot_partitions {
+ use_correct_super: true
+ timeout_millis: 5000
+ }
+}
+actions {
+ initiate_merge {
+ }
+}
+actions {
+ process_update_state {
+ }
+}
diff --git a/fs_mgr/libsnapshot/fuzz.sh b/fs_mgr/libsnapshot/fuzz.sh
index 2910129..0e57674 100755
--- a/fs_mgr/libsnapshot/fuzz.sh
+++ b/fs_mgr/libsnapshot/fuzz.sh
@@ -3,7 +3,8 @@
FUZZ_TARGET=libsnapshot_fuzzer
TARGET_ARCH=$(get_build_var TARGET_ARCH)
FUZZ_BINARY=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/${FUZZ_TARGET}
-DEVICE_CORPSE_DIR=/data/local/tmp/${FUZZ_TARGET}
+DEVICE_INIT_CORPUS_DIR=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/corpus
+DEVICE_GENERATED_CORPUS_DIR=/data/local/tmp/${FUZZ_TARGET}/corpus
DEVICE_GCOV_DIR=/data/local/tmp/${FUZZ_TARGET}/gcov
HOST_SCRATCH_DIR=/tmp/${FUZZ_TARGET}
GCOV_TOOL=${HOST_SCRATCH_DIR}/llvm-gcov
@@ -26,13 +27,14 @@
prepare_device() {
adb root && adb remount &&
- adb shell mkdir -p ${DEVICE_CORPSE_DIR} &&
+ adb shell mkdir -p ${DEVICE_GENERATED_CORPUS_DIR} &&
adb shell rm -rf ${DEVICE_GCOV_DIR} &&
adb shell mkdir -p ${DEVICE_GCOV_DIR}
}
push_binary() {
- adb push ${ANDROID_PRODUCT_OUT}/${FUZZ_BINARY} ${FUZZ_BINARY}
+ adb push ${ANDROID_PRODUCT_OUT}/${FUZZ_BINARY} ${FUZZ_BINARY} &&
+ adb push ${ANDROID_PRODUCT_OUT}/${DEVICE_INIT_CORPUS_DIR} $(dirname ${FUZZ_BINARY})
}
prepare_host() {
@@ -52,7 +54,7 @@
prepare_device &&
build_normal &&
push_binary &&
- adb shell ${FUZZ_BINARY} "$@" ${DEVICE_CORPSE_DIR}
+ adb shell ${FUZZ_BINARY} "$@" ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
}
run_snapshot_fuzz() {
@@ -62,7 +64,7 @@
adb shell GCOV_PREFIX=${DEVICE_GCOV_DIR} GCOV_PREFIX_STRIP=3 \
${FUZZ_BINARY} \
-runs=0 \
- ${DEVICE_CORPSE_DIR}
+ ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
}
show_fuzz_result() {
@@ -82,7 +84,7 @@
# run_snapshot_fuzz -runs=10000
run_snapshot_fuzz_all() {
- generate_corpse "$@" &&
+ generate_corpus "$@" &&
run_snapshot_fuzz &&
show_fuzz_result
}
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
index 421154d..1e90ace 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -54,6 +54,7 @@
namespace android::snapshot {
const SnapshotFuzzData* current_data = nullptr;
+const SnapshotTestModule* current_module = nullptr;
SnapshotFuzzEnv* GetSnapshotFuzzEnv();
@@ -155,6 +156,13 @@
(void)snapshot->MapUpdateSnapshot(params, &path);
}
+SNAPSHOT_FUZZ_FUNCTION(SwitchSlot) {
+ (void)snapshot;
+ CHECK(current_module != nullptr);
+ CHECK(current_module->device_info != nullptr);
+ current_module->device_info->SwitchSlot();
+}
+
// During global init, log all messages to stdio. This is only done once.
int AllowLoggingDuringGlobalInit() {
SetLogger(&StdioLogger);
@@ -208,8 +216,12 @@
auto env = GetSnapshotFuzzEnv();
env->CheckSoftReset();
- auto snapshot_manager = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
- CHECK(snapshot_manager);
+ auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
+ current_module = &test_module;
+ CHECK(test_module.snapshot);
- SnapshotManagerAction::ExecuteAll(snapshot_manager.get(), snapshot_fuzz_data.actions());
+ SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
+
+ current_module = nullptr;
+ current_data = nullptr;
}
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
index 8101d03..c9f1ab0 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -24,7 +24,11 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/properties.h>
+#include <fs_mgr.h>
#include <libsnapshot/auto_device.h>
#include <libsnapshot/snapshot.h>
#include <storage_literals/storage_literals.h>
@@ -41,21 +45,30 @@
using namespace std::chrono_literals;
using namespace std::string_literals;
+using android::base::Basename;
+using android::base::ReadFileToString;
+using android::base::SetProperty;
+using android::base::Split;
+using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::WriteStringToFile;
+using android::dm::DeviceMapper;
+using android::dm::DmTarget;
using android::dm::LoopControl;
using android::fiemap::IImageManager;
using android::fiemap::ImageManager;
using android::fs_mgr::BlockDeviceInfo;
+using android::fs_mgr::FstabEntry;
using android::fs_mgr::IPartitionOpener;
using chromeos_update_engine::DynamicPartitionMetadata;
-// This directory is exempted from pinning in ImageManager.
-static const char MNT_DIR[] = "/data/gsi/ota/test/";
+static const char MNT_DIR[] = "/mnt";
+static const char BLOCK_SYSFS[] = "/sys/block";
static const char FAKE_ROOT_NAME[] = "snapshot_fuzz";
static const auto SUPER_IMAGE_SIZE = 16_MiB;
+static const auto DATA_IMAGE_SIZE = 16_MiB;
static const auto FAKE_ROOT_SIZE = 64_MiB;
namespace android::snapshot {
@@ -98,6 +111,149 @@
return nftw(path.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) == 0;
}
+std::string GetLinearBaseDeviceString(const DeviceMapper::TargetInfo& target) {
+ if (target.spec.target_type != "linear"s) return {};
+ auto tokens = Split(target.data, " ");
+ CHECK_EQ(2, tokens.size());
+ return tokens[0];
+}
+
+std::vector<std::string> GetSnapshotBaseDeviceStrings(const DeviceMapper::TargetInfo& target) {
+ if (target.spec.target_type != "snapshot"s && target.spec.target_type != "snapshot-merge"s)
+ return {};
+ auto tokens = Split(target.data, " ");
+ CHECK_EQ(4, tokens.size());
+ return {tokens[0], tokens[1]};
+}
+
+bool ShouldDeleteLoopDevice(const std::string& node) {
+ std::string backing_file;
+ if (ReadFileToString(StringPrintf("%s/loop/backing_file", node.data()), &backing_file)) {
+ if (StartsWith(backing_file, std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::vector<DeviceMapper::TargetInfo> GetTableInfoIfExists(const std::string& dev_name) {
+ auto& dm = DeviceMapper::Instance();
+ std::vector<DeviceMapper::TargetInfo> table;
+ if (!dm.GetTableInfo(dev_name, &table)) {
+ PCHECK(errno == ENODEV);
+ return {};
+ }
+ return table;
+}
+
+std::set<std::string> GetAllBaseDeviceStrings(const std::string& child_dev) {
+ std::set<std::string> ret;
+ for (const auto& child_target : GetTableInfoIfExists(child_dev)) {
+ auto snapshot_bases = GetSnapshotBaseDeviceStrings(child_target);
+ ret.insert(snapshot_bases.begin(), snapshot_bases.end());
+
+ auto linear_base = GetLinearBaseDeviceString(child_target);
+ if (!linear_base.empty()) {
+ ret.insert(linear_base);
+ }
+ }
+ return ret;
+}
+
+using PropertyList = std::set<std::string>;
+void InsertProperty(const char* key, const char* /*name*/, void* cookie) {
+ reinterpret_cast<PropertyList*>(cookie)->insert(key);
+}
+
+void CheckUnsetGsidProps() {
+ PropertyList list;
+ property_list(&InsertProperty, reinterpret_cast<void*>(&list));
+ for (const auto& key : list) {
+ SetProperty(key, "");
+ }
+}
+
+// Attempt to delete all devices that is based on dev_name, including itself.
+void CheckDeleteDeviceMapperTree(const std::string& dev_name, bool known_allow_delete = false,
+ uint64_t depth = 100) {
+ CHECK(depth > 0) << "Reaching max depth when deleting " << dev_name
+ << ". There may be devices referencing itself. Check `dmctl list devices -v`.";
+
+ auto& dm = DeviceMapper::Instance();
+ auto table = GetTableInfoIfExists(dev_name);
+ if (table.empty()) {
+ PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+ return;
+ }
+
+ if (!known_allow_delete) {
+ for (const auto& target : table) {
+ auto base_device_string = GetLinearBaseDeviceString(target);
+ if (base_device_string.empty()) continue;
+ if (ShouldDeleteLoopDevice(
+ StringPrintf("/sys/dev/block/%s", base_device_string.data()))) {
+ known_allow_delete = true;
+ break;
+ }
+ }
+ }
+ if (!known_allow_delete) {
+ return;
+ }
+
+ std::string dev_string;
+ PCHECK(dm.GetDeviceString(dev_name, &dev_string));
+
+ std::vector<DeviceMapper::DmBlockDevice> devices;
+ PCHECK(dm.GetAvailableDevices(&devices));
+ for (const auto& child_dev : devices) {
+ auto child_bases = GetAllBaseDeviceStrings(child_dev.name());
+ if (child_bases.find(dev_string) != child_bases.end()) {
+ CheckDeleteDeviceMapperTree(child_dev.name(), true /* known_allow_delete */, depth - 1);
+ }
+ }
+
+ PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+}
+
+// Attempt to clean up residues from previous runs.
+void CheckCleanupDeviceMapperDevices() {
+ auto& dm = DeviceMapper::Instance();
+ std::vector<DeviceMapper::DmBlockDevice> devices;
+ PCHECK(dm.GetAvailableDevices(&devices));
+
+ for (const auto& dev : devices) {
+ CheckDeleteDeviceMapperTree(dev.name());
+ }
+}
+
+void CheckUmount(const std::string& path) {
+ PCHECK(TEMP_FAILURE_RETRY(umount(path.data()) == 0) || errno == ENOENT || errno == EINVAL)
+ << path;
+}
+
+void CheckDetachLoopDevices(const std::set<std::string>& exclude_names = {}) {
+ // ~SnapshotFuzzEnv automatically does the following.
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(BLOCK_SYSFS), closedir);
+ PCHECK(dir != nullptr) << BLOCK_SYSFS;
+ LoopControl loop_control;
+ dirent* dp;
+ while ((dp = readdir(dir.get())) != nullptr) {
+ if (exclude_names.find(dp->d_name) != exclude_names.end()) {
+ continue;
+ }
+ if (!ShouldDeleteLoopDevice(StringPrintf("%s/%s", BLOCK_SYSFS, dp->d_name).data())) {
+ continue;
+ }
+ PCHECK(loop_control.Detach(StringPrintf("/dev/block/%s", dp->d_name).data()));
+ }
+}
+
+void CheckUmountAll() {
+ CheckUmount(std::string(MNT_DIR) + "/snapshot_fuzz_data");
+ CheckUmount(std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME);
+}
+
class AutoDeleteDir : public AutoDevice {
public:
static std::unique_ptr<AutoDeleteDir> New(const std::string& path) {
@@ -108,9 +264,7 @@
}
~AutoDeleteDir() {
if (!HasDevice()) return;
- if (rmdir(name_.c_str()) == -1) {
- PLOG(ERROR) << "Cannot remove " << name_;
- }
+ PCHECK(rmdir(name_.c_str()) == 0 || errno == ENOENT) << name_;
}
private:
@@ -119,6 +273,15 @@
class AutoUnmount : public AutoDevice {
public:
+ ~AutoUnmount() {
+ if (!HasDevice()) return;
+ CheckUmount(name_);
+ }
+ AutoUnmount(const std::string& path) : AutoDevice(path) {}
+};
+
+class AutoUnmountTmpfs : public AutoUnmount {
+ public:
static std::unique_ptr<AutoUnmount> New(const std::string& path, uint64_t size) {
if (mount("tmpfs", path.c_str(), "tmpfs", 0,
(void*)StringPrintf("size=%" PRIu64, size).data()) == -1) {
@@ -127,30 +290,20 @@
}
return std::unique_ptr<AutoUnmount>(new AutoUnmount(path));
}
- ~AutoUnmount() {
- if (!HasDevice()) return;
- if (umount(name_.c_str()) == -1) {
- PLOG(ERROR) << "Cannot umount " << name_;
- }
- }
-
private:
- AutoUnmount(const std::string& path) : AutoDevice(path) {}
+ using AutoUnmount::AutoUnmount;
};
// A directory on tmpfs. Upon destruct, it is unmounted and deleted.
class AutoMemBasedDir : public AutoDevice {
public:
static std::unique_ptr<AutoMemBasedDir> New(const std::string& name, uint64_t size) {
- if (!Mkdir(MNT_DIR)) {
- return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
- }
auto ret = std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(name));
ret->auto_delete_mount_dir_ = AutoDeleteDir::New(ret->mount_path());
if (!ret->auto_delete_mount_dir_->HasDevice()) {
return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
}
- ret->auto_umount_mount_point_ = AutoUnmount::New(ret->mount_path(), size);
+ ret->auto_umount_mount_point_ = AutoUnmountTmpfs::New(ret->mount_path(), size);
if (!ret->auto_umount_mount_point_->HasDevice()) {
return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
}
@@ -191,14 +344,41 @@
};
SnapshotFuzzEnv::SnapshotFuzzEnv() {
+ CheckUnsetGsidProps();
+ CheckCleanupDeviceMapperDevices();
+ CheckDetachLoopDevices();
+ CheckUmountAll();
+
fake_root_ = AutoMemBasedDir::New(FAKE_ROOT_NAME, FAKE_ROOT_SIZE);
CHECK(fake_root_ != nullptr);
CHECK(fake_root_->HasDevice());
loop_control_ = std::make_unique<LoopControl>();
- mapped_super_ = CheckMapSuper(fake_root_->persist_path(), loop_control_.get(), &fake_super_);
+
+ fake_data_mount_point_ = MNT_DIR + "/snapshot_fuzz_data"s;
+ auto_delete_data_mount_point_ = AutoDeleteDir::New(fake_data_mount_point_);
+ CHECK(auto_delete_data_mount_point_ != nullptr);
+ CHECK(auto_delete_data_mount_point_->HasDevice());
+
+ const auto& fake_persist_path = fake_root_->persist_path();
+ mapped_super_ = CheckMapImage(fake_persist_path + "/super.img", SUPER_IMAGE_SIZE,
+ loop_control_.get(), &fake_super_);
+ mapped_data_ = CheckMapImage(fake_persist_path + "/data.img", DATA_IMAGE_SIZE,
+ loop_control_.get(), &fake_data_block_device_);
+ mounted_data_ = CheckMountFormatData(fake_data_block_device_, fake_data_mount_point_);
}
-SnapshotFuzzEnv::~SnapshotFuzzEnv() = default;
+SnapshotFuzzEnv::~SnapshotFuzzEnv() {
+ CheckUnsetGsidProps();
+ CheckCleanupDeviceMapperDevices();
+ mounted_data_ = nullptr;
+ auto_delete_data_mount_point_ = nullptr;
+ mapped_data_ = nullptr;
+ mapped_super_ = nullptr;
+ CheckDetachLoopDevices();
+ loop_control_ = nullptr;
+ fake_root_ = nullptr;
+ CheckUmountAll();
+}
void CheckZeroFill(const std::string& file, size_t size) {
std::string zeros(size, '\0');
@@ -208,15 +388,12 @@
void SnapshotFuzzEnv::CheckSoftReset() {
fake_root_->CheckSoftReset();
CheckZeroFill(super(), SUPER_IMAGE_SIZE);
+ CheckCleanupDeviceMapperDevices();
+ CheckDetachLoopDevices({Basename(fake_super_), Basename(fake_data_block_device_)});
}
std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
- const std::string& path) {
- auto images_dir = path + "/images";
- auto metadata_dir = images_dir + "/metadata";
- auto data_dir = images_dir + "/data";
-
- PCHECK(Mkdir(images_dir));
+ const std::string& metadata_dir, const std::string& data_dir) {
PCHECK(Mkdir(metadata_dir));
PCHECK(Mkdir(data_dir));
return ImageManager::Open(metadata_dir, data_dir);
@@ -236,36 +413,42 @@
public:
AutoDetachLoopDevice(LoopControl* control, const std::string& device)
: AutoDevice(device), control_(control) {}
- ~AutoDetachLoopDevice() { control_->Detach(name_); }
+ ~AutoDetachLoopDevice() { PCHECK(control_->Detach(name_)) << name_; }
private:
LoopControl* control_;
};
-std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapSuper(const std::string& fake_persist_path,
- LoopControl* control,
- std::string* fake_super) {
- auto super_img = fake_persist_path + "/super.img";
- CheckZeroFill(super_img, SUPER_IMAGE_SIZE);
- CheckCreateLoopDevice(control, super_img, 1s, fake_super);
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapImage(const std::string& img_path,
+ uint64_t size, LoopControl* control,
+ std::string* mapped_path) {
+ CheckZeroFill(img_path, size);
+ CheckCreateLoopDevice(control, img_path, 1s, mapped_path);
- return std::make_unique<AutoDetachLoopDevice>(control, *fake_super);
+ return std::make_unique<AutoDetachLoopDevice>(control, *mapped_path);
}
-std::unique_ptr<ISnapshotManager> SnapshotFuzzEnv::CheckCreateSnapshotManager(
- const SnapshotFuzzData& data) {
+SnapshotTestModule SnapshotFuzzEnv::CheckCreateSnapshotManager(const SnapshotFuzzData& data) {
+ SnapshotTestModule ret;
auto partition_opener = std::make_unique<TestPartitionOpener>(super());
+ ret.opener = partition_opener.get();
CheckWriteSuperMetadata(data, *partition_opener);
auto metadata_dir = fake_root_->tmp_path() + "/snapshot_metadata";
PCHECK(Mkdir(metadata_dir));
+ if (data.has_metadata_snapshots_dir()) {
+ PCHECK(Mkdir(metadata_dir + "/snapshots"));
+ }
- auto device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
- std::move(partition_opener), metadata_dir);
- auto snapshot = SnapshotManager::New(device_info /* takes ownership */);
- snapshot->images_ = CheckCreateFakeImageManager(fake_root_->tmp_path());
+ ret.device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
+ std::move(partition_opener), metadata_dir);
+ auto snapshot = SnapshotManager::New(ret.device_info /* takes ownership */);
+ snapshot->images_ =
+ CheckCreateFakeImageManager(fake_root_->tmp_path() + "/images_manager_metadata",
+ fake_data_mount_point_ + "/image_manager_data");
snapshot->has_local_image_manager_ = data.manager_data().is_local_image_manager();
+ ret.snapshot = std::move(snapshot);
- return snapshot;
+ return ret;
}
const std::string& SnapshotFuzzEnv::super() const {
@@ -311,4 +494,17 @@
CHECK(FlashPartitionTable(opener, super(), *metadata.get()));
}
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMountFormatData(const std::string& blk_device,
+ const std::string& mount_point) {
+ FstabEntry entry{
+ .blk_device = blk_device,
+ .length = static_cast<off64_t>(DATA_IMAGE_SIZE),
+ .fs_type = "ext4",
+ .mount_point = mount_point,
+ };
+ CHECK(0 == fs_mgr_do_format(entry, false /* crypt_footer */));
+ CHECK(0 == fs_mgr_do_mount_one(entry));
+ return std::make_unique<AutoUnmount>(mount_point);
+}
+
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 5533def..2405088 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -31,12 +31,19 @@
namespace android::snapshot {
class AutoMemBasedDir;
+class SnapshotFuzzDeviceInfo;
class DummyAutoDevice : public AutoDevice {
public:
DummyAutoDevice(bool mounted) : AutoDevice(mounted ? "dummy" : "") {}
};
+struct SnapshotTestModule {
+ std::unique_ptr<ISnapshotManager> snapshot;
+ SnapshotFuzzDeviceInfo* device_info = nullptr;
+ TestPartitionOpener* opener = nullptr;
+};
+
// Prepare test environment. This has a heavy overhead and should be done once.
class SnapshotFuzzEnv {
public:
@@ -54,7 +61,7 @@
// Create a snapshot manager for this test run.
// Client is responsible for maintaining the lifetime of |data| over the life time of
// ISnapshotManager.
- std::unique_ptr<ISnapshotManager> CheckCreateSnapshotManager(const SnapshotFuzzData& data);
+ SnapshotTestModule CheckCreateSnapshotManager(const SnapshotFuzzData& data);
// Return path to super partition.
const std::string& super() const;
@@ -62,14 +69,22 @@
private:
std::unique_ptr<AutoMemBasedDir> fake_root_;
std::unique_ptr<android::dm::LoopControl> loop_control_;
+ std::string fake_data_mount_point_;
+ std::unique_ptr<AutoDevice> auto_delete_data_mount_point_;
std::unique_ptr<AutoDevice> mapped_super_;
std::string fake_super_;
+ std::unique_ptr<AutoDevice> mapped_data_;
+ std::string fake_data_block_device_;
+ std::unique_ptr<AutoDevice> mounted_data_;
static std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(
- const std::string& fake_tmp_path);
- static std::unique_ptr<AutoDevice> CheckMapSuper(const std::string& fake_persist_path,
+ const std::string& metadata_dir, const std::string& data_dir);
+ static std::unique_ptr<AutoDevice> CheckMapImage(const std::string& fake_persist_path,
+ uint64_t size,
android::dm::LoopControl* control,
- std::string* fake_super);
+ std::string* mapped_path);
+ static std::unique_ptr<AutoDevice> CheckMountFormatData(const std::string& blk_device,
+ const std::string& mount_point);
void CheckWriteSuperMetadata(const SnapshotFuzzData& proto,
const android::fs_mgr::IPartitionOpener& opener);
@@ -97,10 +112,8 @@
}
// Following APIs are fuzzed.
- std::string GetSlotSuffix() const override { return data_->slot_suffix_is_a() ? "_a" : "_b"; }
- std::string GetOtherSlotSuffix() const override {
- return data_->slot_suffix_is_a() ? "_b" : "_a";
- }
+ std::string GetSlotSuffix() const override { return CurrentSlotIsA() ? "_a" : "_b"; }
+ std::string GetOtherSlotSuffix() const override { return CurrentSlotIsA() ? "_b" : "_a"; }
bool IsOverlayfsSetup() const override { return data_->is_overlayfs_setup(); }
bool SetBootControlMergeStatus(android::hardware::boot::V1_1::MergeStatus) override {
return data_->allow_set_boot_control_merge_status();
@@ -110,10 +123,15 @@
}
bool IsRecovery() const override { return data_->is_recovery(); }
+ void SwitchSlot() { switched_slot_ = !switched_slot_; }
+
private:
const FuzzDeviceInfoData* data_;
std::unique_ptr<TestPartitionOpener> partition_opener_;
std::string metadata_dir_;
+ bool switched_slot_ = false;
+
+ bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; }
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
index be5e1fe..8a11eaa 100644
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -45,7 +45,12 @@
}
message InstallOperation {
- enum Type { SOURCE_COPY = 4; }
+ enum Type {
+ SOURCE_COPY = 4;
+ // Not used by libsnapshot. Declared here so that the fuzzer has an
+ // alternative value to use for |type|.
+ ZERO = 6;
+ }
required Type type = 1;
repeated Extent src_extents = 4;
repeated Extent dst_extents = 6;
diff --git a/init/README.md b/init/README.md
index 726c0cc..b70366b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -644,7 +644,8 @@
`wait <path> [ <timeout> ]`
> Poll for the existence of the given file and return when found,
or the timeout has been reached. If timeout is not specified it
- currently defaults to five seconds.
+ currently defaults to five seconds. The timeout value can be
+ fractional seconds, specified in floating point notation.
`wait_for_prop <name> <value>`
> Wait for system property _name_ to be _value_. Properties are expanded
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..149a766 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -49,6 +49,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -1065,11 +1066,12 @@
static Result<void> do_wait(const BuiltinArguments& args) {
auto timeout = kCommandRetryTimeout;
if (args.size() == 3) {
- int timeout_int;
- if (!android::base::ParseInt(args[2], &timeout_int)) {
+ double timeout_double;
+ if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
return Error() << "failed to parse timeout";
}
- timeout = std::chrono::seconds(timeout_int);
+ timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::duration<double>(timeout_double));
}
if (wait_for_file(args[1].c_str(), timeout) != 0) {
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index d62ecb0..d1a84f3 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -25,6 +25,7 @@
#include <sys/time.h>
#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@@ -205,8 +206,8 @@
Result<void> check_wait(const BuiltinArguments& args) {
if (args.size() == 3 && !args[2].empty()) {
- int timeout_int;
- if (!android::base::ParseInt(args[2], &timeout_int)) {
+ double timeout_double;
+ if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
return Error() << "failed to parse timeout";
}
}
diff --git a/init/init.cpp b/init/init.cpp
index 3f8f628..631db8e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -537,7 +537,9 @@
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
-static void set_usb_controller() {
+static void SetUsbController() {
+ static auto controller_set = false;
+ if (controller_set) return;
std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
if (!dir) return;
@@ -546,6 +548,7 @@
if (dp->d_name[0] == '.') continue;
SetProperty("sys.usb.controller", dp->d_name);
+ controller_set = true;
break;
}
}
@@ -800,7 +803,7 @@
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
MountHandler mount_handler(&epoll);
- set_usb_controller();
+ SetUsbController();
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
Action::set_function_map(&function_map);
@@ -910,6 +913,7 @@
}
if (!IsShuttingDown()) {
HandleControlMessages();
+ SetUsbController();
}
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 842b2e5..82f5b8c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -877,28 +877,32 @@
}
void PropertyLoadBootDefaults() {
- // TODO(b/117892318): merge prop.default and build.prop files into one
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
// property files, regardless of if they are "ro." properties or not.
std::map<std::string, std::string> properties;
- if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
- // Try recovery path
- if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
- // Try legacy path
- load_properties_from_file("/default.prop", nullptr, &properties);
- }
+
+ if (IsRecoveryMode()) {
+ load_properties_from_file("/prop.default", nullptr, &properties);
}
+
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
- load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+
+ // TODO(b/117892318): uncomment the following condition when vendor.imgs for
+ // aosp_* targets are all updated.
+// if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
+ load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+// }
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
+
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
} else {
load_properties_from_file("/odm/default.prop", nullptr, &properties);
load_properties_from_file("/odm/build.prop", nullptr, &properties);
}
+
load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 96a5b55..565e7d4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -61,8 +61,8 @@
TEST(util, ReadFileSymbolicLink) {
errno = 0;
- // lrw------- 1 root root 23 2008-12-31 19:00 default.prop -> system/etc/prop.default
- auto file_contents = ReadFile("/default.prop");
+ // lrwxr-xr-x 1 root shell 6 2009-01-01 09:00 /system/bin/ps -> toybox
+ auto file_contents = ReadFile("/system/bin/ps");
EXPECT_EQ(ELOOP, errno);
ASSERT_FALSE(file_contents.ok());
EXPECT_EQ("open() failed: Too many symbolic links encountered",
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index dc989a0..c4cfa6f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -48,6 +48,7 @@
"//apex_available:platform",
"//apex_available:anyapex",
],
+ min_sdk_version: "apex_inherit",
}
cc_defaults {
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 0c9a2b8..15b0d89 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -51,6 +51,12 @@
enabled: false,
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Tests
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f3d3f27..3c44534 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -146,6 +146,12 @@
exclude_shared_libs: ["libdexfile_support"],
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Static library without DEX support to avoid dependencies on the ART APEX.
@@ -411,6 +417,7 @@
srcs: [
"benchmarks/unwind_benchmarks.cpp",
"benchmarks/ElfBenchmark.cpp",
+ "benchmarks/MapsBenchmark.cpp",
"benchmarks/SymbolBenchmark.cpp",
"benchmarks/Utils.cpp",
],
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index c108a2a..a46bd7a 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -23,7 +23,9 @@
#include <benchmark/benchmark.h>
#include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
#include "Utils.h"
@@ -75,3 +77,66 @@
BenchmarkElfCreate(state, GetCompressedElfFile());
}
BENCHMARK(BM_elf_create_compressed);
+
+static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
+ unwindstack::MapInfo** build_id_map_info) {
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ return;
+ }
+
+ // Find the libc.so share library and use that for benchmark purposes.
+ *build_id_map_info = nullptr;
+ for (auto& map_info : maps) {
+ if (map_info->offset == 0 && map_info->GetBuildID() != "") {
+ *build_id_map_info = map_info.get();
+ break;
+ }
+ }
+
+ if (*build_id_map_info == nullptr) {
+ state.SkipWithError("Failed to find a map with a BuildID.");
+ }
+}
+
+static void BM_elf_get_build_id_from_object(benchmark::State& state) {
+ unwindstack::LocalMaps maps;
+ unwindstack::MapInfo* build_id_map_info;
+ InitializeBuildId(state, maps, &build_id_map_info);
+
+ unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
+ unwindstack::Regs::CurrentArch());
+ if (!elf->valid()) {
+ state.SkipWithError("Cannot get valid elf from map.");
+ }
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ uintptr_t id = build_id_map_info->build_id;
+ if (id != 0) {
+ delete reinterpret_cast<std::string*>(id);
+ build_id_map_info->build_id = 0;
+ }
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+ }
+}
+BENCHMARK(BM_elf_get_build_id_from_object);
+
+static void BM_elf_get_build_id_from_file(benchmark::State& state) {
+ unwindstack::LocalMaps maps;
+ unwindstack::MapInfo* build_id_map_info;
+ InitializeBuildId(state, maps, &build_id_map_info);
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ uintptr_t id = build_id_map_info->build_id;
+ if (id != 0) {
+ delete reinterpret_cast<std::string*>(id);
+ build_id_map_info->build_id = 0;
+ }
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+ }
+}
+BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
new file mode 100644
index 0000000..be106a3
--- /dev/null
+++ b/libunwindstack/benchmarks/MapsBenchmark.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 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 <err.h>
+#include <stdint.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+
+class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
+ public:
+ BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
+ virtual ~BenchmarkLocalUpdatableMaps() = default;
+
+ const std::string GetMapsFile() const override { return maps_file_; }
+
+ void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+
+ private:
+ std::string maps_file_;
+};
+
+constexpr size_t kNumMaps = 10000;
+
+static void CreateInitialMap(const char* filename) {
+ std::string maps;
+ for (size_t i = 0; i < kNumMaps; i += 2) {
+ maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
+ (i + 1) * 1000, i);
+ }
+ if (!android::base::WriteStringToFile(maps, filename)) {
+ errx(1, "WriteStringToFile failed");
+ }
+}
+
+static void CreateReparseMap(const char* filename) {
+ std::string maps;
+ for (size_t i = 0; i < kNumMaps; i++) {
+ maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 2000,
+ (i + 1) * 2000, 2 * i);
+ }
+ if (!android::base::WriteStringToFile(maps, filename)) {
+ errx(1, "WriteStringToFile failed");
+ }
+}
+
+void BM_local_updatable_maps_reparse(benchmark::State& state) {
+ TemporaryFile initial_map;
+ CreateInitialMap(initial_map.path);
+
+ TemporaryFile reparse_map;
+ CreateReparseMap(reparse_map.path);
+
+ for (auto _ : state) {
+ BenchmarkLocalUpdatableMaps maps;
+ maps.BenchmarkSetMapsFile(initial_map.path);
+ if (!maps.Reparse()) {
+ errx(1, "Internal Error: reparse of initial maps filed.");
+ }
+ if (maps.Total() != (kNumMaps / 2)) {
+ errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+ kNumMaps / 2);
+ }
+ maps.BenchmarkSetMapsFile(reparse_map.path);
+ if (!maps.Reparse()) {
+ errx(1, "Internal Error: reparse of second set of maps filed.");
+ }
+ if (maps.Total() != kNumMaps) {
+ errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+ kNumMaps);
+ }
+ }
+}
+BENCHMARK(BM_local_updatable_maps_reparse);
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
index de9137a..0bee6ef 100644
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -22,7 +22,6 @@
#include <android-base/strings.h>
-#include <unwindstack/Elf.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -83,63 +82,4 @@
}
BENCHMARK(BM_cached_unwind);
-static void Initialize(benchmark::State& state, unwindstack::Maps& maps,
- unwindstack::MapInfo** build_id_map_info) {
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- return;
- }
-
- // Find the libc.so share library and use that for benchmark purposes.
- *build_id_map_info = nullptr;
- for (auto& map_info : maps) {
- if (map_info->offset == 0 && map_info->GetBuildID() != "") {
- *build_id_map_info = map_info.get();
- break;
- }
- }
-
- if (*build_id_map_info == nullptr) {
- state.SkipWithError("Failed to find a map with a BuildID.");
- }
-}
-
-static void BM_get_build_id_from_elf(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- Initialize(state, maps, &build_id_map_info);
-
- unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
- unwindstack::Regs::CurrentArch());
- if (!elf->valid()) {
- state.SkipWithError("Cannot get valid elf from map.");
- }
-
- for (auto _ : state) {
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_get_build_id_from_elf);
-
-static void BM_get_build_id_from_file(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- Initialize(state, maps, &build_id_map_info);
-
- for (auto _ : state) {
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_get_build_id_from_file);
-
BENCHMARK_MAIN();
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 786e7b3..c5a968a 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -111,6 +111,12 @@
enabled: true,
},
},
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.art.debug",
+ "com.android.art.release",
+ ],
}
// Tests.
diff --git a/logd/Android.bp b/logd/Android.bp
index ee86566..d203062 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -32,10 +32,10 @@
name: "liblogd",
srcs: [
- "LogCommand.cpp",
"ChattyLogBuffer.cpp",
"CommandListener.cpp",
"LogListener.cpp",
+ "LogPermissions.cpp",
"LogReader.cpp",
"LogReaderList.cpp",
"LogReaderThread.cpp",
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
index fa5bcee..c6c9a7c 100644
--- a/logd/ChattyLogBuffer.cpp
+++ b/logd/ChattyLogBuffer.cpp
@@ -31,11 +31,8 @@
#include <unordered_map>
#include <utility>
-#include <cutils/properties.h>
#include <private/android_logger.h>
-#include "LogKlog.h"
-#include "LogReader.h"
#include "LogUtils.h"
#ifndef __predict_false
@@ -494,8 +491,8 @@
if (stats_->Sizes(id) > (2 * log_buffer_size(id))) { // +100%
// A misbehaving or slow reader has its connection
// dropped if we hit too much memory pressure.
- android::prdebug("Kicking blocked reader, pid %d, from ChattyLogBuffer::kickMe()\n",
- me->client()->getPid());
+ android::prdebug("Kicking blocked reader, %s, from ChattyLogBuffer::kickMe()\n",
+ me->name().c_str());
me->release_Locked();
} else if (me->deadline().time_since_epoch().count() != 0) {
// Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
@@ -503,8 +500,8 @@
} else {
// tell slow reader to skip entries to catch up
android::prdebug(
- "Skipping %lu entries from slow reader, pid %d, from ChattyLogBuffer::kickMe()\n",
- pruneRows, me->client()->getPid());
+ "Skipping %lu entries from slow reader, %s, from ChattyLogBuffer::kickMe()\n",
+ pruneRows, me->name().c_str());
me->triggerSkip_Locked(id, pruneRows);
}
}
@@ -872,8 +869,8 @@
for (const auto& reader_thread : reader_list_->reader_threads()) {
if (reader_thread->IsWatching(id)) {
android::prdebug(
- "Kicking blocked reader, pid %d, from ChattyLogBuffer::clear()\n",
- reader_thread->client()->getPid());
+ "Kicking blocked reader, %s, from ChattyLogBuffer::clear()\n",
+ reader_thread->name().c_str());
reader_thread->release_Locked();
}
}
@@ -911,10 +908,10 @@
}
uint64_t ChattyLogBuffer::FlushTo(
- SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged, bool security,
+ LogWriter* writer, uint64_t start, pid_t* lastTid,
const std::function<FlushToResult(const LogBufferElement* element)>& filter) {
LogBufferElementCollection::iterator it;
- uid_t uid = reader->getUid();
+ uid_t uid = writer->uid();
rdlock();
@@ -940,11 +937,11 @@
for (; it != mLogElements.end(); ++it) {
LogBufferElement* element = *it;
- if (!privileged && (element->getUid() != uid)) {
+ if (!writer->privileged() && element->getUid() != uid) {
continue;
}
- if (!security && (element->getLogId() == LOG_ID_SECURITY)) {
+ if (!writer->can_read_security_logs() && element->getLogId() == LOG_ID_SECURITY) {
continue;
}
@@ -973,11 +970,10 @@
unlock();
+ curr = element->getSequence();
// range locking in LastLogTimes looks after us
- curr = element->flushTo(reader, stats_, sameTid);
-
- if (curr == element->FLUSH_ERROR) {
- return curr;
+ if (!element->FlushTo(writer, stats_, sameTid)) {
+ return FLUSH_ERROR;
}
rdlock();
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
index d9cd24f..29a421d 100644
--- a/logd/ChattyLogBuffer.h
+++ b/logd/ChattyLogBuffer.h
@@ -28,15 +28,15 @@
#include "LogBuffer.h"
#include "LogBufferElement.h"
+#include "LogReaderList.h"
+#include "LogReaderThread.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogWhiteBlackList.h"
+#include "LogWriter.h"
typedef std::list<LogBufferElement*> LogBufferElementCollection;
-class LogReaderList;
-class LogReaderThread;
-
class ChattyLogBuffer : public LogBuffer {
LogBufferElementCollection mLogElements;
pthread_rwlock_t mLogElementsLock;
@@ -63,7 +63,7 @@
int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
uint16_t len) override;
uint64_t FlushTo(
- SocketClient* writer, uint64_t start, pid_t* lastTid, bool privileged, bool security,
+ LogWriter* writer, uint64_t start, pid_t* lastTid,
const std::function<FlushToResult(const LogBufferElement* element)>& filter) override;
bool Clear(log_id_t id, uid_t uid = AID_ROOT) override;
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 0ff19f8..c6ab22d 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -37,7 +37,7 @@
#include <private/android_filesystem_config.h>
#include <sysutils/SocketClient.h>
-#include "LogUtils.h"
+#include "LogPermissions.h"
CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune,
LogStatistics* stats)
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index fd934f7..a55a393 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -16,12 +16,11 @@
#pragma once
+#include <sysutils/FrameworkCommand.h>
#include <sysutils/FrameworkListener.h>
#include "LogBuffer.h"
-#include "LogCommand.h"
#include "LogListener.h"
-#include "LogReader.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogWhiteBlackList.h"
@@ -39,20 +38,20 @@
PruneList* prune_;
LogStatistics* stats_;
-#define LogCmd(name, command_string) \
- class name##Cmd : public LogCommand { \
- public: \
- explicit name##Cmd(CommandListener* parent) \
- : LogCommand(#command_string), parent_(parent) {} \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient* c, int argc, char** argv); \
- \
- private: \
- LogBuffer* buf() const { return parent_->buf_; } \
- LogTags* tags() const { return parent_->tags_; } \
- PruneList* prune() const { return parent_->prune_; } \
- LogStatistics* stats() const { return parent_->stats_; } \
- CommandListener* parent_; \
+#define LogCmd(name, command_string) \
+ class name##Cmd : public FrameworkCommand { \
+ public: \
+ explicit name##Cmd(CommandListener* parent) \
+ : FrameworkCommand(#command_string), parent_(parent) {} \
+ virtual ~name##Cmd() {} \
+ int runCommand(SocketClient* c, int argc, char** argv); \
+ \
+ private: \
+ LogBuffer* buf() const { return parent_->buf_; } \
+ LogTags* tags() const { return parent_->tags_; } \
+ PruneList* prune() const { return parent_->prune_; } \
+ LogStatistics* stats() const { return parent_->stats_; } \
+ CommandListener* parent_; \
}
LogCmd(Clear, clear);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 887e5f0..6274051 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -25,6 +25,8 @@
#include "LogBufferElement.h"
+class LogWriter;
+
enum class FlushToResult {
kSkip,
kStop,
@@ -42,10 +44,10 @@
// lastTid is an optional context to help detect if the last previous
// valid message was from the same source so we can differentiate chatty
// filter types (identical or expired)
+ static const uint64_t FLUSH_ERROR = 0;
virtual uint64_t FlushTo(
- SocketClient* writer, uint64_t start,
+ LogWriter* writer, uint64_t start,
pid_t* last_tid, // nullable
- bool privileged, bool security,
const std::function<FlushToResult(const LogBufferElement* element)>& filter) = 0;
virtual bool Clear(log_id_t id, uid_t uid) = 0;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 32f641b..8499715 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -27,12 +27,9 @@
#include <log/log_read.h>
#include <private/android_logger.h>
-#include "LogCommand.h"
-#include "LogReader.h"
#include "LogStatistics.h"
#include "LogUtils.h"
-const uint64_t LogBufferElement::FLUSH_ERROR(0);
atomic_int_fast64_t LogBufferElement::sequence(1);
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
@@ -243,7 +240,7 @@
return retval;
}
-uint64_t LogBufferElement::flushTo(SocketClient* reader, LogStatistics* stats, bool lastSame) {
+bool LogBufferElement::FlushTo(LogWriter* writer, LogStatistics* stats, bool lastSame) {
struct logger_entry entry = {};
entry.hdr_size = sizeof(struct logger_entry);
@@ -254,23 +251,18 @@
entry.sec = mRealTime.tv_sec;
entry.nsec = mRealTime.tv_nsec;
- struct iovec iovec[2];
- iovec[0].iov_base = &entry;
- iovec[0].iov_len = entry.hdr_size;
-
char* buffer = nullptr;
-
+ const char* msg;
if (mDropped) {
entry.len = populateDroppedMessage(buffer, stats, lastSame);
- if (!entry.len) return mSequence;
- iovec[1].iov_base = buffer;
+ if (!entry.len) return true;
+ msg = buffer;
} else {
+ msg = mMsg;
entry.len = mMsgLen;
- iovec[1].iov_base = mMsg;
}
- iovec[1].iov_len = entry.len;
- uint64_t retval = reader->sendDatav(iovec, 1 + (entry.len != 0)) ? FLUSH_ERROR : mSequence;
+ bool retval = writer->Write(entry, msg);
if (buffer) free(buffer);
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 3d0b65e..2f2d70d 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -22,7 +22,8 @@
#include <sys/types.h>
#include <log/log.h>
-#include <sysutils/SocketClient.h>
+
+#include "LogWriter.h"
class LogStatistics;
@@ -94,6 +95,5 @@
return mRealTime;
}
- static const uint64_t FLUSH_ERROR;
- uint64_t flushTo(SocketClient* writer, LogStatistics* parent, bool lastSame);
+ bool FlushTo(LogWriter* writer, LogStatistics* parent, bool lastSame);
};
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 77b24bc..56e0452 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -19,10 +19,9 @@
#include <private/android_logger.h>
#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
#include "LogStatistics.h"
-class LogBuffer;
-
class LogKlog : public SocketListener {
LogBuffer* logbuf;
const log_time signature;
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index d2e2efa..a6ab50b 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -30,7 +30,7 @@
#include "LogBuffer.h"
#include "LogListener.h"
-#include "LogUtils.h"
+#include "LogPermissions.h"
LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
diff --git a/logd/LogListener.h b/logd/LogListener.h
index d468df8..c114e38 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -17,7 +17,6 @@
#pragma once
#include "LogBuffer.h"
-#include "LogReader.h"
class LogListener {
public:
diff --git a/logd/LogCommand.cpp b/logd/LogPermissions.cpp
similarity index 97%
rename from logd/LogCommand.cpp
rename to logd/LogPermissions.cpp
index 8bff9da..8f02d5a 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogPermissions.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogPermissions.h"
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -21,12 +23,6 @@
#include <private/android_filesystem_config.h>
-#include "LogCommand.h"
-#include "LogUtils.h"
-
-LogCommand::LogCommand(const char* cmd) : FrameworkCommand(cmd) {
-}
-
// gets a list of supplementary group IDs associated with
// the socket peer. This is implemented by opening
// /proc/PID/status and look for the "Group:" line.
diff --git a/logd/LogCommand.h b/logd/LogPermissions.h
similarity index 74%
rename from logd/LogCommand.h
rename to logd/LogPermissions.h
index e10ffa0..3130db5 100644
--- a/logd/LogCommand.h
+++ b/logd/LogPermissions.h
@@ -14,17 +14,11 @@
* limitations under the License.
*/
-#ifndef _LOGD_COMMAND_H
-#define _LOGD_COMMAND_H
+#pragma once
-#include <sysutils/FrameworkCommand.h>
+#include <sys/types.h>
+
#include <sysutils/SocketClient.h>
-class LogCommand : public FrameworkCommand {
- public:
- explicit LogCommand(const char* cmd);
- virtual ~LogCommand() {
- }
-};
-
-#endif
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
+bool clientHasLogCredentials(SocketClient* cli);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 6f91372..89562a4 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -23,19 +23,58 @@
#include <chrono>
+#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include "LogBuffer.h"
#include "LogBufferElement.h"
+#include "LogPermissions.h"
#include "LogReader.h"
#include "LogUtils.h"
+#include "LogWriter.h"
static bool CanReadSecurityLogs(SocketClient* client) {
return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
}
+static std::string SocketClientToName(SocketClient* client) {
+ return android::base::StringPrintf("pid %d, fd %d", client->getPid(), client->getSocket());
+}
+
+class SocketLogWriter : public LogWriter {
+ public:
+ SocketLogWriter(LogReader* reader, SocketClient* client, bool privileged,
+ bool can_read_security_logs)
+ : LogWriter(client->getUid(), privileged, can_read_security_logs),
+ reader_(reader),
+ client_(client) {}
+
+ bool Write(const logger_entry& entry, const char* msg) override {
+ struct iovec iovec[2];
+ iovec[0].iov_base = const_cast<logger_entry*>(&entry);
+ iovec[0].iov_len = entry.hdr_size;
+ iovec[1].iov_base = const_cast<char*>(msg);
+ iovec[1].iov_len = entry.len;
+
+ return client_->sendDatav(iovec, 1 + (entry.len != 0)) == 0;
+ }
+
+ void Release() override {
+ reader_->release(client_);
+ client_->decRef();
+ }
+
+ void Shutdown() override { shutdown(client_->getSocket(), SHUT_RDWR); }
+
+ std::string name() const override { return SocketClientToName(client_); }
+
+ private:
+ LogReader* reader_;
+ SocketClient* client_;
+};
+
LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
: SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
@@ -51,21 +90,14 @@
int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
if (len <= 0) {
- doSocketDelete(cli);
+ DoSocketDelete(cli);
return false;
}
buffer[len] = '\0';
- // Clients are only allowed to send one command, disconnect them if they
- // send another.
- {
- auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
- for (const auto& entry : reader_list_->reader_threads()) {
- if (entry->client() == cli) {
- entry->release_Locked();
- return false;
- }
- }
+ // Clients are only allowed to send one command, disconnect them if they send another.
+ if (DoSocketDelete(cli)) {
+ return false;
}
unsigned long tail = 0;
@@ -131,6 +163,9 @@
bool privileged = clientHasLogCredentials(cli);
bool can_read_security = CanReadSecurityLogs(cli);
+ std::unique_ptr<LogWriter> socket_log_writer(
+ new SocketLogWriter(this, cli, privileged, can_read_security));
+
uint64_t sequence = 1;
// Convert realtime to sequence number
if (start != log_time::EPOCH) {
@@ -159,11 +194,10 @@
return FlushToResult::kSkip;
};
- log_buffer_->FlushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start);
+ log_buffer_->FlushTo(socket_log_writer.get(), sequence, nullptr, log_find_start);
if (!start_time_set) {
if (nonBlock) {
- doSocketDelete(cli);
return false;
}
sequence = LogBufferElement::getCurrentSequence();
@@ -181,13 +215,9 @@
}
auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
- auto entry = std::make_unique<LogReaderThread>(*this, *reader_list_, cli, nonBlock, tail,
- logMask, pid, start, sequence, deadline,
- privileged, can_read_security);
- if (!entry->startReader_Locked()) {
- return false;
- }
-
+ auto entry = std::make_unique<LogReaderThread>(log_buffer_, reader_list_,
+ std::move(socket_log_writer), nonBlock, tail,
+ logMask, pid, start, sequence, deadline);
// release client and entry reference counts once done
cli->incRef();
reader_list_->reader_threads().emplace_front(std::move(entry));
@@ -200,17 +230,16 @@
return true;
}
-void LogReader::doSocketDelete(SocketClient* cli) {
+bool LogReader::DoSocketDelete(SocketClient* cli) {
+ auto cli_name = SocketClientToName(cli);
auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
- auto it = reader_list_->reader_threads().begin();
- while (it != reader_list_->reader_threads().end()) {
- LogReaderThread* entry = it->get();
- if (entry->client() == cli) {
- entry->release_Locked();
- break;
+ for (const auto& reader : reader_list_->reader_threads()) {
+ if (reader->name() == cli_name) {
+ reader->release_Locked();
+ return true;
}
- it++;
}
+ return false;
}
int LogReader::getLogSocket() {
diff --git a/logd/LogReader.h b/logd/LogReader.h
index 7df3f6b..b85a584 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -18,26 +18,23 @@
#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
#include "LogReaderList.h"
#include "LogReaderThread.h"
#define LOGD_SNDTIMEO 32
-class LogBuffer;
-
class LogReader : public SocketListener {
public:
explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
- LogBuffer* log_buffer() const { return log_buffer_; }
-
protected:
virtual bool onDataAvailable(SocketClient* cli);
private:
static int getLogSocket();
- void doSocketDelete(SocketClient* cli);
+ bool DoSocketDelete(SocketClient* cli);
LogBuffer* log_buffer_;
LogReaderList* reader_list_;
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
index e58e3eb..b2001b5 100644
--- a/logd/LogReaderThread.cpp
+++ b/logd/LogReaderThread.cpp
@@ -23,50 +23,40 @@
#include <thread>
#include "LogBuffer.h"
-#include "LogReader.h"
+#include "LogReaderList.h"
using namespace std::placeholders;
-LogReaderThread::LogReaderThread(LogReader& reader, LogReaderList& reader_list,
- SocketClient* client, bool non_block, unsigned long tail,
- unsigned int log_mask, pid_t pid, log_time start_time,
- uint64_t start, std::chrono::steady_clock::time_point deadline,
- bool privileged, bool can_read_security_logs)
- : leading_dropped_(false),
- reader_(reader),
+LogReaderThread::LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
+ std::unique_ptr<LogWriter> writer, bool non_block,
+ unsigned long tail, unsigned int log_mask, pid_t pid,
+ log_time start_time, uint64_t start,
+ std::chrono::steady_clock::time_point deadline)
+ : log_buffer_(log_buffer),
reader_list_(reader_list),
+ writer_(std::move(writer)),
+ leading_dropped_(false),
log_mask_(log_mask),
pid_(pid),
tail_(tail),
count_(0),
index_(0),
- client_(client),
start_time_(start_time),
start_(start),
deadline_(deadline),
- non_block_(non_block),
- privileged_(privileged),
- can_read_security_logs_(can_read_security_logs) {
+ non_block_(non_block) {
memset(last_tid_, 0, sizeof(last_tid_));
cleanSkip_Locked();
-}
-
-bool LogReaderThread::startReader_Locked() {
auto thread = std::thread{&LogReaderThread::ThreadFunction, this};
thread.detach();
- return true;
}
void LogReaderThread::ThreadFunction() {
prctl(PR_SET_NAME, "logd.reader.per");
- SocketClient* client = client_;
-
- LogBuffer& logbuf = *reader_.log_buffer();
-
leading_dropped_ = true;
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+ auto lock = std::unique_lock{reader_list_->reader_threads_lock()};
uint64_t start = start_;
@@ -84,14 +74,14 @@
lock.unlock();
if (tail_) {
- logbuf.FlushTo(client, start, nullptr, privileged_, can_read_security_logs_,
- std::bind(&LogReaderThread::FilterFirstPass, this, _1));
+ log_buffer_->FlushTo(writer_.get(), start, nullptr,
+ std::bind(&LogReaderThread::FilterFirstPass, this, _1));
leading_dropped_ =
true; // TODO: Likely a bug, if leading_dropped_ was not true before calling
// flushTo(), then it should not be reset to true after.
}
- start = logbuf.FlushTo(client, start, last_tid_, privileged_, can_read_security_logs_,
- std::bind(&LogReaderThread::FilterSecondPass, this, _1));
+ start = log_buffer_->FlushTo(writer_.get(), start, last_tid_,
+ std::bind(&LogReaderThread::FilterSecondPass, this, _1));
// We only ignore entries before the original start time for the first flushTo(), if we
// get entries after this first flush before the original start time, then the client
@@ -104,7 +94,7 @@
lock.lock();
- if (start == LogBufferElement::FLUSH_ERROR) {
+ if (start == LogBuffer::FLUSH_ERROR) {
break;
}
@@ -121,10 +111,9 @@
}
}
- reader_.release(client);
- client->decRef();
+ writer_->Release();
- auto& log_reader_threads = reader_list_.reader_threads();
+ auto& log_reader_threads = reader_list_->reader_threads();
auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
[this](const auto& other) { return other.get() == this; });
@@ -135,7 +124,7 @@
// A first pass to count the number of elements
FlushToResult LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
- auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
if (leading_dropped_) {
if (element->getDropped()) {
@@ -158,7 +147,7 @@
// A second pass to send the selected elements
FlushToResult LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
- auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
start_ = element->getSequence();
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
index f828b6e..e48a3ca 100644
--- a/logd/LogReaderThread.h
+++ b/logd/LogReaderThread.h
@@ -30,21 +30,17 @@
#include <sysutils/SocketClient.h>
#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogWriter.h"
-class LogReader;
-class LogBufferElement;
class LogReaderList;
class LogReaderThread {
public:
- LogReaderThread(LogReader& reader, LogReaderList& reader_list, SocketClient* client,
- bool non_block, unsigned long tail, unsigned int log_mask, pid_t pid,
- log_time start_time, uint64_t sequence,
- std::chrono::steady_clock::time_point deadline, bool privileged,
- bool can_read_security_logs);
-
- bool startReader_Locked();
-
+ LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
+ std::unique_ptr<LogWriter> writer, bool non_block, unsigned long tail,
+ unsigned int log_mask, pid_t pid, log_time start_time, uint64_t sequence,
+ std::chrono::steady_clock::time_point deadline);
void triggerReader_Locked() { thread_triggered_condition_.notify_all(); }
void triggerSkip_Locked(log_id_t id, unsigned int skip) { skip_ahead_[id] = skip; }
@@ -52,7 +48,7 @@
void release_Locked() {
// gracefully shut down the socket.
- shutdown(client_->getSocket(), SHUT_RDWR);
+ writer_->Shutdown();
release_ = true;
thread_triggered_condition_.notify_all();
}
@@ -60,7 +56,7 @@
bool IsWatching(log_id_t id) const { return log_mask_ & (1 << id); }
bool IsWatchingMultiple(unsigned int log_mask) const { return log_mask_ & log_mask; }
- const SocketClient* client() const { return client_; }
+ std::string name() const { return writer_->name(); }
uint64_t start() const { return start_; }
std::chrono::steady_clock::time_point deadline() const { return deadline_; }
@@ -70,19 +66,17 @@
FlushToResult FilterFirstPass(const LogBufferElement* element);
FlushToResult FilterSecondPass(const LogBufferElement* element);
+ std::condition_variable thread_triggered_condition_;
+ LogBuffer* log_buffer_;
+ LogReaderList* reader_list_;
+ std::unique_ptr<LogWriter> writer_;
+
// Set to true to cause the thread to end and the LogReaderThread to delete itself.
bool release_ = false;
// Indicates whether or not 'leading' (first logs seen starting from start_) 'dropped' (chatty)
// messages should be ignored.
bool leading_dropped_;
- // Condition variable for waking the reader thread if there are messages pending for its client.
- std::condition_variable thread_triggered_condition_;
-
- // Reference to the parent thread that manages log reader sockets.
- LogReader& reader_;
- // Reference to the parent list that shares its lock with each instance
- LogReaderList& reader_list_;
// A mask of the logs buffers that are read by this reader.
const unsigned int log_mask_;
// If set to non-zero, only pids equal to this are read by the reader.
@@ -105,8 +99,6 @@
// and to disconnect the reader (if it is dumpAndClose, `adb logcat -t`), when index_ >= count_.
unsigned long index_;
- // A pointer to the socket for this reader.
- SocketClient* client_;
// When a reader requests logs starting from a given timestamp, its stored here for the first
// pass, such that logs before this time stamp that are accumulated in the buffer are ignored.
log_time start_time_;
@@ -117,10 +109,4 @@
std::chrono::steady_clock::time_point deadline_;
// If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
const bool non_block_;
-
- // Whether or not this reader can read logs from all UIDs or only its own UID. See
- // clientHasLogCredentials().
- bool privileged_;
- // Whether or not this reader can read security logs. See CanReadSecurityLogs().
- bool can_read_security_logs_;
};
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 3fe1bbe..ce82b41 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -60,10 +60,6 @@
}
}
-// Furnished in LogCommand.cpp
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
-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);
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 9d762dc..88a3bdc 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -16,13 +16,11 @@
#include <ctype.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
-#include <cutils/properties.h>
#include "LogWhiteBlackList.h"
-// White and Black list
-
Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
}
@@ -75,14 +73,12 @@
it = mNaughty.erase(it);
}
- static const char _default[] = "default";
// default here means take ro.logd.filter, persist.logd.filter then
// internal default in that order.
- if (str && !strcmp(str, _default)) {
+ if (str && !strcmp(str, "default")) {
str = nullptr;
}
- static const char _disable[] = "disable";
- if (str && !strcmp(str, _disable)) {
+ if (str && !strcmp(str, "disable")) {
str = "";
}
@@ -91,22 +87,20 @@
if (str) {
filter = str;
} else {
- char property[PROPERTY_VALUE_MAX];
- property_get("ro.logd.filter", property, _default);
- filter = property;
- property_get("persist.logd.filter", property, filter.c_str());
+ filter = android::base::GetProperty("ro.logd.filter", "default");
+ auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
// default here means take ro.logd.filter
- if (strcmp(property, _default)) {
- filter = property;
+ if (persist_filter != "default") {
+ filter = persist_filter;
}
}
// default here means take internal default.
- if (filter == _default) {
+ if (filter == "default") {
// See README.property for description of filter format
filter = "~! ~1000/!";
}
- if (filter == _disable) {
+ if (filter == "disable") {
filter = "";
}
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 6e9893b..0e4e837 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LOGD_LOG_WHITE_BLACK_LIST_H__
-#define _LOGD_LOG_WHITE_BLACK_LIST_H__
+#pragma once
#include <sys/types.h>
@@ -24,8 +23,6 @@
#include "LogBufferElement.h"
-// White and Blacklist
-
class Prune {
friend class PruneList;
@@ -84,5 +81,3 @@
std::string format();
};
-
-#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/LogWriter.h b/logd/LogWriter.h
new file mode 100644
index 0000000..b6c5b67
--- /dev/null
+++ b/logd/LogWriter.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <log/log_read.h>
+
+// An interface for writing logs to a reader.
+class LogWriter {
+ public:
+ LogWriter(uid_t uid, bool privileged, bool can_read_security_logs)
+ : uid_(uid), privileged_(privileged), can_read_security_logs_(can_read_security_logs) {}
+ virtual ~LogWriter() {}
+
+ virtual bool Write(const logger_entry& entry, const char* msg) = 0;
+ virtual void Shutdown() {}
+ virtual void Release() {}
+
+ virtual std::string name() const = 0;
+ uid_t uid() const { return uid_; }
+
+ bool privileged() const { return privileged_; }
+ bool can_read_security_logs() const { return can_read_security_logs_; }
+
+ private:
+ uid_t uid_;
+
+ // If this writer sees logs from all UIDs or only its own UID. See clientHasLogCredentials().
+ bool privileged_;
+ bool can_read_security_logs_; // If this writer sees security logs. See CanReadSecurityLogs().
+};
\ No newline at end of file
diff --git a/logd/main.cpp b/logd/main.cpp
index 6e1144b..1deca72 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,7 +38,6 @@
#include <android-base/macros.h>
#include <cutils/android_get_control_file.h>
-#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
@@ -53,6 +52,7 @@
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogListener.h"
+#include "LogReader.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogUtils.h"