Merge "COW partition creator uses DmSnapshotCowSizeCalculator"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index cc1978d..375207b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -10,7 +10,7 @@
"name": "debuggerd_test"
},
{
- "name": "fs_mgr_unit_test"
+ "name": "CtsFsMgrTestCases"
},
{
"name": "fs_mgr_vendor_overlay_test"
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4ba1c49..6faead0 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -888,6 +888,17 @@
public:
CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
+ bool NeedsCheckpoint() {
+ if (needs_checkpoint_ != UNKNOWN) {
+ return needs_checkpoint_ == YES;
+ }
+ if (!call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
+ LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+ needs_checkpoint_ = NO;
+ }
+ return needs_checkpoint_ == YES;
+ }
+
bool Update(FstabEntry* entry, const std::string& block_device = std::string()) {
if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
return true;
@@ -897,13 +908,7 @@
call_vdc({"checkpoint", "restoreCheckpoint", entry->blk_device}, nullptr);
}
- if (needs_checkpoint_ == UNKNOWN &&
- !call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
- LERROR << "Failed to find if checkpointing is needed. Assuming no.";
- needs_checkpoint_ = NO;
- }
-
- if (needs_checkpoint_ != YES) {
+ if (!NeedsCheckpoint()) {
return true;
}
@@ -1324,6 +1329,69 @@
return ret;
}
+static std::string GetUserdataBlockDevice() {
+ Fstab fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ LERROR << "Failed to read /proc/mounts";
+ return "";
+ }
+ auto entry = GetEntryForMountPoint(&fstab, "/data");
+ if (entry == nullptr) {
+ LERROR << "Didn't find /data mount point in /proc/mounts";
+ return "";
+ }
+ return entry->blk_device;
+}
+
+int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
+ const std::string& block_device = GetUserdataBlockDevice();
+ LINFO << "Userdata is mounted on " << block_device;
+ auto entry = std::find_if(fstab->begin(), fstab->end(), [&block_device](const FstabEntry& e) {
+ if (e.mount_point != "/data") {
+ return false;
+ }
+ if (e.blk_device == block_device) {
+ return true;
+ }
+ DeviceMapper& dm = DeviceMapper::Instance();
+ std::string path;
+ if (!dm.GetDmDevicePathByName("userdata", &path)) {
+ return false;
+ }
+ return path == block_device;
+ });
+ if (entry == fstab->end()) {
+ LERROR << "Can't find /data in fstab";
+ return -1;
+ }
+ if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
+ LINFO << "Userdata doesn't support checkpointing. Nothing to do";
+ return 0;
+ }
+ CheckpointManager checkpoint_manager;
+ if (!checkpoint_manager.NeedsCheckpoint()) {
+ LINFO << "Checkpointing not needed. Don't remount";
+ return 0;
+ }
+ if (entry->fs_mgr_flags.checkpoint_fs) {
+ // Userdata is f2fs, simply remount it.
+ if (!checkpoint_manager.Update(&(*entry))) {
+ LERROR << "Failed to remount userdata in checkpointing mode";
+ return -1;
+ }
+ if (mount(entry->blk_device.c_str(), entry->mount_point.c_str(), "none",
+ MS_REMOUNT | entry->flags, entry->fs_options.c_str()) != 0) {
+ LERROR << "Failed to remount userdata in checkpointing mode";
+ return -1;
+ }
+ } else {
+ // TODO(b/135984674): support remounting for ext4.
+ LERROR << "Remounting in checkpointing mode is not yet supported for ext4";
+ return -1;
+ }
+ return 0;
+}
+
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 2ff5243..d216458 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -99,71 +99,9 @@
return false;
}
-const std::array<const char*, 3> kFileContentsEncryptionMode = {
- "aes-256-xts",
- "adiantum",
- "ice",
-};
-
-const std::array<const char*, 3> kFileNamesEncryptionMode = {
- "aes-256-cts",
- "aes-256-heh",
- "adiantum",
-};
-
void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
- // The fileencryption flag is followed by an = and 1 to 3 colon-separated fields:
- //
- // 1. Contents encryption mode
- // 2. Filenames encryption mode (defaults to "aes-256-cts" or "adiantum"
- // depending on the contents encryption mode)
- // 3. Encryption policy version (defaults to "v1". Use "v2" on new devices.)
entry->fs_mgr_flags.file_encryption = true;
-
- auto parts = Split(arg, ":");
- if (parts.empty() || parts.size() > 3) {
- LWARNING << "Warning: fileencryption= flag malformed: " << arg;
- return;
- }
-
- // Alias for backwards compatibility.
- if (parts[0] == "software") {
- parts[0] = "aes-256-xts";
- }
-
- if (std::find(kFileContentsEncryptionMode.begin(), kFileContentsEncryptionMode.end(),
- parts[0]) == kFileContentsEncryptionMode.end()) {
- LWARNING << "fileencryption= flag malformed, file contents encryption mode not found: "
- << arg;
- return;
- }
-
- entry->file_contents_mode = parts[0];
-
- if (parts.size() >= 2) {
- if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) ==
- kFileNamesEncryptionMode.end()) {
- LWARNING << "fileencryption= flag malformed, file names encryption mode not found: "
- << arg;
- return;
- }
-
- entry->file_names_mode = parts[1];
- } else if (entry->file_contents_mode == "adiantum") {
- entry->file_names_mode = "adiantum";
- } else {
- entry->file_names_mode = "aes-256-cts";
- }
-
- if (parts.size() >= 3) {
- if (!android::base::StartsWith(parts[2], 'v') ||
- !android::base::ParseInt(&parts[2][1], &entry->file_policy_version)) {
- LWARNING << "fileencryption= flag malformed, unknown options: " << arg;
- return;
- }
- } else {
- entry->file_policy_version = 1;
- }
+ entry->encryption_options = arg;
}
bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
@@ -299,9 +237,7 @@
// return it.
entry->fs_mgr_flags.force_fde_or_fbe = true;
entry->key_loc = arg;
- entry->file_contents_mode = "aes-256-xts";
- entry->file_names_mode = "aes-256-cts";
- entry->file_policy_version = 1;
+ entry->encryption_options = "aes-256-xts:aes-256-cts";
} else if (StartsWith(flag, "max_comp_streams=")) {
if (!ParseInt(arg, &entry->max_comp_streams)) {
LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index bdec7be..ca67f37 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -105,6 +105,8 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
+int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
+
// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 3c517dc..c6a16e3 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -45,9 +45,7 @@
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
- std::string file_contents_mode;
- std::string file_names_mode;
- int file_policy_version = 0;
+ std::string encryption_options;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
std::string sysfs_path;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/auto_device.h b/fs_mgr/libsnapshot/include/libsnapshot/auto_device.h
new file mode 100644
index 0000000..d5ceb0e
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/auto_device.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <string>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace snapshot {
+
+// An abstract "device" that will be cleaned up (unmapped, unmounted, etc.) upon
+// destruction.
+struct AutoDevice {
+ virtual ~AutoDevice(){};
+ void Release();
+
+ protected:
+ AutoDevice(const std::string& name) : name_(name) {}
+ std::string name_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoDevice);
+ AutoDevice(AutoDevice&& other) = delete;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 120340c..431fea1 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -33,6 +33,8 @@
#include <liblp/liblp.h>
#include <update_engine/update_metadata.pb.h>
+#include <libsnapshot/auto_device.h>
+
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
friend class test_set_name##_##individual_test##_Test
@@ -120,6 +122,7 @@
virtual const IPartitionOpener& GetPartitionOpener() const = 0;
virtual bool IsOverlayfsSetup() const = 0;
virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
+ virtual bool IsRecovery() const = 0;
};
~SnapshotManager();
@@ -209,6 +212,22 @@
// Dump debug information.
bool Dump(std::ostream& os);
+ // Ensure metadata directory is mounted in recovery. When the returned
+ // AutoDevice is destroyed, the metadata directory is automatically
+ // unmounted.
+ // Return nullptr if any failure.
+ // In Android mode, Return an AutoDevice that does nothing
+ // In recovery, return an AutoDevice that does nothing if metadata entry
+ // is not found in fstab.
+ // Note: if this function is called the second time before the AutoDevice returned from the
+ // first call is destroyed, the device will be unmounted when any of these AutoDevices is
+ // destroyed. FOr example:
+ // auto a = mgr->EnsureMetadataMounted(); // mounts
+ // auto b = mgr->EnsureMetadataMounted(); // does nothing
+ // b.reset() // unmounts
+ // a.reset() // does nothing
+ std::unique_ptr<AutoDevice> EnsureMetadataMounted();
+
private:
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
FRIEND_TEST(SnapshotTest, CreateSnapshot);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 758f69b..63d97d0 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -77,6 +77,12 @@
static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
+#ifdef __ANDROID_RECOVERY__
+constexpr bool kIsRecovery = true;
+#else
+constexpr bool kIsRecovery = false;
+#endif
+
class DeviceInfo final : public SnapshotManager::IDeviceInfo {
public:
std::string GetGsidDir() const override { return "ota"s; }
@@ -89,6 +95,7 @@
}
bool IsOverlayfsSetup() const override { return fs_mgr_overlayfs_is_setup(); }
bool SetBootControlMergeStatus(MergeStatus status) override;
+ bool IsRecovery() const override { return kIsRecovery; }
private:
android::fs_mgr::PartitionOpener opener_;
@@ -1786,6 +1793,14 @@
auto target_metadata =
MetadataBuilder::NewForUpdate(opener, current_super, current_slot, target_slot);
+ // Delete partitions with target suffix in |current_metadata|. Otherwise,
+ // partition_cow_creator recognizes these left-over partitions as used space.
+ for (const auto& group_name : current_metadata->ListGroups()) {
+ if (android::base::EndsWith(group_name, target_suffix)) {
+ current_metadata->RemoveGroupAndPartitions(group_name);
+ }
+ }
+
SnapshotMetadataUpdater metadata_updater(target_metadata.get(), target_slot, manifest);
if (!metadata_updater.Update()) {
LOG(ERROR) << "Cannot calculate new metadata.";
@@ -2065,5 +2080,14 @@
return ok;
}
+std::unique_ptr<AutoDevice> SnapshotManager::EnsureMetadataMounted() {
+ if (!device_->IsRecovery()) {
+ // No need to mount anything in recovery.
+ LOG(INFO) << "EnsureMetadataMounted does nothing in Android mode.";
+ return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice());
+ }
+ return AutoUnmountDevice::New(device_->GetMetadataDir());
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index d33a04e..5728582 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -26,6 +26,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <fs_mgr/roots.h>
#include <fs_mgr_dm_linear.h>
#include <gtest/gtest.h>
#include <libdm/dm.h>
@@ -47,12 +48,16 @@
using android::fs_mgr::BlockDeviceInfo;
using android::fs_mgr::CreateLogicalPartitionParams;
using android::fs_mgr::DestroyLogicalPartition;
+using android::fs_mgr::EnsurePathMounted;
+using android::fs_mgr::EnsurePathUnmounted;
using android::fs_mgr::Extent;
+using android::fs_mgr::Fstab;
using android::fs_mgr::GetPartitionGroupName;
using android::fs_mgr::GetPartitionName;
using android::fs_mgr::Interval;
using android::fs_mgr::MetadataBuilder;
using chromeos_update_engine::DeltaArchiveManifest;
+using chromeos_update_engine::DynamicPartitionGroup;
using chromeos_update_engine::PartitionUpdate;
using namespace ::testing;
using namespace android::storage_literals;
@@ -656,12 +661,12 @@
// Not using full name "system", "vendor", "product" because these names collide with the
// mapped partitions on the running device.
// Each test modifies manifest_ slightly to indicate changes to the partition layout.
- auto group = manifest_.mutable_dynamic_partition_metadata()->add_groups();
- group->set_name("group");
- group->set_size(kGroupSize);
- group->add_partition_names("sys");
- group->add_partition_names("vnd");
- group->add_partition_names("prd");
+ group_ = manifest_.mutable_dynamic_partition_metadata()->add_groups();
+ group_->set_name("group");
+ group_->set_size(kGroupSize);
+ group_->add_partition_names("sys");
+ group_->add_partition_names("vnd");
+ group_->add_partition_names("prd");
sys_ = manifest_.add_partitions();
sys_->set_partition_name("sys");
SetSize(sys_, 3_MiB);
@@ -765,6 +770,7 @@
PartitionUpdate* sys_ = nullptr;
PartitionUpdate* vnd_ = nullptr;
PartitionUpdate* prd_ = nullptr;
+ DynamicPartitionGroup* group_ = nullptr;
};
// Test full update flow executed by update_engine. Some partitions uses super empty space,
@@ -1071,6 +1077,149 @@
}
}
+TEST_F(SnapshotUpdateTest, RetrofitAfterRegularAb) {
+ constexpr auto kRetrofitGroupSize = kGroupSize / 2;
+
+ // Initialize device-mapper / disk
+ ASSERT_TRUE(UnmapAll());
+ FormatFakeSuper();
+
+ // Setup source partition metadata to have both _a and _b partitions.
+ src_ = MetadataBuilder::New(*opener_, "super", 0);
+ ASSERT_NE(nullptr, src_);
+ for (const auto& suffix : {"_a"s, "_b"s}) {
+ ASSERT_TRUE(src_->AddGroup(group_->name() + suffix, kRetrofitGroupSize));
+ for (const auto& name : {"sys"s, "vnd"s, "prd"s}) {
+ auto partition = src_->AddPartition(name + suffix, group_->name() + suffix, 0);
+ ASSERT_NE(nullptr, partition);
+ ASSERT_TRUE(src_->ResizePartition(partition, 2_MiB));
+ }
+ }
+ auto metadata = src_->Export();
+ ASSERT_NE(nullptr, metadata);
+ ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *metadata.get(), 0));
+
+ // Flash source partitions
+ std::string path;
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ ASSERT_TRUE(CreateLogicalPartition(
+ CreateLogicalPartitionParams{
+ .block_device = fake_super,
+ .metadata_slot = 0,
+ .partition_name = name,
+ .timeout_ms = 1s,
+ .partition_opener = opener_.get(),
+ },
+ &path));
+ ASSERT_TRUE(WriteRandomData(path));
+ auto hash = GetHash(path);
+ ASSERT_TRUE(hash.has_value());
+ hashes_[name] = *hash;
+ }
+
+ // Setup manifest.
+ group_->set_size(kRetrofitGroupSize);
+ for (auto* partition : {sys_, vnd_, prd_}) {
+ SetSize(partition, 2_MiB);
+ auto* e = partition->add_operations()->add_dst_extents();
+ e->set_start_block(0);
+ e->set_num_blocks(2_MiB / manifest_.block_size());
+ }
+
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+ // Test that COW image should not be created for retrofit devices; super
+ // should be big enough.
+ ASSERT_FALSE(image_manager_->BackingImageExists("sys_b-cow-img"));
+ ASSERT_FALSE(image_manager_->BackingImageExists("vnd_b-cow-img"));
+ ASSERT_FALSE(image_manager_->BackingImageExists("prd_b-cow-img"));
+
+ // Write some data to target partitions.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ std::string path;
+ ASSERT_TRUE(sm->MapUpdateSnapshot(
+ CreateLogicalPartitionParams{
+ .block_device = fake_super,
+ .metadata_slot = 1,
+ .partition_name = name,
+ .timeout_ms = 10s,
+ .partition_opener = opener_.get(),
+ },
+ &path))
+ << name;
+ ASSERT_TRUE(WriteRandomData(path));
+ auto hash = GetHash(path);
+ ASSERT_TRUE(hash.has_value());
+ hashes_[name] = *hash;
+ }
+
+ // Assert that source partitions aren't affected.
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
+ ASSERT_TRUE(sm->FinishedSnapshotWrites());
+}
+
+class MetadataMountedTest : public SnapshotUpdateTest {
+ public:
+ void SetUp() override {
+ metadata_dir_ = test_device->GetMetadataDir();
+ ASSERT_TRUE(ReadDefaultFstab(&fstab_));
+ }
+ void TearDown() override {
+ SetUp();
+ // Remount /metadata
+ test_device->set_recovery(false);
+ EXPECT_TRUE(android::fs_mgr::EnsurePathMounted(&fstab_, metadata_dir_));
+ }
+ AssertionResult IsMetadataMounted() {
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ ADD_FAILURE() << "Failed to scan mounted volumes";
+ return AssertionFailure() << "Failed to scan mounted volumes";
+ }
+
+ auto entry = GetEntryForPath(&fstab_, metadata_dir_);
+ if (entry == nullptr) {
+ return AssertionFailure() << "No mount point found in fstab for path " << metadata_dir_;
+ }
+
+ auto mv = GetEntryForMountPoint(&mounted_fstab, entry->mount_point);
+ if (mv == nullptr) {
+ return AssertionFailure() << metadata_dir_ << " is not mounted";
+ }
+ return AssertionSuccess() << metadata_dir_ << " is mounted";
+ }
+ std::string metadata_dir_;
+ Fstab fstab_;
+};
+
+TEST_F(MetadataMountedTest, Android) {
+ auto device = sm->EnsureMetadataMounted();
+ EXPECT_NE(nullptr, device);
+ device.reset();
+
+ EXPECT_TRUE(IsMetadataMounted());
+ EXPECT_TRUE(sm->CancelUpdate()) << "Metadata dir should never be unmounted in Android mode";
+}
+
+TEST_F(MetadataMountedTest, Recovery) {
+ test_device->set_recovery(true);
+ metadata_dir_ = test_device->GetMetadataDir();
+
+ EXPECT_TRUE(android::fs_mgr::EnsurePathUnmounted(&fstab_, metadata_dir_));
+ EXPECT_FALSE(IsMetadataMounted());
+
+ auto device = sm->EnsureMetadataMounted();
+ EXPECT_NE(nullptr, device);
+ EXPECT_TRUE(IsMetadataMounted());
+
+ device.reset();
+ EXPECT_FALSE(IsMetadataMounted());
+}
+
} // namespace snapshot
} // namespace android
@@ -1112,6 +1261,7 @@
}
// Clean up previous run.
+ MetadataMountedTest().TearDown();
SnapshotUpdateTest().Cleanup();
SnapshotTest().Cleanup();
diff --git a/fs_mgr/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/test_helpers.h
index 91a6989..0f70afe 100644
--- a/fs_mgr/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/test_helpers.h
@@ -88,17 +88,20 @@
return true;
}
bool IsOverlayfsSetup() const override { return false; }
+ bool IsRecovery() const override { return recovery_; }
void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
void set_fake_super(const std::string& path) {
opener_ = std::make_unique<TestPartitionOpener>(path);
}
+ void set_recovery(bool value) { recovery_ = value; }
MergeStatus merge_status() const { return merge_status_; }
private:
std::string slot_suffix_ = "_a";
std::unique_ptr<TestPartitionOpener> opener_;
MergeStatus merge_status_;
+ bool recovery_ = false;
};
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 66629e8..615cbca 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -17,9 +17,15 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
+#include <fs_mgr/roots.h>
+using android::fs_mgr::EnsurePathMounted;
+using android::fs_mgr::EnsurePathUnmounted;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::GetEntryForPath;
using android::fs_mgr::MetadataBuilder;
using android::fs_mgr::Partition;
+using android::fs_mgr::ReadDefaultFstab;
namespace android {
namespace snapshot {
@@ -109,5 +115,31 @@
return true;
}
+std::unique_ptr<AutoUnmountDevice> AutoUnmountDevice::New(const std::string& path) {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ LOG(ERROR) << "Cannot read default fstab";
+ return nullptr;
+ }
+
+ if (GetEntryForPath(&fstab, path) == nullptr) {
+ LOG(INFO) << "EnsureMetadataMounted can't find entry for " << path << ", skipping";
+ return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice("", {}));
+ }
+
+ if (!EnsurePathMounted(&fstab, path)) {
+ LOG(ERROR) << "Cannot mount " << path;
+ return nullptr;
+ }
+ return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice(path, std::move(fstab)));
+}
+
+AutoUnmountDevice::~AutoUnmountDevice() {
+ if (name_.empty()) return;
+ if (!EnsurePathUnmounted(&fstab_, name_)) {
+ LOG(ERROR) << "Cannot unmount " << name_;
+ }
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 3051184..0c08ed2 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -18,31 +18,21 @@
#include <string>
#include <android-base/macros.h>
+#include <fstab/fstab.h>
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
#include <libsnapshot/snapshot.h>
#include <update_engine/update_metadata.pb.h>
+#include <libsnapshot/auto_device.h>
+
namespace android {
namespace snapshot {
// Unit is sectors, this is a 4K chunk.
static constexpr uint32_t kSnapshotChunkSize = 8;
-struct AutoDevice {
- virtual ~AutoDevice(){};
- void Release();
-
- protected:
- AutoDevice(const std::string& name) : name_(name) {}
- std::string name_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AutoDevice);
- AutoDevice(AutoDevice&& other) = delete;
-};
-
// A list of devices we created along the way.
// - Whenever a device is created that is subject to GC'ed at the end of
// this function, add it to this list.
@@ -103,6 +93,18 @@
SnapshotManager::LockedFile* lock_ = nullptr;
};
+struct AutoUnmountDevice : AutoDevice {
+ // Empty object that does nothing.
+ AutoUnmountDevice() : AutoDevice("") {}
+ static std::unique_ptr<AutoUnmountDevice> New(const std::string& path);
+ ~AutoUnmountDevice();
+
+ private:
+ AutoUnmountDevice(const std::string& path, android::fs_mgr::Fstab&& fstab)
+ : AutoDevice(path), fstab_(std::move(fstab)) {}
+ android::fs_mgr::Fstab fstab_;
+};
+
// Return a list of partitions in |builder| with the name ending in |suffix|.
std::vector<android::fs_mgr::Partition*> ListPartitionsWithSuffix(
android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 83668e9..4f6ec5a 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -13,8 +13,21 @@
// limitations under the License.
cc_test {
- name: "fs_mgr_unit_test",
- test_suites: ["device-tests"],
+ name: "CtsFsMgrTestCases",
+ test_suites: [
+ "cts",
+ "device-tests",
+ "vts",
+ ],
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
shared_libs: [
"libbase",
diff --git a/fs_mgr/tests/AndroidTest.xml b/fs_mgr/tests/AndroidTest.xml
new file mode 100644
index 0000000..91c3fb9
--- /dev/null
+++ b/fs_mgr/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS fs_mgr test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="systems" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsFsMgrTestCases->/data/local/tmp/CtsFsMgrTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="CtsFsMgrTestCases" />
+ <option name="runtime-hint" value="65s" />
+ </test>
+</configuration>
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index a7ea817..1cbaf45 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -179,6 +179,7 @@
{"nodiratime", MS_NODIRATIME},
{"ro", MS_RDONLY},
{"rw", 0},
+ {"sync", MS_SYNCHRONOUS},
{"remount", MS_REMOUNT},
{"bind", MS_BIND},
{"rec", MS_REC},
@@ -197,7 +198,7 @@
if (!(entry.flags & MS_RDONLY)) {
fs_options.emplace("rw");
}
- EXPECT_EQ(mnt_opts, fs_options);
+ EXPECT_EQ(mnt_opts, fs_options) << "At line " << i;
++i;
}
EXPECT_EQ(i, fstab.size());
@@ -420,8 +421,7 @@
EXPECT_EQ(0, entry->max_comp_streams);
EXPECT_EQ(0, entry->zram_size);
EXPECT_EQ(0, entry->reserved_size);
- EXPECT_EQ("", entry->file_contents_mode);
- EXPECT_EQ("", entry->file_names_mode);
+ EXPECT_EQ("", entry->encryption_options);
EXPECT_EQ(0, entry->erase_blk_size);
EXPECT_EQ(0, entry->logical_blk_size);
EXPECT_EQ("", entry->sysfs_path);
@@ -448,8 +448,7 @@
EXPECT_EQ(0, entry->max_comp_streams);
EXPECT_EQ(0, entry->zram_size);
EXPECT_EQ(0, entry->reserved_size);
- EXPECT_EQ("", entry->file_contents_mode);
- EXPECT_EQ("", entry->file_names_mode);
+ EXPECT_EQ("", entry->encryption_options);
EXPECT_EQ(0, entry->erase_blk_size);
EXPECT_EQ(0, entry->logical_blk_size);
EXPECT_EQ("", entry->sysfs_path);
@@ -458,16 +457,14 @@
EXPECT_EQ("", entry->zram_backing_dev_path);
entry++;
- // forcefdeorfbe sets file_contents_mode and file_names_mode by default, so test it separately.
+ // forcefdeorfbe has its own encryption_options defaults, so test it separately.
EXPECT_EQ("none2", entry->mount_point);
{
FstabEntry::FsMgrFlags flags = {};
flags.force_fde_or_fbe = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
+ EXPECT_EQ("aes-256-xts:aes-256-cts", entry->encryption_options);
EXPECT_EQ("", entry->key_loc);
}
@@ -681,37 +678,21 @@
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ("/dir/key", entry->key_loc);
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
+ EXPECT_EQ("aes-256-xts:aes-256-cts", entry->encryption_options);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults fileencryption=blah
-source none1 swap defaults fileencryption=software
-source none2 swap defaults fileencryption=aes-256-xts
-source none3 swap defaults fileencryption=adiantum
-source none4 swap defaults fileencryption=adiantum:aes-256-heh
-source none5 swap defaults fileencryption=ice
-source none6 swap defaults fileencryption=ice:blah
-source none7 swap defaults fileencryption=ice:aes-256-cts
-source none8 swap defaults fileencryption=ice:aes-256-heh
-source none9 swap defaults fileencryption=ice:adiantum
-source none10 swap defaults fileencryption=aes-256-xts:aes-256-cts:v1
-source none11 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2
-source none12 swap defaults fileencryption=aes-256-xts:aes-256-cts:v2:
-source none13 swap defaults fileencryption=aes-256-xts:aes-256-cts:blah
-source none14 swap defaults fileencryption=aes-256-xts:aes-256-cts:vblah
+source none0 swap defaults fileencryption=aes-256-xts:aes-256-cts:v1
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- ASSERT_EQ(15U, fstab.size());
+ ASSERT_EQ(1U, fstab.size());
FstabEntry::FsMgrFlags flags = {};
flags.file_encryption = true;
@@ -719,107 +700,7 @@
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("", entry->file_contents_mode);
- EXPECT_EQ("", entry->file_names_mode);
- EXPECT_EQ(0, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none1", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none2", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none3", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("adiantum", entry->file_contents_mode);
- EXPECT_EQ("adiantum", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none4", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("adiantum", entry->file_contents_mode);
- EXPECT_EQ("aes-256-heh", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none5", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("ice", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none6", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("ice", entry->file_contents_mode);
- EXPECT_EQ("", entry->file_names_mode);
- EXPECT_EQ(0, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none7", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("ice", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none8", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("ice", entry->file_contents_mode);
- EXPECT_EQ("aes-256-heh", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none9", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("ice", entry->file_contents_mode);
- EXPECT_EQ("adiantum", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none10", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(1, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none11", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(2, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none12", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("", entry->file_contents_mode);
- EXPECT_EQ("", entry->file_names_mode);
- EXPECT_EQ(0, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none13", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(0, entry->file_policy_version);
-
- entry++;
- EXPECT_EQ("none14", entry->mount_point);
- EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
- EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
- EXPECT_EQ("aes-256-cts", entry->file_names_mode);
- EXPECT_EQ(0, entry->file_policy_version);
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v1", entry->encryption_options);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MaxCompStreams) {
@@ -1081,3 +962,10 @@
EXPECT_EQ("none5", entry->mount_point);
EXPECT_EQ("/dev/path2", entry->zram_backing_dev_path);
}
+
+TEST(fs_mgr, DefaultFstabContainsUserdata) {
+ Fstab fstab;
+ ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
+ ASSERT_NE(nullptr, GetEntryForMountPoint(&fstab, "/data"))
+ << "Default fstab doesn't contain /data entry";
+}
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 4f89bfb..e04f70f 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -17,6 +17,10 @@
shared_libs: [
"libutils",
"libbase",
+
+ // Need latest HealthInfo definition from headers of this shared
+ // library. Clients don't need to link to this.
+ "android.hardware.health@2.1",
],
header_libs: ["libhealthd_headers"],
export_header_lib_headers: ["libhealthd_headers"],
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 57ed362..9e168e9 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -29,10 +29,12 @@
#include <algorithm>
#include <memory>
+#include <optional>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <android/hardware/health/2.1/types.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
@@ -47,97 +49,93 @@
#define MILLION 1.0e6
#define DEFAULT_VBUS_VOLTAGE 5000000
+using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+using HealthInfo_2_0 = android::hardware::health::V2_0::HealthInfo;
+using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
+using android::hardware::health::V1_0::BatteryHealth;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V2_1::BatteryCapacityLevel;
+
namespace android {
-struct sysfsStringEnumMap {
+template <typename T>
+struct SysfsStringEnumMap {
const char* s;
- int val;
+ T val;
};
-static int mapSysfsString(const char* str,
- struct sysfsStringEnumMap map[]) {
+template <typename T>
+static std::optional<T> mapSysfsString(const char* str, SysfsStringEnumMap<T> map[]) {
for (int i = 0; map[i].s; i++)
if (!strcmp(str, map[i].s))
return map[i].val;
- return -1;
-}
-
-static void initBatteryProperties(BatteryProperties* props) {
- props->chargerAcOnline = false;
- props->chargerUsbOnline = false;
- props->chargerWirelessOnline = false;
- props->maxChargingCurrent = 0;
- props->maxChargingVoltage = 0;
- props->batteryStatus = BATTERY_STATUS_UNKNOWN;
- props->batteryHealth = BATTERY_HEALTH_UNKNOWN;
- props->batteryPresent = false;
- props->batteryLevel = 0;
- props->batteryVoltage = 0;
- props->batteryTemperature = 0;
- props->batteryCurrent = 0;
- props->batteryCycleCount = 0;
- props->batteryFullCharge = 0;
- props->batteryChargeCounter = 0;
- props->batteryTechnology.clear();
+ return std::nullopt;
}
BatteryMonitor::BatteryMonitor()
: mHealthdConfig(nullptr),
mBatteryDevicePresent(false),
mBatteryFixedCapacity(0),
- mBatteryFixedTemperature(0) {
- initBatteryProperties(&props);
+ mBatteryFixedTemperature(0),
+ mHealthInfo(std::make_unique<HealthInfo_2_1>()) {}
+
+BatteryMonitor::~BatteryMonitor() {}
+
+const HealthInfo_1_0& BatteryMonitor::getHealthInfo_1_0() const {
+ return getHealthInfo_2_0().legacy;
}
-struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor) {
- return batteryMonitor->props;
+const HealthInfo_2_0& BatteryMonitor::getHealthInfo_2_0() const {
+ return getHealthInfo_2_1().legacy;
}
-int BatteryMonitor::getBatteryStatus(const char* status) {
- int ret;
- struct sysfsStringEnumMap batteryStatusMap[] = {
- { "Unknown", BATTERY_STATUS_UNKNOWN },
- { "Charging", BATTERY_STATUS_CHARGING },
- { "Discharging", BATTERY_STATUS_DISCHARGING },
- { "Not charging", BATTERY_STATUS_NOT_CHARGING },
- { "Full", BATTERY_STATUS_FULL },
- { NULL, 0 },
+const HealthInfo_2_1& BatteryMonitor::getHealthInfo_2_1() const {
+ return *mHealthInfo;
+}
+
+BatteryStatus getBatteryStatus(const char* status) {
+ static SysfsStringEnumMap<BatteryStatus> batteryStatusMap[] = {
+ {"Unknown", BatteryStatus::UNKNOWN},
+ {"Charging", BatteryStatus::CHARGING},
+ {"Discharging", BatteryStatus::DISCHARGING},
+ {"Not charging", BatteryStatus::NOT_CHARGING},
+ {"Full", BatteryStatus::FULL},
+ {NULL, BatteryStatus::UNKNOWN},
};
- ret = mapSysfsString(status, batteryStatusMap);
- if (ret < 0) {
+ auto ret = mapSysfsString(status, batteryStatusMap);
+ if (!ret) {
KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
- ret = BATTERY_STATUS_UNKNOWN;
+ *ret = BatteryStatus::UNKNOWN;
}
- return ret;
+ return *ret;
}
-int BatteryMonitor::getBatteryHealth(const char* status) {
- int ret;
- struct sysfsStringEnumMap batteryHealthMap[] = {
- { "Unknown", BATTERY_HEALTH_UNKNOWN },
- { "Good", BATTERY_HEALTH_GOOD },
- { "Overheat", BATTERY_HEALTH_OVERHEAT },
- { "Dead", BATTERY_HEALTH_DEAD },
- { "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
- { "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
- { "Cold", BATTERY_HEALTH_COLD },
- // battery health values from JEITA spec
- { "Warm", BATTERY_HEALTH_GOOD },
- { "Cool", BATTERY_HEALTH_GOOD },
- { "Hot", BATTERY_HEALTH_OVERHEAT },
- { NULL, 0 },
+BatteryHealth getBatteryHealth(const char* status) {
+ static SysfsStringEnumMap<BatteryHealth> batteryHealthMap[] = {
+ {"Unknown", BatteryHealth::UNKNOWN},
+ {"Good", BatteryHealth::GOOD},
+ {"Overheat", BatteryHealth::OVERHEAT},
+ {"Dead", BatteryHealth::DEAD},
+ {"Over voltage", BatteryHealth::OVER_VOLTAGE},
+ {"Unspecified failure", BatteryHealth::UNSPECIFIED_FAILURE},
+ {"Cold", BatteryHealth::COLD},
+ // battery health values from JEITA spec
+ {"Warm", BatteryHealth::GOOD},
+ {"Cool", BatteryHealth::GOOD},
+ {"Hot", BatteryHealth::OVERHEAT},
+ {NULL, BatteryHealth::UNKNOWN},
};
- ret = mapSysfsString(status, batteryHealthMap);
- if (ret < 0) {
+ auto ret = mapSysfsString(status, batteryHealthMap);
+ if (!ret) {
KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
- ret = BATTERY_HEALTH_UNKNOWN;
+ *ret = BatteryHealth::UNKNOWN;
}
- return ret;
+ return *ret;
}
int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
@@ -148,35 +146,34 @@
}
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
- std::string buf;
- int ret;
- struct sysfsStringEnumMap supplyTypeMap[] = {
- { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
- { "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
- { "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
- { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC },
- { "USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB },
- { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
- { NULL, 0 },
+ static SysfsStringEnumMap<int> supplyTypeMap[] = {
+ {"Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN},
+ {"Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY},
+ {"UPS", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"Mains", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB", ANDROID_POWER_SUPPLY_TYPE_USB},
+ {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
+ {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
+ {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
+ {NULL, 0},
};
+ std::string buf;
if (readFromFile(path, &buf) <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- ret = mapSysfsString(buf.c_str(), supplyTypeMap);
+ auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
if (ret < 0) {
KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
- ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+ *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
- return static_cast<BatteryMonitor::PowerSupplyType>(ret);
+ return static_cast<BatteryMonitor::PowerSupplyType>(*ret);
}
bool BatteryMonitor::getBooleanField(const String8& path) {
@@ -201,7 +198,9 @@
}
void BatteryMonitor::updateValues(void) {
- initBatteryProperties(&props);
+ *mHealthInfo = HealthInfo_2_1{};
+
+ HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
@@ -225,6 +224,15 @@
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
+ if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
+ mHealthInfo->legacy.batteryCurrentAverage =
+ getIntField(mHealthdConfig->batteryCurrentAvgPath);
+
+ // TODO(b/142260281): Retrieve these values correctly.
+ mHealthInfo->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+ mHealthInfo->batteryChargeTimeToFullNowSeconds = 0;
+ mHealthInfo->batteryFullCapacityUah = props.batteryFullCharge;
+
props.batteryTemperature = mBatteryFixedTemperature ?
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
@@ -292,6 +300,7 @@
void BatteryMonitor::logValues(void) {
char dmesgline[256];
size_t len;
+ const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
@@ -325,18 +334,19 @@
}
bool BatteryMonitor::isChargerOnline() {
+ const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
return props.chargerAcOnline | props.chargerUsbOnline |
props.chargerWirelessOnline;
}
int BatteryMonitor::getChargeStatus() {
- int result = BATTERY_STATUS_UNKNOWN;
+ BatteryStatus result = BatteryStatus::UNKNOWN;
if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
std::string buf;
if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
result = getBatteryStatus(buf.c_str());
}
- return result;
+ return static_cast<int>(result);
}
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
@@ -409,6 +419,7 @@
void BatteryMonitor::dumpState(int fd) {
int v;
char vs[128];
+ const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
props.chargerAcOnline, props.chargerUsbOnline,
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 0fd3824..d41a374 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -17,6 +17,8 @@
#ifndef HEALTHD_BATTERYMONITOR_H
#define HEALTHD_BATTERYMONITOR_H
+#include <memory>
+
#include <batteryservice/BatteryService.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -24,6 +26,19 @@
#include <healthd/healthd.h>
namespace android {
+namespace hardware {
+namespace health {
+namespace V1_0 {
+struct HealthInfo;
+} // namespace V1_0
+namespace V2_0 {
+struct HealthInfo;
+} // namespace V2_0
+namespace V2_1 {
+struct HealthInfo;
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
class BatteryMonitor {
public:
@@ -37,11 +52,15 @@
};
BatteryMonitor();
+ ~BatteryMonitor();
void init(struct healthd_config *hc);
int getChargeStatus();
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
- friend struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor);
+
+ const android::hardware::health::V1_0::HealthInfo& getHealthInfo_1_0() const;
+ const android::hardware::health::V2_0::HealthInfo& getHealthInfo_2_0() const;
+ const android::hardware::health::V2_1::HealthInfo& getHealthInfo_2_1() const;
void updateValues(void);
void logValues(void);
@@ -53,10 +72,8 @@
bool mBatteryDevicePresent;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
- struct BatteryProperties props;
+ std::unique_ptr<android::hardware::health::V2_1::HealthInfo> mHealthInfo;
- int getBatteryStatus(const char* status);
- int getBatteryHealth(const char* status);
int readFromFile(const String8& path, std::string* buf);
PowerSupplyType readPowerSupplyType(const String8& path);
bool getBooleanField(const String8& path);
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2f2ead0..b2c6461 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -42,6 +42,8 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <memory>
+
#include <ApexProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
@@ -627,6 +629,8 @@
return Error() << "Invalid code: " << code;
}
+static int initial_mount_fstab_return_code = -1;
+
/* mount_all <fstab> [ <path> ]* [--<options>]*
*
* This function might request a reboot, in which case it will
@@ -662,6 +666,7 @@
if (!ReadFstabFromFile(fstab_file, &fstab)) {
return Error() << "Could not read fstab";
}
+
auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
property_set(prop_name, std::to_string(t.duration().count()));
@@ -673,6 +678,7 @@
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
+ initial_mount_fstab_return_code = mount_fstab_return_code;
auto queue_fs_result = queue_fs_event(mount_fstab_return_code);
if (!queue_fs_result) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
@@ -1132,6 +1138,25 @@
return ExecWithFunctionOnFailure(args, reboot);
}
+static Result<void> do_remount_userdata(const BuiltinArguments& args) {
+ if (initial_mount_fstab_return_code == -1) {
+ return Error() << "Calling remount_userdata too early";
+ }
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ // TODO(b/135984674): should we reboot here?
+ return Error() << "Failed to read fstab";
+ }
+ // TODO(b/135984674): check that fstab contains /data.
+ if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
+ TriggerShutdown("reboot,mount-userdata-failed");
+ }
+ if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result) {
+ return Error() << "queue_fs_event() failed: " << result.error();
+ }
+ return {};
+}
+
static Result<void> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return {};
@@ -1243,6 +1268,7 @@
{"umount", {1, 1, {false, do_umount}}},
{"umount_all", {1, 1, {false, do_umount_all}}},
{"readahead", {1, 2, {true, do_readahead}}},
+ {"remount_userdata", {0, 0, {false, do_remount_userdata}}},
{"restart", {1, 1, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d453655..fc18ecb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -181,10 +181,17 @@
}
}
-static void ShutdownVold() {
+static Result<void> ShutdownVold() {
const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
int status;
- logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true, nullptr);
+ if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
+ nullptr) != 0) {
+ return ErrnoError() << "Failed to call 'vdc volume shutdown'";
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return {};
+ }
+ return Error() << "'vdc volume shutdown' failed : " << status;
}
static void LogShutdownTime(UmountStat stat, Timer* t) {
@@ -427,11 +434,11 @@
#define ZRAM_DEVICE "/dev/block/zram0"
#define ZRAM_RESET "/sys/block/zram0/reset"
#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
-static void KillZramBackingDevice() {
+static Result<void> KillZramBackingDevice() {
std::string backing_dev;
- if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
+ if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return {};
- if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
+ if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return {};
// cut the last "\n"
backing_dev.erase(backing_dev.length() - 1);
@@ -440,28 +447,29 @@
Timer swap_timer;
LOG(INFO) << "swapoff() start...";
if (swapoff(ZRAM_DEVICE) == -1) {
- LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: swapoff (" << backing_dev << ")"
+ << " failed";
}
LOG(INFO) << "swapoff() took " << swap_timer;;
if (!WriteStringToFile("1", ZRAM_RESET)) {
- LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
- return;
+ return Error() << "zram_backing_dev: reset (" << backing_dev << ")"
+ << " failed";
}
// clear loopback device
unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
if (loop.get() < 0) {
- LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: open(" << backing_dev << ")"
+ << " failed";
}
if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
- LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: loop_clear (" << backing_dev << ")"
+ << " failed";
}
LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
+ return {};
}
// Stops given services, waits for them to be stopped for |timeout| ms.
@@ -738,7 +746,23 @@
// TODO(b/135984674): store information about offending services for debugging.
return Error() << r << " post-data services are still running";
}
- // TODO(b/135984674): remount userdata
+ // We only really need to restart vold if userdata is ext4 filesystem.
+ // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
+ // First shutdown volumes managed by vold. They will be recreated by
+ // system_server.
+ Service* vold_service = ServiceList::GetInstance().FindService("vold");
+ if (vold_service != nullptr && vold_service->IsRunning()) {
+ if (auto result = ShutdownVold(); !result) {
+ return result;
+ }
+ LOG(INFO) << "Restarting vold";
+ vold_service->Restart();
+ }
+ // Again, we only need to kill zram backing device in case of ext4 userdata.
+ // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
+ if (auto result = KillZramBackingDevice(); !result) {
+ return result;
+ }
if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
false /* SIGKILL */);
r > 0) {
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2251479..667bddc 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -175,7 +175,7 @@
}
cc_binary {
- name: "unzip",
+ name: "ziptool",
defaults: ["libziparchive_flags"],
srcs: ["unzip.cpp"],
shared_libs: [
@@ -183,6 +183,12 @@
"libziparchive",
],
recovery_available: true,
+ host_supported: true,
+ target: {
+ android: {
+ symlinks: ["unzip", "zipinfo"],
+ },
+ },
}
cc_fuzz {
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 391cff9..f0f5a1d 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -79,6 +79,12 @@
// The offset to the start of data for this ZipEntry.
off64_t offset;
+
+ // The version of zip and the host file system this came from.
+ uint16_t version_made_by;
+
+ // Whether this entry is believed to be text or binary.
+ bool is_text;
};
struct ZipArchive;
@@ -125,6 +131,19 @@
*/
void CloseArchive(ZipArchiveHandle archive);
+/** See GetArchiveInfo(). */
+struct ZipArchiveInfo {
+ /** The size in bytes of the archive itself. Used by zipinfo. */
+ off64_t archive_size;
+ /** The number of entries in the archive. */
+ size_t entry_count;
+};
+
+/**
+ * Returns information about the given archive.
+ */
+ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive);
+
/*
* Find an entry in the Zip archive, by name. |data| must be non-null.
*
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 426325e..e936614 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -40,12 +40,15 @@
kPrompt,
};
+static bool is_unzip;
static OverwriteMode overwrite_mode = kPrompt;
+static bool flag_1 = false;
static const char* flag_d = nullptr;
static bool flag_l = false;
static bool flag_p = false;
static bool flag_q = false;
static bool flag_v = false;
+static bool flag_x = false;
static const char* archive_name = nullptr;
static std::set<std::string> includes;
static std::set<std::string> excludes;
@@ -88,32 +91,51 @@
return static_cast<int>((100LL * (uncompressed - compressed)) / uncompressed);
}
-static void MaybeShowHeader() {
- if (!flag_q) printf("Archive: %s\n", archive_name);
- if (flag_v) {
- printf(
- " Length Method Size Cmpr Date Time CRC-32 Name\n"
- "-------- ------ ------- ---- ---------- ----- -------- ----\n");
- } else if (flag_l) {
- printf(
- " Length Date Time Name\n"
- "--------- ---------- ----- ----\n");
+static void MaybeShowHeader(ZipArchiveHandle zah) {
+ if (is_unzip) {
+ // unzip has three formats.
+ if (!flag_q) printf("Archive: %s\n", archive_name);
+ if (flag_v) {
+ printf(
+ " Length Method Size Cmpr Date Time CRC-32 Name\n"
+ "-------- ------ ------- ---- ---------- ----- -------- ----\n");
+ } else if (flag_l) {
+ printf(
+ " Length Date Time Name\n"
+ "--------- ---------- ----- ----\n");
+ }
+ } else {
+ // zipinfo.
+ if (!flag_1 && includes.empty() && excludes.empty()) {
+ ZipArchiveInfo info{GetArchiveInfo(zah)};
+ printf("Archive: %s\n", archive_name);
+ printf("Zip file size: %" PRId64 " bytes, number of entries: %zu\n", info.archive_size,
+ info.entry_count);
+ }
}
}
static void MaybeShowFooter() {
- if (flag_v) {
- printf(
- "-------- ------- --- -------\n"
- "%8" PRId64 " %8" PRId64 " %3d%% %zu file%s\n",
- total_uncompressed_length, total_compressed_length,
- CompressionRatio(total_uncompressed_length, total_compressed_length), file_count,
- (file_count == 1) ? "" : "s");
- } else if (flag_l) {
- printf(
- "--------- -------\n"
- "%9" PRId64 " %zu file%s\n",
- total_uncompressed_length, file_count, (file_count == 1) ? "" : "s");
+ if (is_unzip) {
+ if (flag_v) {
+ printf(
+ "-------- ------- --- -------\n"
+ "%8" PRId64 " %8" PRId64 " %3d%% %zu file%s\n",
+ total_uncompressed_length, total_compressed_length,
+ CompressionRatio(total_uncompressed_length, total_compressed_length), file_count,
+ (file_count == 1) ? "" : "s");
+ } else if (flag_l) {
+ printf(
+ "--------- -------\n"
+ "%9" PRId64 " %zu file%s\n",
+ total_uncompressed_length, file_count, (file_count == 1) ? "" : "s");
+ }
+ } else {
+ if (!flag_1 && includes.empty() && excludes.empty()) {
+ printf("%zu files, %" PRId64 " bytes uncompressed, %" PRId64 " bytes compressed: %3d%%\n",
+ file_count, total_uncompressed_length, total_compressed_length,
+ CompressionRatio(total_uncompressed_length, total_compressed_length));
+ }
}
}
@@ -226,17 +248,61 @@
}
}
+static void InfoOne(const ZipEntry& entry, const std::string& name) {
+ if (flag_1) {
+ // "android-ndk-r19b/sources/android/NOTICE"
+ printf("%s\n", name.c_str());
+ return;
+ }
+
+ int version = entry.version_made_by & 0xff;
+ int os = (entry.version_made_by >> 8) & 0xff;
+
+ // TODO: Support suid/sgid? Non-Unix host file system attributes?
+ char mode[] = "??????????";
+ if (os == 3) {
+ mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?');
+ mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-';
+ mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-';
+ mode[3] = entry.unix_mode & S_IXUSR ? 'x' : '-';
+ mode[4] = entry.unix_mode & S_IRGRP ? 'r' : '-';
+ mode[5] = entry.unix_mode & S_IWGRP ? 'w' : '-';
+ mode[6] = entry.unix_mode & S_IXGRP ? 'x' : '-';
+ mode[7] = entry.unix_mode & S_IROTH ? 'r' : '-';
+ mode[8] = entry.unix_mode & S_IWOTH ? 'w' : '-';
+ mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-';
+ }
+
+ // TODO: zipinfo (unlike unzip) sometimes uses time zone?
+ // TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it.
+ tm t = entry.GetModificationTime();
+ char time[32];
+ snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
+ t.tm_mday, t.tm_hour, t.tm_min);
+
+ // "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE"
+ printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10,
+ os == 3 ? "unx" : "???", entry.uncompressed_length, entry.is_text ? 't' : 'b',
+ entry.has_data_descriptor ? 'X' : 'x', entry.method == kCompressStored ? "stor" : "defX",
+ time, name.c_str());
+}
+
static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
- if (flag_l || flag_v) {
- // -l or -lv or -lq or -v.
- ListOne(entry, name);
- } else {
- // Actually extract.
- if (flag_p) {
- ExtractToPipe(zah, entry, name);
+ if (is_unzip) {
+ if (flag_l || flag_v) {
+ // -l or -lv or -lq or -v.
+ ListOne(entry, name);
} else {
- ExtractOne(zah, entry, name);
+ // Actually extract.
+ if (flag_p) {
+ ExtractToPipe(zah, entry, name);
+ } else {
+ ExtractOne(zah, entry, name);
+ }
}
+ } else {
+ // zipinfo or zipinfo -1.
+ InfoOne(entry, name);
}
total_uncompressed_length += entry.uncompressed_length;
total_compressed_length += entry.compressed_length;
@@ -244,7 +310,7 @@
}
static void ProcessAll(ZipArchiveHandle zah) {
- MaybeShowHeader();
+ MaybeShowHeader(zah);
// libziparchive iteration order doesn't match the central directory.
// We could sort, but that would cost extra and wouldn't match either.
@@ -267,73 +333,110 @@
}
static void ShowHelp(bool full) {
- fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
- if (!full) exit(EXIT_FAILURE);
+ if (is_unzip) {
+ fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
+ if (!full) exit(EXIT_FAILURE);
- printf(
- "\n"
- "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
- "exclude (-x) lists use shell glob patterns.\n"
- "\n"
- "-d DIR Extract into DIR\n"
- "-l List contents (-lq excludes archive name, -lv is verbose)\n"
- "-n Never overwrite files (default: prompt)\n"
- "-o Always overwrite files\n"
- "-p Pipe to stdout\n"
- "-q Quiet\n"
- "-v List contents verbosely\n"
- "-x FILE Exclude files\n");
+ printf(
+ "\n"
+ "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
+ "exclude (-x) lists use shell glob patterns.\n"
+ "\n"
+ "-d DIR Extract into DIR\n"
+ "-l List contents (-lq excludes archive name, -lv is verbose)\n"
+ "-n Never overwrite files (default: prompt)\n"
+ "-o Always overwrite files\n"
+ "-p Pipe to stdout\n"
+ "-q Quiet\n"
+ "-v List contents verbosely\n"
+ "-x FILE Exclude files\n");
+ } else {
+ fprintf(full ? stdout : stderr, "usage: zipinfo [-1] ZIP [FILE...] [-x FILE...]\n");
+ if (!full) exit(EXIT_FAILURE);
+
+ printf(
+ "\n"
+ "Show information about FILEs from ZIP archive. Default is all files.\n"
+ "Both the include and exclude (-x) lists use shell glob patterns.\n"
+ "\n"
+ "-1 Show filenames only, one per line\n"
+ "-x FILE Exclude files\n");
+ }
exit(EXIT_SUCCESS);
}
+static void HandleCommonOption(int opt) {
+ switch (opt) {
+ case 'h':
+ ShowHelp(true);
+ break;
+ case 'x':
+ flag_x = true;
+ break;
+ case 1:
+ // -x swallows all following arguments, so we use '-' in the getopt
+ // string and collect files here.
+ if (!archive_name) {
+ archive_name = optarg;
+ } else if (flag_x) {
+ excludes.insert(optarg);
+ } else {
+ includes.insert(optarg);
+ }
+ break;
+ default:
+ ShowHelp(false);
+ break;
+ }
+}
+
int main(int argc, char* argv[]) {
static struct option opts[] = {
{"help", no_argument, 0, 'h'},
};
- bool saw_x = false;
- int opt;
- while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
- switch (opt) {
- case 'd':
- flag_d = optarg;
- break;
- case 'h':
- ShowHelp(true);
- break;
- case 'l':
- flag_l = true;
- break;
- case 'n':
- overwrite_mode = kNever;
- break;
- case 'o':
- overwrite_mode = kAlways;
- break;
- case 'p':
- flag_p = flag_q = true;
- break;
- case 'q':
- flag_q = true;
- break;
- case 'v':
- flag_v = true;
- break;
- case 'x':
- saw_x = true;
- break;
- case 1:
- // -x swallows all following arguments, so we use '-' in the getopt
- // string and collect files here.
- if (!archive_name) {
- archive_name = optarg;
- } else if (saw_x) {
- excludes.insert(optarg);
- } else {
- includes.insert(optarg);
- }
- break;
- default:
- ShowHelp(false);
+
+ is_unzip = !strcmp(basename(argv[0]), "unzip");
+ if (is_unzip) {
+ int opt;
+ while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
+ switch (opt) {
+ case 'd':
+ flag_d = optarg;
+ break;
+ case 'l':
+ flag_l = true;
+ break;
+ case 'n':
+ overwrite_mode = kNever;
+ break;
+ case 'o':
+ overwrite_mode = kAlways;
+ break;
+ case 'p':
+ flag_p = flag_q = true;
+ break;
+ case 'q':
+ flag_q = true;
+ break;
+ case 'v':
+ flag_v = true;
+ break;
+ default:
+ HandleCommonOption(opt);
+ break;
+ }
+ }
+ } else {
+ int opt;
+ while ((opt = getopt_long(argc, argv, "-1hx", opts, nullptr)) != -1) {
+ switch (opt) {
+ case '1':
+ flag_1 = true;
+ break;
+ default:
+ HandleCommonOption(opt);
+ break;
+ }
}
}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 3a552d8..caf8fae 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -478,6 +478,13 @@
return OpenArchiveInternal(archive, debug_file_name);
}
+ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive) {
+ ZipArchiveInfo result;
+ result.archive_size = archive->mapped_zip.GetFileLength();
+ result.entry_count = archive->num_entries;
+ return result;
+}
+
/*
* Close a ZipArchive, closing the file and freeing the contents.
*/
@@ -614,12 +621,17 @@
}
// 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3.
- if ((cdr->version_made_by >> 8) == 3) {
+ data->version_made_by = cdr->version_made_by;
+ if ((data->version_made_by >> 8) == 3) {
data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff;
} else {
data->unix_mode = 0777;
}
+ // 4.4.14: the lowest bit of the internal file attributes field indicates text.
+ // Currently only needed to implement zipinfo.
+ data->is_text = (cdr->internal_file_attributes & 1);
+
// Check that the local file header name matches the declared
// name in the central directory.
if (lfh->file_name_length != nameLen) {
diff --git a/logcat/Android.bp b/logcat/Android.bp
index e6b0c7d..e472d08 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -21,6 +21,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
],
shared_libs: [
"libbase",
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f164a12..1517c33 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -16,16 +16,12 @@
#include "logcat.h"
-#include <android-base/macros.h>
-#include <arpa/inet.h>
-#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <math.h>
-#include <pthread.h>
#include <sched.h>
#include <stdarg.h>
#include <stdio.h>
@@ -34,13 +30,11 @@
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-#include <atomic>
#include <memory>
#include <regex>
#include <string>
@@ -48,10 +42,11 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/sockets.h>
+#include <android-base/unique_fd.h>
#include <log/event_tag_map.h>
#include <log/logprint.h>
#include <private/android_logger.h>
@@ -60,6 +55,8 @@
#define DEFAULT_MAX_ROTATED_LOGS 4
+using android::base::StringPrintf;
+
struct log_device_t {
const char* device;
bool binary;
@@ -79,85 +76,51 @@
}
};
-struct android_logcat_context_internal {
- // status
- volatile std::atomic_int retval; // valid if thread_stopped set
- // Arguments passed in, or copies and storage thereof if a thread.
- int argc;
- char* const* argv;
- char* const* envp;
- std::vector<std::string> args;
- std::vector<const char*> argv_hold;
- std::vector<std::string> envs;
- std::vector<const char*> envp_hold;
- int output_fd; // duplication of fileno(output) (below)
- int error_fd; // duplication of fileno(error) (below)
+class Logcat {
+ public:
+ ~Logcat();
- // library
- int fds[2]; // From popen call
- FILE* output; // everything writes to fileno(output), buffer unused
- FILE* error; // unless error == output.
- pthread_t thr;
- volatile std::atomic_bool stop; // quick exit flag
- volatile std::atomic_bool thread_stopped;
- bool stderr_null; // shell "2>/dev/null"
- bool stderr_stdout; // shell "2>&1"
+ int Run(int argc, char** argv);
- // global variables
- AndroidLogFormat* logformat;
- const char* outputFileName;
+ private:
+ void RotateLogs();
+ void ProcessBuffer(log_device_t* dev, struct log_msg* buf);
+ void MaybePrintStart(log_device_t* dev, bool print_dividers);
+ void SetupOutputAndSchedulingPolicy(bool blocking);
+ int SetLogFormat(const char* format_string);
+
+ android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
+ std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
+ android_log_format_new(), &android_log_format_free};
+ const char* output_file_name_ = nullptr;
// 0 means "no log rotation"
- size_t logRotateSizeKBytes;
+ size_t log_rotate_size_kb_ = 0;
// 0 means "unbounded"
- size_t maxRotatedLogs;
- size_t outByteCount;
- int printBinary;
- int devCount; // >1 means multiple
- std::unique_ptr<std::regex> regex;
- log_device_t* devices;
- EventTagMap* eventTagMap;
+ size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS;
+ size_t out_byte_count_ = 0;
+ int print_binary_ = 0;
+ int dev_count_ = 0; // >1 means multiple
+ std::unique_ptr<std::regex> regex_;
+ log_device_t* devices_ = nullptr;
+ std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
+ nullptr, &android_closeEventTagMap};
// 0 means "infinite"
- size_t maxCount;
- size_t printCount;
+ size_t max_count_ = 0;
+ size_t print_count_ = 0;
- bool printItAnyways;
- bool debug;
- bool hasOpenedEventTagMap;
+ bool print_it_anyways_ = false;
+ bool debug_ = false;
+ bool has_opened_event_tag_map_ = false;
};
-// Creates a context associated with this logcat instance
-android_logcat_context create_android_logcat() {
- android_logcat_context_internal* context;
-
- context = (android_logcat_context_internal*)calloc(
- 1, sizeof(android_logcat_context_internal));
- if (!context) return nullptr;
-
- context->fds[0] = -1;
- context->fds[1] = -1;
- context->output_fd = -1;
- context->error_fd = -1;
- context->maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
-
- context->argv_hold.clear();
- context->args.clear();
- context->envp_hold.clear();
- context->envs.clear();
-
- return (android_logcat_context)context;
-}
-
// logd prefixes records with a length field
#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
-namespace android {
-
enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
-// if showHelp is set, newline required in fmt statement to transition to usage
-static void logcat_panic(android_logcat_context_internal* context,
- enum helpType showHelp, const char* fmt, ...)
- __printflike(3, 4);
+// if show_help is set, newline required in fmt statement to transition to usage
+static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) __printflike(2, 3)
+ __attribute__((__noreturn__));
#ifndef F2FS_IOC_SET_PIN_FILE
#define F2FS_IOCTL_MAGIC 0xf5
@@ -165,7 +128,7 @@
#endif
static int openLogFile(const char* pathname, size_t sizeKB) {
- int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
+ int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd < 0) {
return fd;
}
@@ -177,107 +140,29 @@
return fd;
}
-static void close_output(android_logcat_context_internal* context) {
- // split output_from_error
- if (context->error == context->output) {
- context->output = nullptr;
- context->output_fd = -1;
- }
- if (context->error && (context->output_fd == fileno(context->error))) {
- context->output_fd = -1;
- }
- if (context->output_fd == context->error_fd) {
- context->output_fd = -1;
- }
- // close output channel
- if (context->output) {
- if (context->output != stdout) {
- if (context->output_fd == fileno(context->output)) {
- context->output_fd = -1;
- }
- if (context->fds[1] == fileno(context->output)) {
- context->fds[1] = -1;
- }
- fclose(context->output);
- }
- context->output = nullptr;
- }
- if (context->output_fd >= 0) {
- if (context->output_fd != fileno(stdout)) {
- if (context->fds[1] == context->output_fd) {
- context->fds[1] = -1;
- }
- posix_fadvise(context->output_fd, 0, 0, POSIX_FADV_DONTNEED);
- close(context->output_fd);
- }
- context->output_fd = -1;
- }
-}
-
-static void close_error(android_logcat_context_internal* context) {
- // split error_from_output
- if (context->output == context->error) {
- context->error = nullptr;
- context->error_fd = -1;
- }
- if (context->output && (context->error_fd == fileno(context->output))) {
- context->error_fd = -1;
- }
- if (context->error_fd == context->output_fd) {
- context->error_fd = -1;
- }
- // close error channel
- if (context->error) {
- if ((context->error != stderr) && (context->error != stdout)) {
- if (context->error_fd == fileno(context->error)) {
- context->error_fd = -1;
- }
- if (context->fds[1] == fileno(context->error)) {
- context->fds[1] = -1;
- }
- fclose(context->error);
- }
- context->error = nullptr;
- }
- if (context->error_fd >= 0) {
- if ((context->error_fd != fileno(stdout)) &&
- (context->error_fd != fileno(stderr))) {
- if (context->fds[1] == context->error_fd) context->fds[1] = -1;
- close(context->error_fd);
- }
- context->error_fd = -1;
- }
-}
-
-static void rotateLogs(android_logcat_context_internal* context) {
- int err;
-
+void Logcat::RotateLogs() {
// Can't rotate logs if we're not outputting to a file
- if (!context->outputFileName) return;
+ if (!output_file_name_) return;
- close_output(context);
+ output_fd_.reset();
// Compute the maximum number of digits needed to count up to
// maxRotatedLogs in decimal. eg:
// maxRotatedLogs == 30
// -> log10(30) == 1.477
// -> maxRotationCountDigits == 2
- int maxRotationCountDigits =
- (context->maxRotatedLogs > 0)
- ? (int)(floor(log10(context->maxRotatedLogs) + 1))
- : 0;
+ int max_rotation_count_digits =
+ max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
- for (int i = context->maxRotatedLogs; i > 0; i--) {
- std::string file1 = android::base::StringPrintf(
- "%s.%.*d", context->outputFileName, maxRotationCountDigits, i);
+ for (int i = max_rotated_logs_; i > 0; i--) {
+ std::string file1 =
+ StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
std::string file0;
if (!(i - 1)) {
- file0 = android::base::StringPrintf("%s", context->outputFileName);
+ file0 = output_file_name_;
} else {
- file0 =
- android::base::StringPrintf("%s.%.*d", context->outputFileName,
- maxRotationCountDigits, i - 1);
+ file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
}
if (!file0.length() || !file1.length()) {
@@ -285,169 +170,123 @@
break;
}
- err = rename(file0.c_str(), file1.c_str());
+ int err = rename(file0.c_str(), file1.c_str());
if (err < 0 && errno != ENOENT) {
perror("while rotating log files");
}
}
- context->output_fd = openLogFile(context->outputFileName, context->logRotateSizeKBytes);
+ output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
- if (context->output_fd < 0) {
- logcat_panic(context, HELP_FALSE, "couldn't open output file");
- return;
- }
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- logcat_panic(context, HELP_FALSE, "couldn't fdopen output file");
- return;
- }
- if (context->stderr_stdout) {
- close_error(context);
- context->error = context->output;
- context->error_fd = context->output_fd;
+ if (!output_fd_.ok()) {
+ LogcatPanic(HELP_FALSE, "couldn't open output file");
}
- context->outByteCount = 0;
+ out_byte_count_ = 0;
}
-void printBinary(android_logcat_context_internal* context, struct log_msg* buf) {
- size_t size = buf->len();
-
- TEMP_FAILURE_RETRY(write(context->output_fd, buf, size));
-}
-
-static bool regexOk(android_logcat_context_internal* context,
- const AndroidLogEntry& entry) {
- if (!context->regex) return true;
-
- return std::regex_search(entry.message, entry.message + entry.messageLen, *context->regex);
-}
-
-static void processBuffer(android_logcat_context_internal* context,
- log_device_t* dev, struct log_msg* buf) {
+void Logcat::ProcessBuffer(log_device_t* dev, struct log_msg* buf) {
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
if (dev->binary) {
- if (!context->eventTagMap && !context->hasOpenedEventTagMap) {
- context->eventTagMap = android_openEventTagMap(nullptr);
- context->hasOpenedEventTagMap = true;
+ if (!event_tag_map_ && !has_opened_event_tag_map_) {
+ event_tag_map_.reset(android_openEventTagMap(nullptr));
+ has_opened_event_tag_map_ = true;
}
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, context->eventTagMap,
+ err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
binaryMsgBuf, sizeof(binaryMsgBuf));
// printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
err = android_log_processLogBuffer(&buf->entry, &entry);
}
- if ((err < 0) && !context->debug) return;
+ if (err < 0 && !debug_) return;
- if (android_log_shouldPrintLine(
- context->logformat, std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = regexOk(context, entry);
+ if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
+ entry.priority)) {
+ bool match = !regex_ ||
+ std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
- context->printCount += match;
- if (match || context->printItAnyways) {
- bytesWritten = android_log_printLogLine(context->logformat,
- context->output_fd, &entry);
+ print_count_ += match;
+ if (match || print_it_anyways_) {
+ bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
if (bytesWritten < 0) {
- logcat_panic(context, HELP_FALSE, "output error");
- return;
+ LogcatPanic(HELP_FALSE, "output error");
}
}
}
- context->outByteCount += bytesWritten;
+ out_byte_count_ += bytesWritten;
- if (context->logRotateSizeKBytes > 0 &&
- (context->outByteCount / 1024) >= context->logRotateSizeKBytes) {
- rotateLogs(context);
+ if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
+ RotateLogs();
}
}
-static void maybePrintStart(android_logcat_context_internal* context,
- log_device_t* dev, bool printDividers) {
- if (!dev->printed || printDividers) {
- if (context->devCount > 1 && !context->printBinary) {
- char buf[1024];
- snprintf(buf, sizeof(buf), "--------- %s %s\n",
- dev->printed ? "switch to" : "beginning of", dev->device);
- if (write(context->output_fd, buf, strlen(buf)) < 0) {
- logcat_panic(context, HELP_FALSE, "output error");
- return;
+void Logcat::MaybePrintStart(log_device_t* dev, bool print_dividers) {
+ if (!dev->printed || print_dividers) {
+ if (dev_count_ > 1 && !print_binary_) {
+ if (dprintf(output_fd_.get(), "--------- %s %s\n",
+ dev->printed ? "switch to" : "beginning of", dev->device) < 0) {
+ LogcatPanic(HELP_FALSE, "output error");
}
}
dev->printed = true;
}
}
-static void setupOutputAndSchedulingPolicy(
- android_logcat_context_internal* context, bool blocking) {
- if (!context->outputFileName) return;
+void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
+ if (!output_file_name_) return;
if (blocking) {
// Lower priority and set to batch scheduling if we are saving
// the logs into files and taking continuous content.
- if ((set_sched_policy(0, SP_BACKGROUND) < 0) && context->error) {
- fprintf(context->error,
- "failed to set background scheduling policy\n");
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+ fprintf(stderr, "failed to set background scheduling policy\n");
}
- struct sched_param param;
- memset(¶m, 0, sizeof(param));
+ struct sched_param param = {};
if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
fprintf(stderr, "failed to set to batch scheduler\n");
}
- if ((setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) &&
- context->error) {
- fprintf(context->error, "failed set to priority\n");
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ fprintf(stderr, "failed set to priority\n");
}
}
- close_output(context);
+ output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
- context->output_fd = openLogFile(context->outputFileName, context->logRotateSizeKBytes);
-
- if (context->output_fd < 0) {
- logcat_panic(context, HELP_FALSE, "couldn't open output file");
- return;
+ if (!output_fd_.ok()) {
+ LogcatPanic(HELP_FALSE, "couldn't open output file");
}
struct stat statbuf;
- if (fstat(context->output_fd, &statbuf) == -1) {
- close_output(context);
- logcat_panic(context, HELP_FALSE, "couldn't get output file stat\n");
- return;
+ if (fstat(output_fd_.get(), &statbuf) == -1) {
+ output_fd_.reset();
+ LogcatPanic(HELP_FALSE, "couldn't get output file stat\n");
}
if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- close_output(context);
- logcat_panic(context, HELP_FALSE, "invalid output file stat\n");
- return;
+ output_fd_.reset();
+ LogcatPanic(HELP_FALSE, "invalid output file stat\n");
}
- context->output = fdopen(context->output_fd, "web");
-
- context->outByteCount = statbuf.st_size;
+ out_byte_count_ = statbuf.st_size;
}
// clang-format off
-static void show_help(android_logcat_context_internal* context) {
- if (!context->error) return;
+static void show_help() {
+ const char* cmd = getprogname();
- const char* cmd = strrchr(context->argv[0], '/');
- cmd = cmd ? cmd + 1 : context->argv[0];
+ fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
- fprintf(context->error, "Usage: %s [options] [filterspecs]\n", cmd);
-
- fprintf(context->error, "options include:\n"
+ fprintf(stderr, "options include:\n"
" -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
" -f <file>, --file=<file> Log to file. Default is stdout\n"
" -r <kbytes>, --rotate-kbytes=<kbytes>\n"
@@ -514,7 +353,7 @@
" comes first. Improves efficiency of polling by providing\n"
" an about-to-wrap wakeup.\n");
- fprintf(context->error, "\nfilterspecs are a series of \n"
+ fprintf(stderr, "\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
"where <tag> is a log component tag (or * for all) and priority is:\n"
" V Verbose (default for <tag>)\n"
@@ -532,9 +371,8 @@
"or defaults to \"threadtime\"\n\n");
}
-static void show_format_help(android_logcat_context_internal* context) {
- if (!context->error) return;
- fprintf(context->error,
+static void show_format_help() {
+ fprintf(stderr,
"-v <format>, --format=<format> options:\n"
" Sets log print format verb and adverbs, where <format> is:\n"
" brief long process raw tag thread threadtime time\n"
@@ -568,16 +406,13 @@
}
// clang-format on
-static int setLogFormat(android_logcat_context_internal* context,
- const char* formatString) {
- AndroidLogPrintFormat format;
-
- format = android_log_formatFromString(formatString);
+int Logcat::SetLogFormat(const char* format_string) {
+ AndroidLogPrintFormat format = android_log_formatFromString(format_string);
// invalid string?
if (format == FORMAT_OFF) return -1;
- return android_log_setPrintFormat(context->logformat, format);
+ return android_log_setPrintFormat(logformat_.get(), format);
}
static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
@@ -607,32 +442,25 @@
return true;
}
-static void logcat_panic(android_logcat_context_internal* context,
- enum helpType showHelp, const char* fmt, ...) {
- context->retval = EXIT_FAILURE;
- if (!context->error) {
- context->stop = true;
- return;
- }
-
+static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- vfprintf(context->error, fmt, args);
+ vfprintf(stderr, fmt, args);
va_end(args);
switch (showHelp) {
case HELP_TRUE:
- show_help(context);
+ show_help();
break;
case HELP_FORMAT:
- show_format_help(context);
+ show_format_help();
break;
case HELP_FALSE:
default:
break;
}
- context->stop = true;
+ exit(EXIT_FAILURE);
}
static char* parseTime(log_time& t, const char* cp) {
@@ -712,18 +540,6 @@
return retval;
}
-const char* getenv(android_logcat_context_internal* context, const char* name) {
- if (!context->envp || !name || !*name) return nullptr;
-
- for (size_t len = strlen(name), i = 0; context->envp[i]; ++i) {
- if (strncmp(context->envp[i], name, len)) continue;
- if (context->envp[i][len] == '=') return &context->envp[i][len + 1];
- }
- return nullptr;
-}
-
-} // namespace android
-
void reportErrorName(const char** current, const char* name,
bool blockSecurity) {
if (*current) return;
@@ -732,8 +548,7 @@
}
}
-static int __logcat(android_logcat_context_internal* context) {
- using namespace android;
+int Logcat::Run(int argc, char** argv) {
int err;
bool hasSetLogFormat = false;
bool clearLog = false;
@@ -760,101 +575,10 @@
const char* clearFail = nullptr;
const char* setSizeFail = nullptr;
const char* getSizeFail = nullptr;
- int argc = context->argc;
- char* const* argv = context->argv;
-
- context->output = stdout;
- context->error = stderr;
-
- for (int i = 0; i < argc; ++i) {
- // Simulate shell stderr redirect parsing
- if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue;
-
- // Append to file not implemented, just open file
- size_t skip = (argv[i][2] == '>') + 2;
- if (!strcmp(&argv[i][skip], "/dev/null")) {
- context->stderr_null = true;
- } else if (!strcmp(&argv[i][skip], "&1")) {
- context->stderr_stdout = true;
- } else {
- // stderr file redirections are not supported
- fprintf(context->stderr_stdout ? stdout : stderr,
- "stderr redirection to file %s unsupported, skipping\n",
- &argv[i][skip]);
- }
- // Only the first one
- break;
- }
-
- const char* filename = nullptr;
- for (int i = 0; i < argc; ++i) {
- // Simulate shell stdout redirect parsing
- if (argv[i][0] != '>') continue;
-
- // Append to file not implemented, just open file
- filename = &argv[i][(argv[i][1] == '>') + 1];
- // Only the first one
- break;
- }
-
- // Deal with setting up file descriptors and FILE pointers
- if (context->error_fd >= 0) { // Is an error file descriptor supplied?
- if (context->error_fd == context->output_fd) {
- context->stderr_stdout = true;
- } else if (context->stderr_null) { // redirection told us to close it
- close(context->error_fd);
- context->error_fd = -1;
- } else { // All Ok, convert error to a FILE pointer
- context->error = fdopen(context->error_fd, "web");
- if (!context->error) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : stderr,
- "Failed to fdopen(error_fd=%d) %s\n", context->error_fd,
- strerror(errno));
- goto exit;
- }
- }
- }
- if (context->output_fd >= 0) { // Is an output file descriptor supplied?
- if (filename) { // redirect to file, close supplied file descriptor.
- close(context->output_fd);
- context->output_fd = -1;
- } else { // All Ok, convert output to a FILE pointer
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : context->error,
- "Failed to fdopen(output_fd=%d) %s\n",
- context->output_fd, strerror(errno));
- goto exit;
- }
- }
- }
- if (filename) { // We supplied an output file redirected in command line
- context->output = fopen(filename, "web");
- }
- // Deal with 2>&1
- if (context->stderr_stdout) context->error = context->output;
- // Deal with 2>/dev/null
- if (context->stderr_null) {
- context->error_fd = -1;
- context->error = nullptr;
- }
- // Only happens if output=stdout or output=filename
- if ((context->output_fd < 0) && context->output) {
- context->output_fd = fileno(context->output);
- }
- // Only happens if error=stdout || error=stderr
- if ((context->error_fd < 0) && context->error) {
- context->error_fd = fileno(context->error);
- }
-
- context->logformat = android_log_format_new();
if (argc == 2 && !strcmp(argv[1], "--help")) {
- show_help(context);
- context->retval = EXIT_SUCCESS;
- goto exit;
+ show_help();
+ return EXIT_SUCCESS;
}
// meant to catch comma-delimited values, but cast a wider
@@ -912,15 +636,13 @@
// only long options
if (long_options[option_index].name == pid_str) {
if (pid != 0) {
- logcat_panic(context, HELP_TRUE, "Only supports one PID argument.\n");
- goto exit;
+ LogcatPanic(HELP_TRUE, "Only supports one PID argument.\n");
}
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name, optarg);
}
break;
}
@@ -930,25 +652,22 @@
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name, optarg);
}
- if ((dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) &&
- context->error) {
- fprintf(context->error,
- "WARNING: %s %u seconds, ignoring %zu\n",
- long_options[option_index].name,
- ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
+ if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
+ fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
+ long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
+ dummy);
}
break;
}
if (long_options[option_index].name == print_str) {
- context->printItAnyways = true;
+ print_it_anyways_ = true;
break;
}
if (long_options[option_index].name == debug_str) {
- context->debug = true;
+ debug_ = true;
break;
}
if (long_options[option_index].name == id_str) {
@@ -958,7 +677,7 @@
case 's':
// default to all silent
- android_log_addFilterRule(context->logformat, "*:s");
+ android_log_addFilterRule(logformat_.get(), "*:s");
break;
case 'c':
@@ -983,25 +702,18 @@
if (strspn(optarg, "0123456789") != strlen(optarg)) {
char* cp = parseTime(tail_time, optarg);
if (!cp) {
- logcat_panic(context, HELP_FALSE, "-%c \"%s\" not in time format\n", c,
- optarg);
- goto exit;
+ LogcatPanic(HELP_FALSE, "-%c \"%s\" not in time format\n", c, optarg);
}
if (*cp) {
char ch = *cp;
*cp = '\0';
- if (context->error) {
- fprintf(context->error, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
- c, optarg, ch, cp + 1);
- }
+ fprintf(stderr, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n", c, optarg,
+ ch, cp + 1);
*cp = ch;
}
} else {
if (!getSizeTArg(optarg, &tail_lines, 1)) {
- if (context->error) {
- fprintf(context->error, "WARNING: -%c %s invalid, setting to 1\n", c,
- optarg);
- }
+ fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
tail_lines = 1;
}
}
@@ -1012,14 +724,13 @@
break;
case 'e':
- context->regex.reset(new std::regex(optarg));
+ regex_.reset(new std::regex(optarg));
break;
case 'm': {
- if (!getSizeTArg(optarg, &context->maxCount)) {
- logcat_panic(context, HELP_FALSE,
- "-%c \"%s\" isn't an integer greater than zero\n", c, optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &max_count_)) {
+ LogcatPanic(HELP_FALSE, "-%c \"%s\" isn't an integer greater than zero\n", c,
+ optarg);
}
} break;
@@ -1059,9 +770,7 @@
}
if (!setLogSize) {
- logcat_panic(context, HELP_FALSE,
- "ERROR: -G <num><multiplier>\n");
- goto exit;
+ LogcatPanic(HELP_FALSE, "ERROR: -G <num><multiplier>\n");
}
} break;
@@ -1093,9 +802,7 @@
const char* name = android_log_id_to_name(log_id);
if (!!strcmp(name, arg)) {
- logcat_panic(context, HELP_TRUE,
- "unknown buffer %s\n", arg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "unknown buffer %s\n", arg);
}
if (log_id == LOG_ID_SECURITY) allSelected = false;
idMask |= (1 << log_id);
@@ -1111,7 +818,7 @@
if (!(idMask & (1 << i))) continue;
bool found = false;
- for (dev = context->devices; dev; dev = dev->next) {
+ for (dev = devices_; dev; dev = dev->next) {
if (!strcmp(name, dev->device)) {
found = true;
break;
@@ -1129,14 +836,14 @@
dev->next = d;
dev = d;
} else {
- context->devices = dev = d;
+ devices_ = dev = d;
}
- context->devCount++;
+ dev_count_++;
}
} break;
case 'B':
- context->printBinary = 1;
+ print_binary_ = 1;
break;
case 'f':
@@ -1144,38 +851,33 @@
tail_time = lastLogTime(optarg);
}
// redirect output to a file
- context->outputFileName = optarg;
+ output_file_name_ = optarg;
break;
case 'r':
- if (!getSizeTArg(optarg, &context->logRotateSizeKBytes, 1)) {
- logcat_panic(context, HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &log_rotate_size_kb_, 1)) {
+ LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
- if (!getSizeTArg(optarg, &context->maxRotatedLogs, 1)) {
- logcat_panic(context, HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &max_rotated_logs_, 1)) {
+ LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
case 'v': {
if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
- show_format_help(context);
- context->retval = EXIT_SUCCESS;
- goto exit;
+ show_format_help();
+ return EXIT_SUCCESS;
}
std::unique_ptr<char, void (*)(void*)> formats(strdup(optarg), free);
char* arg = formats.get();
char* sv = nullptr; // protect against -ENOMEM above
while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = setLogFormat(context, arg);
+ err = SetLogFormat(arg);
if (err < 0) {
- logcat_panic(context, HELP_FORMAT,
- "Invalid parameter \"%s\" to -v\n", arg);
- goto exit;
+ LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg);
}
arg = nullptr;
if (err) hasSetLogFormat = true;
@@ -1198,8 +900,7 @@
{
// if not in emulator, exit quietly
if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
- context->retval = EXIT_SUCCESS;
- goto exit;
+ return EXIT_SUCCESS;
}
std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
@@ -1210,8 +911,7 @@
const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
// if nothing found or invalid filters, exit quietly
if (!logcatFilter) {
- context->retval = EXIT_SUCCESS;
- goto exit;
+ return EXIT_SUCCESS;
}
const char* p = logcatFilter + strlen(LOGCAT_FILTER);
@@ -1230,8 +930,7 @@
} else if (console) {
p = console + strlen(CONSOLE_OPTION);
} else {
- context->retval = EXIT_FAILURE;
- goto exit;
+ return EXIT_FAILURE;
}
q = strpbrk(p, " \t\n\r");
@@ -1248,37 +947,26 @@
devname = devname.substr(0, pos);
}
}
- cmdline.erase();
- if (context->error) {
- fprintf(context->error, "logcat using %s\n",
- devname.c_str());
+ fprintf(stderr, "logcat using %s\n", devname.c_str());
+
+ int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ break;
}
- FILE* fp = fopen(devname.c_str(), "web");
- devname.erase();
- if (!fp) break;
-
if (consolePipe) {
// need the trailing '\0'
- if(!android::base::WriteFully(fileno(fp), pipePurpose.c_str(),
- pipePurpose.size() + 1)) {
- fclose(fp);
- context->retval = EXIT_FAILURE;
- goto exit;
+ if (!android::base::WriteFully(fd, pipePurpose.c_str(),
+ pipePurpose.size() + 1)) {
+ close(fd);
+ return EXIT_FAILURE;
}
}
-
// close output and error channels, replace with console
- android::close_output(context);
- android::close_error(context);
- context->stderr_stdout = true;
- context->output = fp;
- context->output_fd = fileno(fp);
- if (context->stderr_null) break;
- context->stderr_stdout = true;
- context->error = fp;
- context->error_fd = fileno(fp);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
}
break;
@@ -1287,69 +975,59 @@
break;
case ':':
- logcat_panic(context, HELP_TRUE, "Option -%c needs an argument\n", optopt);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Option -%c needs an argument\n", optopt);
case 'h':
- show_help(context);
- show_format_help(context);
- goto exit;
+ show_help();
+ show_format_help();
+ return EXIT_SUCCESS;
default:
- logcat_panic(context, HELP_TRUE, "Unrecognized Option %c\n", optopt);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Unrecognized Option %c\n", optopt);
}
}
- if (context->maxCount && got_t) {
- logcat_panic(context, HELP_TRUE,
- "Cannot use -m (--max-count) and -t together\n");
- goto exit;
+ if (max_count_ && got_t) {
+ LogcatPanic(HELP_TRUE, "Cannot use -m (--max-count) and -t together\n");
}
- if (context->printItAnyways && (!context->regex || !context->maxCount)) {
+ if (print_it_anyways_ && (!regex_ || !max_count_)) {
// One day it would be nice if --print -v color and --regex <expr>
// could play with each other and show regex highlighted content.
- // clang-format off
- if (context->error) {
- fprintf(context->error, "WARNING: "
- "--print ignored, to be used in combination with\n"
- " "
- "--regex <expr> and --max-count <N>\n");
- }
- context->printItAnyways = false;
+ fprintf(stderr,
+ "WARNING: "
+ "--print ignored, to be used in combination with\n"
+ " "
+ "--regex <expr> and --max-count <N>\n");
+ print_it_anyways_ = false;
}
- if (!context->devices) {
- dev = context->devices = new log_device_t("main", false);
- context->devCount = 1;
+ if (!devices_) {
+ dev = devices_ = new log_device_t("main", false);
+ dev_count_ = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
dev = dev->next = new log_device_t("system", false);
- context->devCount++;
+ dev_count_++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
dev = dev->next = new log_device_t("crash", false);
- context->devCount++;
+ dev_count_++;
}
if (android_name_to_log_id("kernel") == LOG_ID_KERNEL) {
dev = dev->next = new log_device_t("kernel", false);
- context->devCount++;
+ dev_count_++;
}
}
- if (!!context->logRotateSizeKBytes && !context->outputFileName) {
- logcat_panic(context, HELP_TRUE, "-r requires -f as well\n");
- goto exit;
+ if (log_rotate_size_kb_ != 0 && !output_file_name_) {
+ LogcatPanic(HELP_TRUE, "-r requires -f as well\n");
}
- if (!!setId) {
- if (!context->outputFileName) {
- logcat_panic(context, HELP_TRUE,
- "--id='%s' requires -f as well\n", setId);
- goto exit;
+ if (setId != 0) {
+ if (!output_file_name_) {
+ LogcatPanic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
}
- std::string file_name = android::base::StringPrintf(
- "%s.id", context->outputFileName);
+ std::string file_name = StringPrintf("%s.id", output_file_name_);
std::string file;
bool file_ok = android::base::ReadFileToString(file_name, &file);
android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
@@ -1358,7 +1036,7 @@
}
if (!hasSetLogFormat) {
- const char* logFormat = android::getenv(context, "ANDROID_PRINTF_LOG");
+ const char* logFormat = getenv("ANDROID_PRINTF_LOG");
if (!!logFormat) {
std::unique_ptr<char, void (*)(void*)> formats(strdup(logFormat),
@@ -1366,41 +1044,34 @@
char* sv = nullptr; // protect against -ENOMEM above
char* arg = formats.get();
while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = setLogFormat(context, arg);
+ err = SetLogFormat(arg);
// environment should not cause crash of logcat
- if ((err < 0) && context->error) {
- fprintf(context->error,
- "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
+ if (err < 0) {
+ fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
}
arg = nullptr;
if (err > 0) hasSetLogFormat = true;
}
}
if (!hasSetLogFormat) {
- setLogFormat(context, "threadtime");
+ SetLogFormat("threadtime");
}
}
if (forceFilters.size()) {
- err = android_log_addFilterString(context->logformat,
- forceFilters.c_str());
+ err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
if (err < 0) {
- logcat_panic(context, HELP_FALSE,
- "Invalid filter expression in logcat args\n");
- goto exit;
+ LogcatPanic(HELP_FALSE, "Invalid filter expression in logcat args\n");
}
} else if (argc == optind) {
// Add from environment variable
- const char* env_tags_orig = android::getenv(context, "ANDROID_LOG_TAGS");
+ const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
if (!!env_tags_orig) {
- err = android_log_addFilterString(context->logformat,
- env_tags_orig);
+ err = android_log_addFilterString(logformat_.get(), env_tags_orig);
if (err < 0) {
- logcat_panic(context, HELP_TRUE,
- "Invalid filter expression in ANDROID_LOG_TAGS\n");
- goto exit;
+ LogcatPanic(HELP_TRUE, "Invalid filter expression in ANDROID_LOG_TAGS\n");
}
}
} else {
@@ -1411,16 +1082,14 @@
// skip stdout redirections of _all_ kinds
if (argv[i][0] == '>') continue;
- err = android_log_addFilterString(context->logformat, argv[i]);
+ err = android_log_addFilterString(logformat_.get(), argv[i]);
if (err < 0) {
- logcat_panic(context, HELP_TRUE,
- "Invalid filter expression '%s'\n", argv[i]);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Invalid filter expression '%s'\n", argv[i]);
}
}
}
- dev = context->devices;
+ dev = devices_;
if (tail_time != log_time::EPOCH) {
logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
} else {
@@ -1439,21 +1108,18 @@
}
if (clearLog || setId) {
- if (context->outputFileName) {
- int maxRotationCountDigits =
- (context->maxRotatedLogs > 0) ?
- (int)(floor(log10(context->maxRotatedLogs) + 1)) :
- 0;
+ if (output_file_name_) {
+ int max_rotation_count_digits =
+ max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
- for (int i = context->maxRotatedLogs ; i >= 0 ; --i) {
+ for (int i = max_rotated_logs_; i >= 0; --i) {
std::string file;
if (!i) {
- file = android::base::StringPrintf(
- "%s", context->outputFileName);
+ file = output_file_name_;
} else {
- file = android::base::StringPrintf("%s.%.*d",
- context->outputFileName, maxRotationCountDigits, i);
+ file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits,
+ i);
}
if (!file.length()) {
@@ -1497,36 +1163,25 @@
readable_format.first, readable_format.second,
(int)LOGGER_ENTRY_MAX_LEN,
(int)LOGGER_ENTRY_MAX_PAYLOAD);
- TEMP_FAILURE_RETRY(write(context->output_fd,
- str.data(), str.length()));
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
}
}
dev = dev->next;
}
- context->retval = EXIT_SUCCESS;
-
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(context, HELP_FALSE,
- "Unable to open log device '%s'\n", openDeviceFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "Unable to open log device '%s'\n", openDeviceFail);
}
if (clearFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to clear the '%s' log\n", clearFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to clear the '%s' log\n", clearFail);
}
if (setSizeFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to set the '%s' log size\n", setSizeFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to set the '%s' log size\n", setSizeFail);
}
if (getSizeFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to get the readable '%s' log size", getSizeFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size", getSizeFail);
}
if (setPruneList) {
@@ -1537,15 +1192,13 @@
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(context, HELP_FALSE,
- "failed to set the prune list");
+ LogcatPanic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(context, HELP_FALSE,
- "failed to set the prune list (alloc)");
+ LogcatPanic(HELP_FALSE, "failed to set the prune list (alloc)");
}
- goto close;
+ return EXIT_SUCCESS;
}
if (printStatistics || getPruneList) {
@@ -1574,8 +1227,7 @@
}
if (!buf) {
- logcat_panic(context, HELP_FALSE, "failed to read data");
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to read data");
}
// remove trailing FF
@@ -1592,149 +1244,68 @@
}
len = strlen(cp);
- TEMP_FAILURE_RETRY(write(context->output_fd, cp, len));
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
delete[] buf;
- goto close;
+ return EXIT_SUCCESS;
}
- if (getLogSize || setLogSize || clearLog) goto close;
+ if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
- setupOutputAndSchedulingPolicy(context, !(mode & ANDROID_LOG_NONBLOCK));
- if (context->stop) goto close;
-
- // LOG_EVENT_INT(10, 12345);
- // LOG_EVENT_LONG(11, 0x1122334455667788LL);
- // LOG_EVENT_STRING(0, "whassup, doc?");
+ SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
dev = nullptr;
- while (!context->stop &&
- (!context->maxCount || (context->printCount < context->maxCount))) {
+ while (!max_count_ || print_count_ < max_count_) {
struct log_msg log_msg;
int ret = android_logger_list_read(logger_list, &log_msg);
if (!ret) {
- logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret < 0) {
if (ret == -EAGAIN) break;
if (ret == -EIO) {
- logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
- logcat_panic(context, HELP_FALSE, "read: unexpected length.\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected length.\n");
}
- logcat_panic(context, HELP_FALSE, "logcat read failure\n");
- break;
+ LogcatPanic(HELP_FALSE, "logcat read failure\n");
}
log_device_t* d;
- for (d = context->devices; d; d = d->next) {
+ for (d = devices_; d; d = d->next) {
if (android_name_to_log_id(d->device) == log_msg.id()) break;
}
if (!d) {
- context->devCount = 2; // set to Multiple
+ dev_count_ = 2; // set to Multiple
d = &unexpected;
d->binary = log_msg.id() == LOG_ID_EVENTS;
}
if (dev != d) {
dev = d;
- maybePrintStart(context, dev, printDividers);
- if (context->stop) break;
+ MaybePrintStart(dev, printDividers);
}
- if (context->printBinary) {
- printBinary(context, &log_msg);
+ if (print_binary_) {
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
} else {
- processBuffer(context, dev, &log_msg);
+ ProcessBuffer(dev, &log_msg);
}
}
-
-close:
- // Short and sweet. Implemented generic version in android_logcat_destroy.
- while (!!(dev = context->devices)) {
- context->devices = dev->next;
- delete dev;
- }
- android_logger_list_free(logger_list);
-
-exit:
- // close write end of pipe to help things along
- if (context->output_fd == context->fds[1]) {
- android::close_output(context);
- }
- if (context->error_fd == context->fds[1]) {
- android::close_error(context);
- }
- if (context->fds[1] >= 0) {
- // NB: should be closed by the above
- int save_errno = errno;
- close(context->fds[1]);
- errno = save_errno;
- context->fds[1] = -1;
- }
- context->thread_stopped = true;
- return context->retval;
+ return EXIT_SUCCESS;
}
-// Can block
-int android_logcat_run_command(android_logcat_context ctx,
- int output, int error,
- int argc, char* const* argv,
- char* const* envp) {
- android_logcat_context_internal* context = ctx;
-
- context->output_fd = output;
- context->error_fd = error;
- context->argc = argc;
- context->argv = argv;
- context->envp = envp;
- context->stop = false;
- context->thread_stopped = false;
- return __logcat(context);
+int RunLogcat(int argc, char** argv) {
+ Logcat logcat;
+ return logcat.Run(argc, argv);
}
-// Finished with context
-int android_logcat_destroy(android_logcat_context* ctx) {
- android_logcat_context_internal* context = *ctx;
-
- if (!context) return -EBADF;
-
- *ctx = nullptr;
-
- context->stop = true;
-
- while (context->thread_stopped == false) {
- // Makes me sad, replace thread_stopped with semaphore. Short lived.
- sched_yield();
- }
-
- context->argv_hold.clear();
- context->args.clear();
- context->envp_hold.clear();
- context->envs.clear();
- if (context->fds[0] >= 0) {
- close(context->fds[0]);
- context->fds[0] = -1;
- }
- android::close_output(context);
- android::close_error(context);
-
- if (context->fds[1] >= 0) {
- // NB: this should be closed by close_output, but just in case...
- close(context->fds[1]);
- context->fds[1] = -1;
- }
-
- android_closeEventTagMap(context->eventTagMap);
-
+Logcat::~Logcat() {
// generic cleanup of devices list to handle all possible dirty cases
log_device_t* dev;
- while (!!(dev = context->devices)) {
+ while (!!(dev = devices_)) {
struct logger_list* logger_list = dev->logger_list;
if (logger_list) {
for (log_device_t* d = dev; d; d = d->next) {
@@ -1742,13 +1313,7 @@
}
android_logger_list_free(logger_list);
}
- context->devices = dev->next;
+ devices_ = dev->next;
delete dev;
}
-
- int retval = context->retval;
-
- free(context);
-
- return retval;
}
diff --git a/logcat/logcat.h b/logcat/logcat.h
index 85ed7da..4cc112b 100644
--- a/logcat/logcat.h
+++ b/logcat/logcat.h
@@ -16,45 +16,4 @@
#pragma once
-#include <stdio.h>
-
-/*
- * The opaque context
- */
-typedef struct android_logcat_context_internal* android_logcat_context;
-
-/* Creates a context associated with this logcat instance
- *
- * Returns a pointer to the context, or a NULL on error.
- */
-android_logcat_context create_android_logcat();
-
-/* Collects and outputs the logcat data to output and error file descriptors
- *
- * Will block, performed in-thread and in-process
- *
- * The output file descriptor variable, if greater than or equal to 0, is
- * where the output (ie: stdout) will be sent. The file descriptor is closed
- * on android_logcat_destroy which terminates the instance, or when an -f flag
- * (output redirect to a file) is present in the command. The error file
- * descriptor variable, if greater than or equal to 0, is where the error
- * stream (ie: stderr) will be sent, also closed on android_logcat_destroy.
- * The error file descriptor can be set to equal to the output file descriptor,
- * which will mix output and error stream content, and will defer closure of
- * the file descriptor on -f flag redirection. Negative values for the file
- * descriptors will use stdout and stderr FILE references respectively
- * internally, and will not close the references as noted above.
- *
- * Return value is 0 for success, non-zero for errors.
- */
-int android_logcat_run_command(android_logcat_context ctx, int output, int error, int argc,
- char* const* argv, char* const* envp);
-
-/* Finished with context
- *
- * Kill the command thread ASAP (if any), and free up all associated resources.
- *
- * Return value is the result of the android_logcat_run_command, or
- * non-zero for any errors.
- */
-int android_logcat_destroy(android_logcat_context* ctx);
+int RunLogcat(int argc, char** argv);
\ No newline at end of file
diff --git a/logcat/logcat_main.cpp b/logcat/logcat_main.cpp
index ecfa2ba..59ab716 100644
--- a/logcat/logcat_main.cpp
+++ b/logcat/logcat_main.cpp
@@ -19,12 +19,7 @@
#include "logcat.h"
-int main(int argc, char** argv, char** envp) {
- android_logcat_context ctx = create_android_logcat();
- if (!ctx) return -1;
+int main(int argc, char** argv) {
signal(SIGPIPE, exit);
- int retval = android_logcat_run_command(ctx, -1, -1, argc, argv, envp);
- int ret = android_logcat_destroy(&ctx);
- if (!ret) ret = retval;
- return ret;
+ return RunLogcat(argc, argv);
}
diff --git a/logcat/logcatd_main.cpp b/logcat/logcatd_main.cpp
index c131846..4da933f 100644
--- a/logcat/logcatd_main.cpp
+++ b/logcat/logcatd_main.cpp
@@ -23,10 +23,7 @@
#include "logcat.h"
-int main(int argc, char** argv, char** envp) {
- android_logcat_context ctx = create_android_logcat();
- if (!ctx) return -1;
-
+int main(int argc, char** argv) {
signal(SIGPIPE, exit);
// Save and detect presence of -L or --last flag
@@ -46,8 +43,7 @@
int ret = 0;
if (last) {
// Run logcat command with -L flag
- ret = android_logcat_run_command(ctx, -1, -1, argv_hold.size() - 1,
- (char* const*)&argv_hold[0], envp);
+ ret = RunLogcat(argv_hold.size() - 1, (char**)&argv_hold[0]);
// Remove -L and --last flags from argument list
for (std::vector<const char*>::iterator it = argv_hold.begin();
it != argv_hold.end();) {
@@ -62,10 +58,7 @@
}
// Run logcat command without -L flag
- int retval = android_logcat_run_command(ctx, -1, -1, argv_hold.size() - 1,
- (char* const*)&argv_hold[0], envp);
- if (!ret) ret = retval;
- retval = android_logcat_destroy(&ctx);
+ int retval = RunLogcat(argv_hold.size() - 1, (char**)&argv_hold[0]);
if (!ret) ret = retval;
return ret;
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5241730..e1bb02f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -326,7 +326,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -342,7 +342,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -358,7 +358,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 674ed01..9b77ce2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -926,9 +926,17 @@
setprop sys.init.updatable_crashing 0
setprop apexd.status 0
+on userspace-reboot-fs-remount
+ # Make sure that vold is running.
+ # This is mostly a precaution measure in case vold for some reason wasn't running when
+ # userspace reboot was initiated.
+ start vold
+ exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
+ exec - system system -- /system/bin/vdc checkpoint markBootAttempt
+ remount_userdata
+
on userspace-reboot-resume
- # TODO(b/135984674): remount userdata and reset checkpointing
- trigger nonencrypted
+ trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 694b50e..ec4f6ab 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -25,7 +25,7 @@
"tcpdump",
"toolbox",
"toybox",
- "unzip",
+ "ziptool",
],
}