Merge "Use property ro.product.enforce_debugfs_restrictions to enable debugfs restrictions"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 700d4bd..dfed77e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -673,7 +673,7 @@
return fd;
}
-static void CheckRequirement(const std::string& cur_product, const std::string& var,
+static bool CheckRequirement(const std::string& cur_product, const std::string& var,
const std::string& product, bool invert,
const std::vector<std::string>& options) {
Status("Checking '" + var + "'");
@@ -685,7 +685,7 @@
double split = now();
fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n",
cur_product.c_str(), product.c_str(), (split - start));
- return;
+ return true;
}
}
@@ -694,7 +694,7 @@
fprintf(stderr, "FAILED\n\n");
fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
fb->Error().c_str());
- die("requirements not met!");
+ return false;
}
bool match = false;
@@ -714,7 +714,7 @@
if (match) {
double split = now();
fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
- return;
+ return true;
}
fprintf(stderr, "FAILED\n\n");
@@ -724,7 +724,7 @@
fprintf(stderr, " or '%s'", it->c_str());
}
fprintf(stderr, ".\n\n");
- die("requirements not met!");
+ return false;
}
bool ParseRequirementLine(const std::string& line, std::string* name, std::string* product,
@@ -788,7 +788,7 @@
}
}
-static void CheckRequirements(const std::string& data) {
+static void CheckRequirements(const std::string& data, bool force_flash) {
std::string cur_product;
if (fb->GetVar("product", &cur_product) != fastboot::SUCCESS) {
fprintf(stderr, "getvar:product FAILED (%s)\n", fb->Error().c_str());
@@ -812,7 +812,14 @@
if (name == "partition-exists") {
HandlePartitionExists(options);
} else {
- CheckRequirement(cur_product, name, product, invert, options);
+ bool met = CheckRequirement(cur_product, name, product, invert, options);
+ if (!met) {
+ if (!force_flash) {
+ die("requirements not met!");
+ } else {
+ fprintf(stderr, "requirements not met! but proceeding due to --force\n");
+ }
+ }
}
}
}
@@ -1405,7 +1412,8 @@
class FlashAllTool {
public:
- FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe);
+ FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary,
+ bool wipe, bool force_flash);
void Flash();
@@ -1421,16 +1429,19 @@
std::string slot_override_;
bool skip_secondary_;
bool wipe_;
+ bool force_flash_;
std::string secondary_slot_;
std::vector<std::pair<const Image*, std::string>> boot_images_;
std::vector<std::pair<const Image*, std::string>> os_images_;
};
-FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe)
+FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override,
+ bool skip_secondary, bool wipe, bool force_flash)
: source_(source),
slot_override_(slot_override),
skip_secondary_(skip_secondary),
- wipe_(wipe)
+ wipe_(wipe),
+ force_flash_(force_flash)
{
}
@@ -1478,7 +1489,7 @@
if (!source_.ReadFile("android-info.txt", &contents)) {
die("could not read android-info.txt");
}
- ::CheckRequirements({contents.data(), contents.size()});
+ ::CheckRequirements({contents.data(), contents.size()}, force_flash_);
}
void FlashAllTool::DetermineSecondarySlot() {
@@ -1598,14 +1609,15 @@
return unzip_to_file(zip_, name.c_str());
}
-static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
+static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary,
+ bool force_flash) {
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
- FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false);
+ FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false, force_flash);
tool.Flash();
CloseArchive(zip);
@@ -1630,8 +1642,9 @@
return unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_BINARY)));
}
-static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
- FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
+static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe,
+ bool force_flash) {
+ FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe, force_flash);
tool.Flash();
}
@@ -2179,9 +2192,9 @@
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(slot_override, true, wants_wipe);
+ do_flashall(slot_override, true, wants_wipe, force_flash);
} else {
- do_flashall(slot_override, skip_secondary, wants_wipe);
+ do_flashall(slot_override, skip_secondary, wants_wipe, force_flash);
}
wants_reboot = true;
} else if (command == "update") {
@@ -2193,7 +2206,7 @@
if (!args.empty()) {
filename = next_arg(&args);
}
- do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
+ do_update(filename.c_str(), slot_override, skip_secondary || slot_all, force_flash);
wants_reboot = true;
} else if (command == FB_CMD_SET_ACTIVE) {
std::string slot = verify_slot(next_arg(&args), false);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6952cdf..bbbb7e8 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -647,6 +647,46 @@
return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
}
+static void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb) {
+ std::string block_device;
+ if (!Realpath(entry_block_device, &block_device)) {
+ PERROR << "Failed to realpath " << entry_block_device;
+ return;
+ }
+
+ static constexpr std::string_view kDevBlockPrefix("/dev/block/");
+ if (!android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ LWARNING << block_device << " is not a block device";
+ return;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ while (true) {
+ std::string block_name = block_device;
+ if (android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ block_name = block_device.substr(kDevBlockPrefix.length());
+ }
+ std::string sys_partition =
+ android::base::StringPrintf("/sys/class/block/%s/partition", block_name.c_str());
+ struct stat info;
+ if (lstat(sys_partition.c_str(), &info) == 0) {
+ // it has a partition like "sda12".
+ block_name += "/..";
+ }
+ std::string sys_ra = android::base::StringPrintf("/sys/class/block/%s/queue/read_ahead_kb",
+ block_name.c_str());
+ std::string size = android::base::StringPrintf("%llu", (long long)size_kb);
+ android::base::WriteStringToFile(size, sys_ra.c_str());
+ LINFO << "Set readahead_kb: " << size << " on " << sys_ra;
+
+ auto parent = dm.GetParentBlockDeviceByPath(block_device);
+ if (!parent) {
+ return;
+ }
+ block_device = *parent;
+ }
+}
+
//
// Prepare the filesystem on the given block device to be mounted.
//
@@ -667,6 +707,11 @@
}
mkdir(mount_point.c_str(), 0755);
+ // Don't need to return error, since it's a salt
+ if (entry.readahead_size_kb != -1) {
+ SetReadAheadSize(blk_device, entry.readahead_size_kb);
+ }
+
int fs_stat = 0;
if (is_extfs(entry.fs_type)) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0c0862e..42bf356 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -254,6 +255,13 @@
} else {
entry->reserved_size = static_cast<off64_t>(size);
}
+ } else if (StartsWith(flag, "readahead_size_kb=")) {
+ int val;
+ if (ParseInt(arg, &val, 0, 16 * 1024)) {
+ entry->readahead_size_kb = val;
+ } else {
+ LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
+ }
} else if (StartsWith(flag, "eraseblk=")) {
// The erase block size flag is followed by an = and the flash erase block size. Get it,
// check that it is a power of 2 and at least 4096, and return it.
@@ -680,7 +688,7 @@
}
}
-bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
+bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
@@ -689,41 +697,51 @@
bool is_proc_mounts = path == "/proc/mounts";
- if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
+ Fstab fstab;
+ if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, &fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
return false;
}
- if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
- // This is expected to fail if host is android Q, since Q doesn't
- // support DSU slotting. The DSU "active" indicator file would be
- // non-existent or empty if DSU is enabled within the guest system.
- // In that case, just use the default slot name "dsu".
- std::string dsu_slot;
- if (!android::gsi::GetActiveDsu(&dsu_slot)) {
- PWARNING << __FUNCTION__ << "(): failed to get active dsu slot";
+ if (!is_proc_mounts) {
+ if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
+ // This is expected to fail if host is android Q, since Q doesn't
+ // support DSU slotting. The DSU "active" indicator file would be
+ // non-existent or empty if DSU is enabled within the guest system.
+ // In that case, just use the default slot name "dsu".
+ std::string dsu_slot;
+ if (!android::gsi::GetActiveDsu(&dsu_slot) && errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to get active DSU slot";
+ return false;
+ }
+ if (dsu_slot.empty()) {
+ dsu_slot = "dsu";
+ LWARNING << __FUNCTION__ << "(): assuming default DSU slot: " << dsu_slot;
+ }
+ // This file is non-existent on Q vendor.
+ std::string lp_names;
+ if (!ReadFileToString(gsi::kGsiLpNamesFile, &lp_names) && errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to read DSU LP names";
+ return false;
+ }
+ TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ","));
+ } else if (errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator";
+ return false;
}
- if (dsu_slot.empty()) {
- dsu_slot = "dsu";
- }
-
- std::string lp_names;
- ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
- TransformFstabForDsu(fstab, dsu_slot, Split(lp_names, ","));
}
-#ifndef NO_SKIP_MOUNT
- SkipMountingPartitions(fstab);
-#endif
- EnableMandatoryFlags(fstab);
+ SkipMountingPartitions(&fstab, false /* verbose */);
+ EnableMandatoryFlags(&fstab);
+ *fstab_out = std::move(fstab);
return true;
}
// Returns fstab entries parsed from the device tree if they exist
-bool ReadFstabFromDt(Fstab* fstab, bool log) {
+bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
std::string fstab_buf = ReadFstabFromDt();
if (fstab_buf.empty()) {
- if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
+ if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
return false;
}
@@ -731,34 +749,36 @@
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
- if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ if (verbose) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
return false;
}
if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
- if (log) {
+ if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
}
return false;
}
-#ifndef NO_SKIP_MOUNT
- SkipMountingPartitions(fstab);
-#endif
+ SkipMountingPartitions(fstab, verbose);
return true;
}
-#ifndef NO_SKIP_MOUNT
+#ifdef NO_SKIP_MOUNT
+bool SkipMountingPartitions(Fstab*, bool) {
+ return true;
+}
+#else
// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
// only common files for all targets can be put into system partition. It is under
// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
// partition and product partition under /system/system_ext and /system/product, respectively.
-bool SkipMountingPartitions(Fstab* fstab) {
- constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
+bool SkipMountingPartitions(Fstab* fstab, bool verbose) {
+ static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
std::string skip_config;
auto save_errno = errno;
@@ -767,29 +787,39 @@
return true;
}
- for (const auto& skip_mount_point : Split(skip_config, "\n")) {
- if (skip_mount_point.empty()) {
+ std::vector<std::string> skip_mount_patterns;
+ for (const auto& line : Split(skip_config, "\n")) {
+ if (line.empty() || StartsWith(line, "#")) {
continue;
}
- auto it = std::remove_if(fstab->begin(), fstab->end(),
- [&skip_mount_point](const auto& entry) {
- return entry.mount_point == skip_mount_point;
- });
- if (it == fstab->end()) continue;
- fstab->erase(it, fstab->end());
- LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+ skip_mount_patterns.push_back(line);
}
+ // Returns false if mount_point matches any of the skip mount patterns, so that the FstabEntry
+ // would be partitioned to the second group.
+ auto glob_pattern_mismatch = [&skip_mount_patterns](const FstabEntry& entry) -> bool {
+ for (const auto& pattern : skip_mount_patterns) {
+ if (!fnmatch(pattern.c_str(), entry.mount_point.c_str(), 0 /* flags */)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ auto remove_from = std::stable_partition(fstab->begin(), fstab->end(), glob_pattern_mismatch);
+ if (verbose) {
+ for (auto it = remove_from; it != fstab->end(); ++it) {
+ LINFO << "Skip mounting mountpoint: " << it->mount_point;
+ }
+ }
+ fstab->erase(remove_from, fstab->end());
return true;
}
#endif
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
- Fstab dt_fstab;
- ReadFstabFromDt(&dt_fstab, false);
-
- *fstab = std::move(dt_fstab);
+ fstab->clear();
+ ReadFstabFromDt(fstab, false /* verbose */);
std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
@@ -800,16 +830,14 @@
}
Fstab default_fstab;
- if (!default_fstab_path.empty()) {
- ReadFstabFromFile(default_fstab_path, &default_fstab);
+ if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
+ for (auto&& entry : default_fstab) {
+ fstab->emplace_back(std::move(entry));
+ }
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
- for (auto&& entry : default_fstab) {
- fstab->emplace_back(std::move(entry));
- }
-
return !fstab->empty();
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 2d4de09..2704e47 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -47,6 +47,7 @@
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
+ off64_t readahead_size_kb = -1;
std::string encryption_options;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
@@ -97,9 +98,9 @@
using Fstab = std::vector<FstabEntry>;
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
-bool ReadFstabFromDt(Fstab* fstab, bool log = true);
+bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);
bool ReadDefaultFstab(Fstab* fstab);
-bool SkipMountingPartitions(Fstab* fstab);
+bool SkipMountingPartitions(Fstab* fstab, bool verbose = false);
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
// The Fstab can contain multiple entries for the same mount point with different configurations.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
new file mode 100644
index 0000000..ac2c787
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 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 <gmock/gmock.h>
+#include <libsnapshot/snapshot_stats.h>
+
+namespace android::snapshot {
+
+class MockSnapshotMergeStats final : public ISnapshotMergeStats {
+ public:
+ virtual ~MockSnapshotMergeStats() = default;
+ // Called when merge starts or resumes.
+ MOCK_METHOD(bool, Start, (), (override));
+ MOCK_METHOD(void, set_state, (android::snapshot::UpdateState, bool), (override));
+ MOCK_METHOD(void, set_cow_file_size, (uint64_t), ());
+ MOCK_METHOD(void, set_total_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_estimated_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_boot_complete_time_ms, (uint32_t), (override));
+ MOCK_METHOD(void, set_boot_complete_to_merge_start_time_ms, (uint32_t), (override));
+ MOCK_METHOD(uint64_t, cow_file_size, (), (override));
+ MOCK_METHOD(uint64_t, total_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint64_t, estimated_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_time_ms, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_to_merge_start_time_ms, (), (override));
+ MOCK_METHOD(std::unique_ptr<Result>, Finish, (), (override));
+
+ using ISnapshotMergeStats::Result;
+ // Return nullptr if any failure.
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index 1dab361..280e857 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -69,6 +69,8 @@
// must ONLY be called if the control device has already been deleted.
bool WaitForDeviceDelete(const std::string& control_device);
+ void CloseConnection() { sockfd_ = {}; }
+
// Detach snapuserd. This shuts down the listener socket, and will cause
// snapuserd to gracefully exit once all handler threads have terminated.
// This should only be used on first-stage instances of snapuserd.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 2c5bf75..a0a1e4f 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2297,6 +2297,17 @@
return false;
}
}
+
+ // Terminate the daemon and release the snapuserd_client_ object.
+ // If we need to re-connect with the daemon, EnsureSnapuserdConnected()
+ // will re-create the object and establish the socket connection.
+ if (snapuserd_client_) {
+ LOG(INFO) << "Shutdown snapuserd daemon";
+ snapuserd_client_->DetachSnapuserd();
+ snapuserd_client_->CloseConnection();
+ snapuserd_client_ = nullptr;
+ }
+
return true;
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 6ed0129..8fae00b 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2019,6 +2019,8 @@
// Read bytes back and verify they match the cache.
ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
+
+ ASSERT_TRUE(sm->UnmapAllSnapshots());
}
TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 9335364..87c5528 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -158,6 +158,7 @@
bool CommitMerge(int num_merge_ops);
void CloseFds() { cow_fd_ = {}; }
+ void FreeResources() { worker_threads_.clear(); }
size_t GetMetadataAreaSize() { return vec_.size(); }
void* GetExceptionBuffer(size_t i) { return vec_[i].get(); }
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 167895e..64332d1 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -219,7 +219,13 @@
auto iter = FindHandler(&lock, handler->misc_name());
if (iter == dm_users_.end()) {
// RemoveAndJoinHandler() already removed us from the list, and is
- // now waiting on a join(), so just return.
+ // now waiting on a join(), so just return. Additionally, release
+ // all the resources held by snapuserd object which are shared
+ // by worker threads. This should be done when the last reference
+ // of "handler" is released; but we will explicitly release here
+ // to make sure snapuserd object is freed as it is the biggest
+ // consumer of memory in the daemon.
+ handler->FreeResources();
LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
return;
}
diff --git a/fs_mgr/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd_server.h
index e9d575d..6699189 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd_server.h
@@ -49,7 +49,15 @@
public:
explicit DmUserHandler(std::shared_ptr<Snapuserd> snapuserd);
- void FreeResources() { snapuserd_ = nullptr; }
+ void FreeResources() {
+ // Each worker thread holds a reference to snapuserd.
+ // Clear them so that all the resources
+ // held by snapuserd is released
+ if (snapuserd_) {
+ snapuserd_->FreeResources();
+ snapuserd_ = nullptr;
+ }
+ }
const std::shared_ptr<Snapuserd>& snapuserd() const { return snapuserd_; }
std::thread& thread() { return thread_; }
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 5887641..9adb6bd 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1097,3 +1097,59 @@
ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults readahead_size_kb=blah
+source none1 swap defaults readahead_size_kb=128
+source none2 swap defaults readahead_size_kb=5%
+source none3 swap defaults readahead_size_kb=5kb
+source none4 swap defaults readahead_size_kb=16385
+source none5 swap defaults readahead_size_kb=-128
+source none6 swap defaults readahead_size_kb=0
+)fs";
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_EQ(7U, fstab.size());
+
+ FstabEntry::FsMgrFlags flags = {};
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("none0", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none1", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(128, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none2", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none3", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none4", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none5", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none6", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(0, entry->readahead_size_kb);
+}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a11bb28..3faf430 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -97,7 +97,6 @@
bool MountPartitions();
bool TrySwitchSystemAsRoot();
- bool TrySkipMountingPartitions();
bool IsDmLinearEnabled();
void GetSuperDeviceName(std::set<std::string>* devices);
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
@@ -534,7 +533,7 @@
bool FirstStageMount::MountPartitions() {
if (!TrySwitchSystemAsRoot()) return false;
- if (!SkipMountingPartitions(&fstab_)) return false;
+ if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;
for (auto current = fstab_.begin(); current != fstab_.end();) {
// We've already mounted /system above.
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 73ef97a..c2eb73c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1176,7 +1176,7 @@
} else if (qemu_key == "media.ccodec"sv) {
return "debug.stagefright.ccodec"s;
} else {
- return ""s; // TBD
+ return "qemu."s + std::string(qemu_key);
}
}
@@ -1200,6 +1200,22 @@
// emulator specific, should be retired once emulator migrates to
// androidboot.
InitPropertySet("ro.boot." + key, value);
+ } else if (key == "android.bootanim" && value == "0") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ InitPropertySet("ro.boot.debug.sf.nobootanimation", "1");
+ } else if (key == "android.checkjni") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ std::string value_bool;
+ if (value == "0") {
+ value_bool = "false";
+ } else if (value == "1") {
+ value_bool = "true";
+ } else {
+ value_bool = value;
+ }
+ InitPropertySet("ro.boot.dalvik.vm.checkjni", value_bool);
}
});
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 62c4586..2d3e06e 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -658,7 +658,7 @@
extra_fstab.emplace_back(std::move(entry));
}
- SkipMountingPartitions(&extra_fstab);
+ SkipMountingPartitions(&extra_fstab, true /* verbose */);
if (extra_fstab.empty()) {
return;
}
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index cab988b..2221228 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -106,10 +106,10 @@
}
if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
- [&args](const auto& other) { return other.devpath == args[2]; }) !=
+ [&args](const auto& other) { return other.devpath == args[1]; }) !=
external_firmware_handlers->end()) {
return Error() << "found a previous external_firmware_handler with the same devpath, '"
- << args[2] << "'";
+ << args[1] << "'";
}
passwd* pwd = getpwnam(args[2].c_str());
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index b604c53..4e63ba5 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -45,6 +45,13 @@
EXPECT_EQ(expected.attribute_, test.attribute_);
}
+void TestExternalFirmwareHandler(const ExternalFirmwareHandler& expected,
+ const ExternalFirmwareHandler& test) {
+ EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
+ EXPECT_EQ(expected.uid, test.uid) << expected.uid;
+ EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
+}
+
template <typename T, typename F>
void TestVector(const T& expected, const T& test, F function) {
ASSERT_EQ(expected.size(), test.size());
@@ -67,6 +74,8 @@
TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
+ TestVector(expected.external_firmware_handlers, result.external_firmware_handlers,
+ TestExternalFirmwareHandler);
}
TEST(ueventd_parser, EmptyFile) {
@@ -144,7 +153,7 @@
auto ueventd_file = R"(
external_firmware_handler devpath root handler_path
external_firmware_handler /devices/path/firmware/something001.bin system /vendor/bin/firmware_handler.sh
-external_firmware_handler /devices/path/firmware/something001.bin radio "/vendor/bin/firmware_handler.sh --has --arguments"
+external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor/bin/firmware_handler.sh --has --arguments"
)";
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
@@ -159,7 +168,7 @@
"/vendor/bin/firmware_handler.sh",
},
{
- "/devices/path/firmware/something001.bin",
+ "/devices/path/firmware/something002.bin",
AID_RADIO,
"/vendor/bin/firmware_handler.sh --has --arguments",
},
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index baee4f9..c934860 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -24,7 +24,8 @@
class Modprobe {
public:
- Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load");
+ Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load",
+ bool use_blocklist = true);
bool LoadListedModules(bool strict = true);
bool LoadWithAliases(const std::string& module_name, bool strict,
@@ -36,7 +37,6 @@
std::vector<std::string>* post_dependencies);
void ResetModuleCount() { module_count_ = 0; }
int GetModuleCount() { return module_count_; }
- void EnableBlocklist(bool enable);
private:
std::string MakeCanonical(const std::string& module_path);
@@ -48,6 +48,7 @@
void AddOption(const std::string& module_name, const std::string& option_name,
const std::string& value);
std::string GetKernelCmdline();
+ bool IsBlocklisted(const std::string& module_name);
bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
bool ParseAliasCallback(const std::vector<std::string>& args);
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index b3ae937..1a9d364 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -313,7 +313,9 @@
}
}
-Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file) {
+Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file,
+ bool use_blocklist)
+ : blocklist_enabled(use_blocklist) {
using namespace std::placeholders;
for (const auto& base_path : base_paths) {
@@ -339,10 +341,6 @@
ParseKernelCmdlineOptions();
}
-void Modprobe::EnableBlocklist(bool enable) {
- blocklist_enabled = enable;
-}
-
std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
auto it = module_deps_.find(module);
if (it == module_deps_.end()) {
@@ -427,10 +425,23 @@
return true;
}
+bool Modprobe::IsBlocklisted(const std::string& module_name) {
+ if (!blocklist_enabled) return false;
+
+ auto canonical_name = MakeCanonical(module_name);
+ auto dependencies = GetDependencies(canonical_name);
+ for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
+ if (module_blocklist_.count(MakeCanonical(*dep))) return true;
+ }
+
+ return module_blocklist_.count(canonical_name) > 0;
+}
+
bool Modprobe::LoadListedModules(bool strict) {
auto ret = true;
for (const auto& module : module_load_) {
if (!LoadWithAliases(module, true)) {
+ if (IsBlocklisted(module)) continue;
ret = false;
if (strict) break;
}
@@ -440,16 +451,10 @@
bool Modprobe::Remove(const std::string& module_name) {
auto dependencies = GetDependencies(MakeCanonical(module_name));
- if (dependencies.empty()) {
- LOG(ERROR) << "Empty dependencies for module " << module_name;
- return false;
- }
- if (!Rmmod(dependencies[0])) {
- return false;
- }
- for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
+ for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
Rmmod(*dep);
}
+ Rmmod(module_name);
return true;
}
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index d50c10d..f960b61 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -78,6 +78,18 @@
"/test13.ko",
};
+ std::vector<std::string> expected_modules_blocklist_enabled = {
+ "/test1.ko option1=50 option2=60",
+ "/test6.ko",
+ "/test2.ko",
+ "/test5.ko option1=",
+ "/test8.ko",
+ "/test7.ko param1=4",
+ "/test12.ko",
+ "/test11.ko",
+ "/test13.ko",
+ };
+
const std::string modules_dep =
"test1.ko:\n"
"test2.ko:\n"
@@ -146,7 +158,7 @@
*i = dir.path + *i;
}
- Modprobe m({dir.path});
+ Modprobe m({dir.path}, "modules.load", false);
EXPECT_TRUE(m.LoadListedModules());
GTEST_LOG_(INFO) << "Expected modules loaded (in order):";
@@ -176,8 +188,22 @@
EXPECT_TRUE(modules_loaded == expected_after_remove);
- m.EnableBlocklist(true);
+ m = Modprobe({dir.path});
EXPECT_FALSE(m.LoadWithAliases("test4", true));
+ while (modules_loaded.size() > 0) EXPECT_TRUE(m.Remove(modules_loaded.front()));
+ EXPECT_TRUE(m.LoadListedModules());
+
+ GTEST_LOG_(INFO) << "Expected modules loaded after enabling blocklist (in order):";
+ for (auto i = expected_modules_blocklist_enabled.begin();
+ i != expected_modules_blocklist_enabled.end(); ++i) {
+ *i = dir.path + *i;
+ GTEST_LOG_(INFO) << "\"" << *i << "\"";
+ }
+ GTEST_LOG_(INFO) << "Actual modules loaded with blocklist enabled (in order):";
+ for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) {
+ GTEST_LOG_(INFO) << "\"" << *i << "\"";
+ }
+ EXPECT_TRUE(modules_loaded == expected_modules_blocklist_enabled);
}
TEST(libmodprobe, ModuleDepLineWithoutColonIsSkipped) {
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 5b57bdd..bd94621 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -70,11 +70,11 @@
"Name": "Frozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": ""
+ "Name": "FreezerState",
+ "Value": "1"
}
}
]
@@ -83,11 +83,11 @@
"Name": "Unfrozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": "../"
+ "Name": "FreezerState",
+ "Value": "0"
}
}
]
@@ -558,32 +558,6 @@
}
]
},
- {
- "Name": "FreezerDisabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "0"
- }
- }
- ]
- },
- {
- "Name": "FreezerEnabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "1"
- }
- }
- ]
- }
],
"AggregateProfiles": [
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index f13a681..db00a49 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -518,10 +518,10 @@
std::string attr_filepath = params_val["FilePath"].asString();
std::string attr_value = params_val["Value"].asString();
if (!attr_filepath.empty() && !attr_value.empty()) {
- const Json::Value& logfailures = params_val["LogFailures"];
- bool attr_logfailures = logfailures.isNull() || logfailures.asBool();
+ std::string attr_logfailures = params_val["LogFailures"].asString();
+ bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
- attr_logfailures));
+ logfailures));
} else if (attr_filepath.empty()) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty filepath";
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
new file mode 100644
index 0000000..354c7b3
--- /dev/null
+++ b/libstats/pull_rust/Android.bp
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_bindgen {
+ name: "libstatspull_bindgen",
+ wrapper_src: "statslog.h",
+ crate_name: "statspull_bindgen",
+ source_stem: "bindings",
+ bindgen_flags: [
+ "--size_t-is-usize",
+ "--whitelist-function=AStatsEventList_addStatsEvent",
+ "--whitelist-function=AStatsEvent_.*",
+ "--whitelist-function=AStatsManager_.*",
+ "--whitelist-var=AStatsManager_.*",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libstatspull",
+ "libstatssocket",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libstatspull",
+ "libstatssocket",
+ ],
+ },
+ },
+}
+
+rust_library {
+ name: "libstatspull_rust",
+ crate_name: "statspull_rust",
+ srcs: ["stats_pull.rs"],
+ rustlibs: [
+ "liblazy_static",
+ "liblog_rust",
+ "libstatslog_rust_header",
+ "libstatspull_bindgen",
+ ],
+}
diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs
new file mode 100644
index 0000000..174125e
--- /dev/null
+++ b/libstats/pull_rust/stats_pull.rs
@@ -0,0 +1,170 @@
+// Copyright 2021, 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.
+
+//! A Rust interface for the StatsD pull API.
+
+use lazy_static::lazy_static;
+use statslog_rust_header::{Atoms, Stat, StatsError};
+use statspull_bindgen::*;
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::os::raw::c_void;
+use std::sync::Mutex;
+
+/// The return value of callbacks.
+pub type StatsPullResult = Vec<Box<dyn Stat>>;
+
+/// A wrapper for AStatsManager_PullAtomMetadata.
+/// It calls AStatsManager_PullAtomMetadata_release on drop.
+pub struct Metadata {
+ metadata: *mut AStatsManager_PullAtomMetadata,
+}
+
+impl Metadata {
+ /// Calls AStatsManager_PullAtomMetadata_obtain.
+ pub fn new() -> Self {
+ // Safety: We panic if the memory allocation fails.
+ let metadata = unsafe { AStatsManager_PullAtomMetadata_obtain() };
+ if metadata.is_null() {
+ panic!("Cannot obtain pull atom metadata.");
+ } else {
+ Metadata { metadata }
+ }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setCoolDownMillis.
+ pub fn set_cooldown_millis(&mut self, cooldown_millis: i64) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_setCoolDownMillis(self.metadata, cooldown_millis) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getCoolDownMillis.
+ pub fn get_cooldown_millis(&self) -> i64 {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_getCoolDownMillis(self.metadata) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setTimeoutMillis.
+ pub fn set_timeout_millis(&mut self, timeout_millis: i64) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_setTimeoutMillis(self.metadata, timeout_millis) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getTimeoutMillis.
+ pub fn get_timeout_millis(&self) -> i64 {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_getTimeoutMillis(self.metadata) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setAdditiveFields.
+ pub fn set_additive_fields(&mut self, additive_fields: &mut Vec<i32>) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe {
+ AStatsManager_PullAtomMetadata_setAdditiveFields(
+ self.metadata,
+ additive_fields.as_mut_ptr(),
+ additive_fields.len().try_into().expect("Cannot convert length to i32"),
+ )
+ }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getAdditiveFields.
+ pub fn get_additive_fields(&self) -> Vec<i32> {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ // We call getNumAdditiveFields to ensure we pass getAdditiveFields a large enough array.
+ unsafe {
+ let num_fields = AStatsManager_PullAtomMetadata_getNumAdditiveFields(self.metadata)
+ .try_into()
+ .expect("Cannot convert num additive fields to usize");
+ let mut fields = vec![0; num_fields];
+ AStatsManager_PullAtomMetadata_getAdditiveFields(self.metadata, fields.as_mut_ptr());
+ fields
+ }
+ }
+}
+
+impl Drop for Metadata {
+ fn drop(&mut self) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_release(self.metadata) }
+ }
+}
+
+impl Default for Metadata {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+lazy_static! {
+ static ref COOKIES: Mutex<HashMap<i32, fn() -> StatsPullResult>> = Mutex::new(HashMap::new());
+}
+
+// Safety: We store our callbacks in the global so they are valid.
+unsafe extern "C" fn callback_wrapper(
+ atom_tag: i32,
+ data: *mut AStatsEventList,
+ _cookie: *mut c_void,
+) -> AStatsManager_PullAtomCallbackReturn {
+ if !data.is_null() {
+ let map = COOKIES.lock().unwrap();
+ let cb = map.get(&atom_tag);
+ match cb {
+ None => log::error!("No callback found for {}", atom_tag),
+ Some(cb) => {
+ let stats = cb();
+ let result = stats
+ .iter()
+ .map(|stat| stat.add_astats_event(&mut *data))
+ .collect::<Result<Vec<()>, StatsError>>();
+ match result {
+ Ok(_) => {
+ return AStatsManager_PULL_SUCCESS as AStatsManager_PullAtomCallbackReturn
+ }
+ _ => log::error!("Error adding astats events: {:?}", result),
+ }
+ }
+ }
+ }
+ AStatsManager_PULL_SKIP as AStatsManager_PullAtomCallbackReturn
+}
+
+/// Rust wrapper for AStatsManager_setPullAtomCallback.
+pub fn set_pull_atom_callback(
+ atom: Atoms,
+ metadata: Option<&Metadata>,
+ callback: fn() -> StatsPullResult,
+) {
+ COOKIES.lock().unwrap().insert(atom as i32, callback);
+ let metadata_raw = match metadata {
+ Some(m) => m.metadata,
+ None => std::ptr::null_mut(),
+ };
+ // Safety: We pass a valid function as the callback.
+ unsafe {
+ AStatsManager_setPullAtomCallback(
+ atom as i32,
+ metadata_raw,
+ Some(callback_wrapper),
+ std::ptr::null_mut(),
+ );
+ }
+}
+
+/// Rust wrapper for AStatsManager_clearPullAtomCallback.
+pub fn clear_pull_atom_callback(atom: Atoms) {
+ COOKIES.lock().unwrap().remove(&(atom as i32));
+ // Safety: No memory allocations.
+ unsafe { AStatsManager_clearPullAtomCallback(atom as i32) }
+}
diff --git a/libstats/pull_rust/statslog.h b/libstats/pull_rust/statslog.h
new file mode 100644
index 0000000..983fb7b
--- /dev/null
+++ b/libstats/pull_rust/statslog.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "stats_pull_atom_callback.h"
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 8e45226..b57e287 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -443,6 +443,20 @@
refs->mBase->onFirstRef();
}
+void RefBase::incStrongRequireStrong(const void* id) const {
+ weakref_impl* const refs = mRefs;
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
+
+ LOG_ALWAYS_FATAL_IF(c <= 0 || c == INITIAL_STRONG_VALUE,
+ "incStrongRequireStrong() called on %p which isn't already owned", refs);
+#if PRINT_REFS
+ ALOGD("incStrong (requiring strong) of %p from %p: cnt=%d\n", this, id, c);
+#endif
+}
+
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
@@ -521,6 +535,14 @@
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
+void RefBase::weakref_type::incWeakRequireWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->addWeakRef(id);
+ const int32_t c __unused = impl->mWeak.fetch_add(1,
+ std::memory_order_relaxed);
+ LOG_ALWAYS_FATAL_IF(c <= 0, "incWeakRequireWeak called on %p which has no weak refs", this);
+}
void RefBase::weakref_type::decWeak(const void* id)
{
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index c9b4894..93f9654 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -241,6 +241,30 @@
ASSERT_FALSE(wp1 != wp2);
}
+TEST(RefBase, AssertWeakRefExistsSuccess) {
+ bool isDeleted;
+ sp<Foo> foo = sp<Foo>::make(&isDeleted);
+ wp<Foo> weakFoo = foo;
+
+ EXPECT_EQ(weakFoo, wp<Foo>::fromExisting(foo.get()));
+ EXPECT_EQ(weakFoo.unsafe_get(), wp<Foo>::fromExisting(foo.get()).unsafe_get());
+
+ EXPECT_FALSE(isDeleted);
+ foo = nullptr;
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST(RefBase, AssertWeakRefExistsDeath) {
+ // uses some other refcounting method, or none at all
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+
+ // can only get a valid wp<> object when you construct it from an sp<>
+ EXPECT_DEATH(wp<Foo>::fromExisting(foo), "");
+
+ delete foo;
+}
+
// Set up a situation in which we race with visit2AndRremove() to delete
// 2 strong references. Bar destructor checks that there are no early
// deletions and prior updates are visible to destructor.
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 70bf5a0..e3e5f11 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -390,28 +390,6 @@
return static_cast<size_t>(*(p - 1));
}
-status_t String16::makeLower()
-{
- const size_t N = size();
- const char16_t* str = string();
- char16_t* edited = nullptr;
- for (size_t i=0; i<N; i++) {
- const char16_t v = str[i];
- if (v >= 'A' && v <= 'Z') {
- if (!edited) {
- SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
- if (!buf) {
- return NO_MEMORY;
- }
- edited = (char16_t*)buf->data();
- mString = str = edited;
- }
- edited[i] = tolower((char)v);
- }
- }
- return OK;
-}
-
status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
{
const size_t N = size();
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
index 63c2800..defa0f5 100644
--- a/libutils/String16_fuzz.cpp
+++ b/libutils/String16_fuzz.cpp
@@ -34,11 +34,6 @@
str1.size();
}),
- // Casing
- ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
- str1.makeLower();
- }),
-
// Comparison
([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
str1.startsWith(str2);
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index 2505f44..c2e9b02 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -97,13 +97,6 @@
EXPECT_STR16EQ(u" m", tmp);
}
-TEST(String16Test, MakeLower) {
- String16 tmp("Verify Me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
-}
-
TEST(String16Test, ReplaceAll) {
String16 tmp("Verify verify Verify");
tmp.replaceAll(u'r', u'!');
@@ -176,14 +169,6 @@
EXPECT_FALSE(tmp.isStaticString());
}
-TEST(String16Test, StaticStringMakeLower) {
- StaticString16 tmp(u"Verify me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
- EXPECT_FALSE(tmp.isStaticString());
-}
-
TEST(String16Test, StaticStringReplaceAll) {
StaticString16 tmp(u"Verify verify Verify");
tmp.replaceAll(u'r', u'!');
diff --git a/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index d37c1de..29f6bd4 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -21,8 +21,8 @@
using namespace android;
-class SPFoo : public LightRefBase<SPFoo> {
-public:
+class SPFoo : virtual public RefBase {
+ public:
explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
@@ -69,3 +69,14 @@
ASSERT_NE(nullptr, foo);
ASSERT_NE(foo, nullptr);
}
+
+TEST(StrongPointer, AssertStrongRefExists) {
+ // uses some other refcounting method, or non at all
+ bool isDeleted;
+ SPFoo* foo = new SPFoo(&isDeleted);
+
+ // can only get a valid sp<> object when you construct it as an sp<> object
+ EXPECT_DEATH(sp<SPFoo>::fromExisting(foo), "");
+
+ delete foo;
+}
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index e7acd17..7148949 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -140,7 +140,9 @@
// count, and accidentally passed to f(sp<T>), a strong pointer to the object
// will be temporarily constructed and destroyed, prematurely deallocating the
// object, and resulting in heap corruption. None of this would be easily
-// visible in the source.
+// visible in the source. See below on
+// ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION for a compile time
+// option which helps avoid this case.
// Extra Features:
@@ -167,6 +169,42 @@
// to THE SAME sp<> or wp<>. In effect, their thread-safety properties are
// exactly like those of T*, NOT atomic<T*>.
+// Safety option: ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION
+//
+// This flag makes the semantics for using a RefBase object with wp<> and sp<>
+// much stricter by disabling implicit conversion from raw pointers to these
+// objects. In order to use this, apply this flag in Android.bp like so:
+//
+// cflags: [
+// "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
+// ],
+//
+// REGARDLESS of whether this flag is on, best usage of sp<> is shown below. If
+// this flag is on, no other usage is possible (directly calling RefBase methods
+// is possible, but seeing code using 'incStrong' instead of 'sp<>', for
+// instance, should already set off big alarm bells. With carefully constructed
+// data structures, it should NEVER be necessary to directly use RefBase
+// methods). Proper RefBase usage:
+//
+// class Foo : virtual public RefBase { ... };
+//
+// // always construct an sp object with sp::make
+// sp<Foo> myFoo = sp<Foo>::make(/*args*/);
+//
+// // if you need a weak pointer, it must be constructed from a strong
+// // pointer
+// wp<Foo> weakFoo = myFoo; // NOT myFoo.get()
+//
+// // If you are inside of a method of Foo and need access to a strong
+// // explicitly call this function. This documents your intention to code
+// // readers, and it will give a runtime error for what otherwise would
+// // be potential double ownership
+// .... Foo::someMethod(...) {
+// // asserts if there is a memory issue
+// sp<Foo> thiz = sp<Foo>::fromExisting(this);
+// }
+//
+
#ifndef ANDROID_REF_BASE_H
#define ANDROID_REF_BASE_H
@@ -244,6 +282,7 @@
{
public:
void incStrong(const void* id) const;
+ void incStrongRequireStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
@@ -257,6 +296,7 @@
RefBase* refBase() const;
void incWeak(const void* id);
+ void incWeakRequireWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
@@ -365,10 +405,24 @@
inline wp() : m_ptr(nullptr), m_refs(nullptr) { }
+ // if nullptr, returns nullptr
+ //
+ // if a weak pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline wp<T> fromExisting(T* other);
+
+ // for more information about this flag, see above
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ wp(std::nullptr_t) : wp() {}
+#else
wp(T* other); // NOLINT(implicit)
+#endif
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> wp(U* other); // NOLINT(implicit)
+#endif
template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
@@ -376,11 +430,15 @@
// Assignment
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
wp& operator = (T* other);
+#endif
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> wp& operator = (U* other);
+#endif
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
@@ -481,12 +539,27 @@
// Note that the above comparison operations go out of their way to provide an ordering consistent
// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs.
+template <typename T>
+wp<T> wp<T>::fromExisting(T* other) {
+ if (!other) return nullptr;
+
+ auto refs = other->getWeakRefs();
+ refs->incWeakRequireWeak(other);
+
+ wp<T> ret;
+ ret.m_ptr = other;
+ ret.m_refs = refs;
+ return ret;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}
+#endif
template<typename T>
wp<T>::wp(const wp<T>& other)
@@ -502,12 +575,14 @@
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
wp<T>::wp(U* other)
: m_ptr(other)
{
m_refs = other ? other->createWeak(this) : nullptr;
}
+#endif
template<typename T> template<typename U>
wp<T>::wp(const wp<U>& other)
@@ -534,6 +609,7 @@
if (m_ptr) m_refs->decWeak(this);
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
wp<T>& wp<T>::operator = (T* other)
{
@@ -544,6 +620,7 @@
m_refs = newRefs;
return *this;
}
+#endif
template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
@@ -569,6 +646,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (U* other)
{
@@ -579,6 +657,7 @@
m_refs = newRefs;
return *this;
}
+#endif
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const wp<U>& other)
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 1a4b47e..5ce48c6 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -85,8 +85,6 @@
bool contains(const char16_t* chrs) const;
- status_t makeLower();
-
status_t replaceAll(char16_t replaceThis,
char16_t withThis);
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 11128f2..dd53b9e 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -32,30 +32,67 @@
public:
inline sp() : m_ptr(nullptr) { }
- // TODO: switch everyone to using this over new, and make RefBase operator
- // new private to that class so that we can avoid RefBase being used with
- // other memory management mechanisms.
+ // The old way of using sp<> was like this. This is bad because it relies
+ // on implicit conversion to sp<>, which we would like to remove (if an
+ // object is being managed some other way, this is double-ownership). We
+ // want to move away from this:
+ //
+ // sp<Foo> foo = new Foo(...); // DO NOT DO THIS
+ //
+ // Instead, prefer to do this:
+ //
+ // sp<Foo> foo = sp<Foo>::make(...); // DO THIS
+ //
+ // Sometimes, in order to use this, when a constructor is marked as private,
+ // you may need to add this to your class:
+ //
+ // friend class sp<Foo>;
template <typename... Args>
static inline sp<T> make(Args&&... args);
+ // if nullptr, returns nullptr
+ //
+ // if a strong pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline sp<T> fromExisting(T* other);
+
+ // for more information about this macro and correct RefBase usage, see
+ // the comment at the top of utils/RefBase.h
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ sp(std::nullptr_t) : sp() {}
+#else
sp(T* other); // NOLINT(implicit)
+#endif
sp(const sp<T>& other);
sp(sp<T>&& other) noexcept;
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> sp(U* other); // NOLINT(implicit)
+#endif
template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
+ // Cast a strong pointer directly from one type to another. Constructors
+ // allow changing types, but only if they are pointer-compatible. This does
+ // a static_cast internally.
+ template <typename U>
+ static inline sp<T> cast(const sp<U>& other);
+
~sp();
// Assignment
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
sp& operator = (T* other);
+#endif
sp& operator = (const sp<T>& other);
sp& operator=(sp<T>&& other) noexcept;
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (sp<U>&& other);
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> sp& operator = (U* other);
+#endif
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
@@ -189,6 +226,19 @@
return result;
}
+template <typename T>
+sp<T> sp<T>::fromExisting(T* other) {
+ if (other) {
+ check_not_on_stack(other);
+ other->incStrongRequireStrong(other);
+ sp<T> result;
+ result.m_ptr = other;
+ return result;
+ }
+ return nullptr;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
@@ -197,6 +247,7 @@
other->incStrong(this);
}
}
+#endif
template<typename T>
sp<T>::sp(const sp<T>& other)
@@ -210,6 +261,7 @@
other.m_ptr = nullptr;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
sp<T>::sp(U* other)
: m_ptr(other) {
@@ -218,6 +270,7 @@
(static_cast<T*>(other))->incStrong(this);
}
}
+#endif
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
@@ -232,6 +285,12 @@
other.m_ptr = nullptr;
}
+template <typename T>
+template <typename U>
+sp<T> sp<T>::cast(const sp<U>& other) {
+ return sp<T>::fromExisting(static_cast<T*>(other.get()));
+}
+
template<typename T>
sp<T>::~sp() {
if (m_ptr)
@@ -260,6 +319,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
@@ -272,6 +332,7 @@
m_ptr = other;
return *this;
}
+#endif
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(const sp<U>& other) {
@@ -294,6 +355,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(U* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
@@ -303,6 +365,7 @@
m_ptr = other;
return *this;
}
+#endif
template<typename T>
void sp<T>::force_set(T* other) {
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 83cb6ff..d9f5526 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -1,8 +1,7 @@
{
"requireLibs": [
- // Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
- "libdexfile_external.so",
- "libdexfiled_external.so",
+ "libdexfile.so",
+ "libdexfiled.so",
"libnativebridge.so",
"libnativehelper.so",
"libnativeloader.so",
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
index 7529cb9..5e2c581 100644
--- a/toolbox/OWNERS
+++ b/toolbox/OWNERS
@@ -1 +1,2 @@
include platform/system/core:/janitors/OWNERS
+per-file modprobe.c=willmcvicker@google.com,dvander@google.com
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 7df7b71..711586a 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -215,10 +215,7 @@
return EXIT_FAILURE;
}
- Modprobe m(mod_dirs);
- if (blocklist) {
- m.EnableBlocklist(true);
- }
+ Modprobe m(mod_dirs, "modules.load", blocklist);
for (const auto& module : modules) {
switch (mode) {
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 8ab6303..4aca375 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -96,13 +96,13 @@
unique_fd file_fd(TEMP_FAILURE_RETRY(open(file_name, O_RDONLY)));
if (!file_fd.ok()) {
- fprintf(stderr, "Error opening file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error opening file " << file_name;
return {};
}
rc = fstat64(file_fd, &st);
if (rc < 0) {
- fprintf(stderr, "Error calling stat on file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error calling stat on file '" << file_name << "'";
return {};
}
@@ -115,14 +115,14 @@
file_page_offset = page_size - file_page_offset;
}
if (__builtin_add_overflow(file_size, file_page_offset, &file_page_size)) {
- fprintf(stderr, "Failed to page-align file size\n");
+ LOG(ERROR) << "Failed to page-align file size";
return {};
}
BufferAllocator alloc;
unique_fd dmabuf_fd(alloc.Alloc(kDmabufSystemHeapName, file_page_size));
if (!dmabuf_fd.ok()) {
- fprintf(stderr, "Error creating dmabuf: %d\n", dmabuf_fd.get());
+ LOG(ERROR) << "Error creating dmabuf: " << dmabuf_fd.get();
return dmabuf_fd;
}
@@ -137,12 +137,12 @@
pread(file_fd, (char*)shm + file_offset, file_size - file_offset, file_offset));
if (num_read < 0) {
- fprintf(stderr, "Error reading package file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error reading package file '" << file_name << "'";
break;
}
if (num_read == 0) {
- fprintf(stderr, "Unexpected end of file '%s'\n", file_name);
+ LOG(ERROR) << "Unexpected end of file '" << file_name << "'";
break;
}
@@ -182,17 +182,17 @@
struct apploader_resp resp;
ssize_t rc = read(tipc_fd, &resp, sizeof(resp));
if (rc < 0) {
- fprintf(stderr, "Failed to read response: %zd\n", rc);
+ PLOG(ERROR) << "Failed to read response";
return rc;
}
if (rc < sizeof(resp)) {
- fprintf(stderr, "Not enough data in response: %zd\n", rc);
+ LOG(ERROR) << "Not enough data in response: " << rc;
return -EIO;
}
if (resp.hdr.cmd != (APPLOADER_CMD_LOAD_APPLICATION | APPLOADER_RESP_BIT)) {
- fprintf(stderr, "Invalid command in response: %u\n", resp.hdr.cmd);
+ LOG(ERROR) << "Invalid command in response: " << resp.hdr.cmd;
return -EINVAL;
}
@@ -200,28 +200,28 @@
case APPLOADER_NO_ERROR:
break;
case APPLOADER_ERR_UNKNOWN_CMD:
- fprintf(stderr, "Error: unknown command\n");
+ LOG(ERROR) << "Error: unknown command";
break;
case APPLOADER_ERR_INVALID_CMD:
- fprintf(stderr, "Error: invalid command arguments\n");
+ LOG(ERROR) << "Error: invalid command arguments";
break;
case APPLOADER_ERR_NO_MEMORY:
- fprintf(stderr, "Error: out of Trusty memory\n");
+ LOG(ERROR) << "Error: out of Trusty memory";
break;
case APPLOADER_ERR_VERIFICATION_FAILED:
- fprintf(stderr, "Error: failed to verify the package\n");
+ LOG(ERROR) << "Error: failed to verify the package";
break;
case APPLOADER_ERR_LOADING_FAILED:
- fprintf(stderr, "Error: failed to load the package\n");
+ LOG(ERROR) << "Error: failed to load the package";
break;
case APPLOADER_ERR_ALREADY_EXISTS:
- fprintf(stderr, "Error: application already exists\n");
+ LOG(ERROR) << "Error: application already exists";
break;
case APPLOADER_ERR_INTERNAL:
- fprintf(stderr, "Error: internal apploader error\n");
+ LOG(ERROR) << "Error: internal apploader error";
break;
default:
- fprintf(stderr, "Unrecognized error: %u\n", resp.error);
+ LOG(ERROR) << "Unrecognized error: " << resp.error;
break;
}
@@ -241,14 +241,14 @@
tipc_fd = tipc_connect(dev_name, APPLOADER_PORT);
if (tipc_fd < 0) {
- fprintf(stderr, "Failed to connect to Trusty app loader: %s\n", strerror(-tipc_fd));
+ LOG(ERROR) << "Failed to connect to Trusty app loader: " << strerror(-tipc_fd);
rc = tipc_fd;
goto err_tipc_connect;
}
rc = send_load_message(tipc_fd, package_fd, package_size);
if (rc < 0) {
- fprintf(stderr, "Failed to send package: %zd\n", rc);
+ LOG(ERROR) << "Failed to send package: " << rc;
goto err_send;
}