Merge "Revert "liblog: use a blocking socket for sending messages to logd""
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9f22be5..1462cc9 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1113,10 +1113,9 @@
// metadata-encrypted device with smaller blocks, we must not change this for
// devices shipped with Q or earlier unless they explicitly selected dm-default-key
// v2
- constexpr unsigned int pre_gki_level = __ANDROID_API_Q__;
unsigned int options_format_version = android::base::GetUintProperty<unsigned int>(
"ro.crypto.dm_default_key.options_format.version",
- (android::fscrypt::GetFirstApiLevel() <= pre_gki_level ? 1 : 2));
+ (android::fscrypt::GetFirstApiLevel() <= __ANDROID_API_Q__ ? 1 : 2));
if (options_format_version > 1) {
bowTarget->SetBlockSize(4096);
}
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 65eaedd..b3de9c4 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -243,17 +243,44 @@
cc_test {
name: "libhealthd_charger_test",
- srcs: ["AnimationParser_test.cpp"],
- shared_libs: [
- "liblog",
- "libbase",
- "libcutils",
+ defaults: ["charger_defaults"],
+ srcs: [
+ "AnimationParser_test.cpp",
+ "healthd_mode_charger_test.cpp"
],
static_libs: [
- "libhealthd_charger",
+ "libgmock",
],
test_suites: [
"general-tests",
"device-tests",
],
+ data: [
+ ":libhealthd_charger_test_data",
+ ],
+ require_root: true,
+}
+
+// /system/etc/res/images/charger/battery_fail.png
+prebuilt_etc {
+ name: "system_core_charger_res_images_battery_fail.png",
+ src: "images/battery_fail.png",
+ relative_install_path: "res/images/charger",
+ filename: "battery_fail.png",
+}
+
+// /system/etc/res/images/charger/battery_scale.png
+prebuilt_etc {
+ name: "system_core_charger_res_images_battery_scale.png",
+ src: "images/battery_scale.png",
+ relative_install_path: "res/images/charger",
+ filename: "battery_scale.png",
+}
+
+phony {
+ name: "charger_res_images",
+ required: [
+ "system_core_charger_res_images_battery_fail.png",
+ "system_core_charger_res_images_battery_scale.png",
+ ],
}
diff --git a/healthd/Android.mk b/healthd/Android.mk
deleted file mode 100644
index 4b09cf8..0000000
--- a/healthd/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
-LOCAL_CHARGER_NO_UI := true
-endif
-
-### charger_res_images ###
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-define _add-charger-image
-include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_res_images_$(notdir $(1))
-LOCAL_MODULE_STEM := $(notdir $(1))
-_img_modules += $$(LOCAL_MODULE)
-LOCAL_SRC_FILES := $1
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
-include $$(BUILD_PREBUILT)
-endef
-
-_img_modules :=
-_images :=
-$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
- $(eval $(call _add-charger-image,$(_img))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := charger_res_images
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := $(_img_modules)
-include $(BUILD_PHONY_PACKAGE)
-
-_add-charger-image :=
-_img_modules :=
-endif # LOCAL_CHARGER_NO_UI
diff --git a/healthd/animation.h b/healthd/animation.h
index d02d7a7..c2d5f1c 100644
--- a/healthd/animation.h
+++ b/healthd/animation.h
@@ -18,6 +18,7 @@
#define HEALTHD_ANIMATION_H
#include <inttypes.h>
+
#include <string>
class GRSurface;
@@ -52,20 +53,11 @@
// - When treating paths as relative paths, it adds ".png" suffix.
// - When treating paths as absolute paths, it doesn't add the suffix. Hence, the suffix
// is added here.
- void set_resource_root(const std::string& root) {
- if (!animation_file.empty()) {
- animation_file = root + animation_file + ".png";
- }
- if (!fail_file.empty()) {
- fail_file = root + fail_file + ".png";
- }
- if (!text_clock.font_file.empty()) {
- text_clock.font_file = root + text_clock.font_file + ".png";
- }
- if (!text_percent.font_file.empty()) {
- text_percent.font_file = root + text_percent.font_file + ".png";
- }
- }
+ // If |backup_root| is provided, additionally check if file under |root| is accessbile or not.
+ // If not accessbile, use |backup_root| instead.
+ // Require that |root| starts and ends with "/". If |backup_root| is provided, require that
+ // |backup_root| starts and ends with "/".
+ void set_resource_root(const std::string& root, const std::string& backup_root = "");
std::string animation_file;
std::string fail_file;
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 386ba1a..04a99a3 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -33,7 +33,9 @@
#include <optional>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/strings.h>
#include <linux/netlink.h>
#include <sys/socket.h>
@@ -58,6 +60,7 @@
#include <health2impl/Health.h>
#include <healthd/healthd.h>
+using std::string_literals::operator""s;
using namespace android;
using android::hardware::Return;
using android::hardware::health::GetHealthServiceOrDefault;
@@ -103,7 +106,13 @@
namespace android {
-// Resources in /product/etc/res overrides resources in /res.
+// Legacy animation resources are loaded from this directory.
+static constexpr const char* legacy_animation_root = "/res/images/";
+
+// Built-in animation resources are loaded from this directory.
+static constexpr const char* system_animation_root = "/system/etc/res/images/";
+
+// Resources in /product/etc/res overrides resources in /res and /system/etc/res.
// If the device is using the Generic System Image (GSI), resources may exist in
// both paths.
static constexpr const char* product_animation_desc_path =
@@ -625,6 +634,12 @@
batt_anim_.set_resource_root(product_animation_root);
} else if (base::ReadFileToString(animation_desc_path, &content)) {
parse_success = parse_animation_desc(content, &batt_anim_);
+ // Fallback resources always exist in system_animation_root. On legacy devices with an old
+ // ramdisk image, resources may be overridden under root. For example,
+ // /res/images/charger/battery_fail.png may not be the same as
+ // system/core/healthd/images/battery_fail.png in the source tree, but is a device-specific
+ // image. Hence, load from /res, and fall back to /system/etc/res.
+ batt_anim_.set_resource_root(legacy_animation_root, system_animation_root);
} else {
LOGW("Could not open animation description at %s\n", animation_desc_path);
parse_success = false;
@@ -633,13 +648,13 @@
if (!parse_success) {
LOGW("Could not parse animation description. Using default animation.\n");
batt_anim_ = BASE_ANIMATION;
- batt_anim_.animation_file.assign("charger/battery_scale");
+ batt_anim_.animation_file.assign(system_animation_root + "charger/battery_scale.png"s);
InitDefaultAnimationFrames();
batt_anim_.frames = owned_frames_.data();
batt_anim_.num_frames = owned_frames_.size();
}
if (batt_anim_.fail_file.empty()) {
- batt_anim_.fail_file.assign("charger/battery_fail");
+ batt_anim_.fail_file.assign(system_animation_root + "charger/battery_fail.png"s);
}
LOGV("Animation Description:\n");
@@ -678,10 +693,11 @@
InitAnimation();
- ret = res_create_display_surface(batt_anim_.fail_file.c_str(), &surf_unknown_);
+ ret = CreateDisplaySurface(batt_anim_.fail_file.c_str(), &surf_unknown_);
if (ret < 0) {
LOGE("Cannot load custom battery_fail image. Reverting to built in: %d\n", ret);
- ret = res_create_display_surface("charger/battery_fail", &surf_unknown_);
+ ret = CreateDisplaySurface((system_animation_root + "charger/battery_fail.png"s).c_str(),
+ &surf_unknown_);
if (ret < 0) {
LOGE("Cannot load built in battery_fail image\n");
surf_unknown_ = NULL;
@@ -692,8 +708,8 @@
int scale_count;
int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text
// chunk). We are using hard-coded frame.disp_time instead.
- ret = res_create_multi_display_surface(batt_anim_.animation_file.c_str(), &scale_count,
- &scale_fps, &scale_frames);
+ ret = CreateMultiDisplaySurface(batt_anim_.animation_file.c_str(), &scale_count, &scale_fps,
+ &scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
batt_anim_.num_frames = 0;
@@ -722,6 +738,43 @@
boot_min_cap_ = config->boot_min_cap;
}
+int Charger::CreateDisplaySurface(const std::string& name, GRSurface** surface) {
+ return res_create_display_surface(name.c_str(), surface);
+}
+
+int Charger::CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
+ GRSurface*** surface) {
+ return res_create_multi_display_surface(name.c_str(), frames, fps, surface);
+}
+
+void set_resource_root_for(const std::string& root, const std::string& backup_root,
+ std::string* value) {
+ if (value->empty()) {
+ return;
+ }
+
+ std::string new_value = root + *value + ".png";
+ // If |backup_root| is provided, additionally check whether the file under |root| is
+ // accessible or not. If not accessible, fallback to file under |backup_root|.
+ if (!backup_root.empty() && access(new_value.data(), F_OK) == -1) {
+ new_value = backup_root + *value + ".png";
+ }
+
+ *value = new_value;
+}
+
+void animation::set_resource_root(const std::string& root, const std::string& backup_root) {
+ CHECK(android::base::StartsWith(root, "/") && android::base::EndsWith(root, "/"))
+ << "animation root " << root << " must start and end with /";
+ CHECK(backup_root.empty() || (android::base::StartsWith(backup_root, "/") &&
+ android::base::EndsWith(backup_root, "/")))
+ << "animation backup root " << backup_root << " must start and end with /";
+ set_resource_root_for(root, backup_root, &animation_file);
+ set_resource_root_for(root, backup_root, &fail_file);
+ set_resource_root_for(root, backup_root, &text_clock.font_file);
+ set_resource_root_for(root, backup_root, &text_percent.font_file);
+}
+
} // namespace android
int healthd_charger_main(int argc, char** argv) {
diff --git a/healthd/healthd_mode_charger.h b/healthd/healthd_mode_charger.h
index 6e569ee..6f9ae8c 100644
--- a/healthd/healthd_mode_charger.h
+++ b/healthd/healthd_mode_charger.h
@@ -53,6 +53,11 @@
// HalHealthLoop overrides
void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
+ // Allowed to be mocked for testing.
+ virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
+ virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
+ GRSurface*** surface);
+
private:
void InitDefaultAnimationFrames();
void UpdateScreenState(int64_t now);
diff --git a/healthd/healthd_mode_charger_test.cpp b/healthd/healthd_mode_charger_test.cpp
new file mode 100644
index 0000000..f444f66
--- /dev/null
+++ b/healthd/healthd_mode_charger_test.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <health/utils.h>
+
+#include "healthd_mode_charger.h"
+
+using android::hardware::Return;
+using android::hardware::health::InitHealthdConfig;
+using std::string_literals::operator""s;
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::StrEq;
+using testing::Test;
+
+namespace android {
+
+// A replacement to ASSERT_* to be used in a forked process. When the condition is not met,
+// print a gtest message, then exit abnormally.
+class ChildAssertHelper : public std::stringstream {
+ public:
+ ChildAssertHelper(bool res, const char* expr, const char* file, int line) : res_(res) {
+ (*this) << file << ":" << line << ": `" << expr << "` evaluates to false\n";
+ }
+ ~ChildAssertHelper() {
+ EXPECT_TRUE(res_) << str();
+ if (!res_) exit(EX_SOFTWARE);
+ }
+
+ private:
+ bool res_;
+ DISALLOW_COPY_AND_ASSIGN(ChildAssertHelper);
+};
+#define CHILD_ASSERT_TRUE(expr) ChildAssertHelper(expr, #expr, __FILE__, __LINE__)
+
+// Run |test_body| in a chroot jail in a forked process. |subdir| is a sub-directory in testdata.
+// Within |test_body|,
+// - non-fatal errors may be reported using EXPECT_* macro as usual.
+// - fatal errors must be reported using CHILD_ASSERT_TRUE macro. ASSERT_* must not be used.
+void ForkTest(const std::string& subdir, const std::function<void(void)>& test_body) {
+ pid_t pid = fork();
+ ASSERT_GE(pid, 0) << "Fork fails: " << strerror(errno);
+ if (pid == 0) {
+ // child
+ CHILD_ASSERT_TRUE(
+ chroot((android::base::GetExecutableDirectory() + "/" + subdir).c_str()) != -1)
+ << "Failed to chroot to " << subdir << ": " << strerror(errno);
+ test_body();
+ // EXPECT_* macros may set the HasFailure bit without calling exit(). Set exit status
+ // accordingly.
+ exit(::testing::Test::HasFailure() ? EX_SOFTWARE : EX_OK);
+ }
+ // parent
+ int status;
+ ASSERT_NE(-1, waitpid(pid, &status, 0)) << "waitpid() fails: " << strerror(errno);
+ ASSERT_TRUE(WIFEXITED(status)) << "Test fails, waitpid() returns " << status;
+ ASSERT_EQ(EX_OK, WEXITSTATUS(status)) << "Test fails, child process returns " << status;
+}
+
+class MockHealth : public android::hardware::health::V2_1::IHealth {
+ MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, registerCallback,
+ (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
+ MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, unregisterCallback,
+ (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
+ MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, update, ());
+ MOCK_METHOD(Return<void>, getChargeCounter, (getChargeCounter_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getCurrentNow, (getCurrentNow_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getCurrentAverage, (getCurrentAverage_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getCapacity, (getCapacity_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getEnergyCounter, (getEnergyCounter_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getChargeStatus, (getChargeStatus_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getStorageInfo, (getStorageInfo_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getDiskStats, (getDiskStats_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getHealthInfo, (getHealthInfo_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getHealthConfig, (getHealthConfig_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, getHealthInfo_2_1, (getHealthInfo_2_1_cb _hidl_cb));
+ MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
+};
+
+class TestCharger : public Charger {
+ public:
+ // Inherit constructor.
+ using Charger::Charger;
+ // Expose protected functions to be used in tests.
+ void Init(struct healthd_config* config) override { Charger::Init(config); }
+ MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
+ MOCK_METHOD(int, CreateMultiDisplaySurface,
+ (const std::string& name, int* frames, int* fps, GRSurface*** surface));
+};
+
+// Intentionally leak TestCharger instance to avoid calling ~HealthLoop() because ~HealthLoop()
+// should never be called. But still verify expected calls upon destruction.
+class VerifiedTestCharger {
+ public:
+ VerifiedTestCharger(TestCharger* charger) : charger_(charger) {
+ testing::Mock::AllowLeak(charger_);
+ }
+ TestCharger& operator*() { return *charger_; }
+ TestCharger* operator->() { return charger_; }
+ ~VerifiedTestCharger() { testing::Mock::VerifyAndClearExpectations(charger_); }
+
+ private:
+ TestCharger* charger_;
+};
+
+// Do not use SetUp and TearDown of a test suite, as they will be invoked in the parent process, not
+// the child process. In particular, if the test suite contains mocks, they will not be verified in
+// the child process. Instead, create mocks within closures in each tests.
+void ExpectChargerResAt(const std::string& root) {
+ sp<NiceMock<MockHealth>> health(new NiceMock<MockHealth>());
+ VerifiedTestCharger charger(new NiceMock<TestCharger>(health));
+
+ // Only one frame in all testdata/**/animation.txt
+ GRSurface* multi[] = {nullptr};
+
+ EXPECT_CALL(*charger, CreateDisplaySurface(StrEq(root + "charger/battery_fail.png"), _))
+ .WillRepeatedly(Invoke([](const auto&, GRSurface** surface) {
+ *surface = nullptr;
+ return 0;
+ }));
+ EXPECT_CALL(*charger,
+ CreateMultiDisplaySurface(StrEq(root + "charger/battery_scale.png"), _, _, _))
+ .WillRepeatedly(Invoke([&](const auto&, int* frames, int* fps, GRSurface*** surface) {
+ *frames = arraysize(multi);
+ *fps = 60; // Unused fps value
+ *surface = multi;
+ return 0;
+ }));
+ struct healthd_config healthd_config;
+ InitHealthdConfig(&healthd_config);
+ charger->Init(&healthd_config);
+};
+
+// Test that if resources does not exist in /res or in /product/etc/res, load from /system.
+TEST(ChargerLoadAnimationRes, Empty) {
+ ForkTest("empty", std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
+}
+
+// Test loading everything from /res
+TEST(ChargerLoadAnimationRes, Legacy) {
+ ForkTest("legacy", std::bind(&ExpectChargerResAt, "/res/images/"));
+}
+
+// Test loading animation text from /res but images from /system if images does not exist under
+// /res.
+TEST(ChargerLoadAnimationRes, LegacyTextSystemImages) {
+ ForkTest("legacy_text_system_images",
+ std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
+}
+
+// Test loading everything from /product
+TEST(ChargerLoadAnimationRes, Product) {
+ ForkTest("product", std::bind(&ExpectChargerResAt, "/product/etc/res/images/"));
+}
+
+} // namespace android
diff --git a/healthd/testdata/Android.bp b/healthd/testdata/Android.bp
new file mode 100644
index 0000000..110c79a
--- /dev/null
+++ b/healthd/testdata/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+filegroup {
+ name: "libhealthd_charger_test_data",
+ srcs: ["**/*.*"],
+}
diff --git a/healthd/testdata/empty/ensure_directory_creation.txt b/healthd/testdata/empty/ensure_directory_creation.txt
new file mode 100644
index 0000000..36ceff4
--- /dev/null
+++ b/healthd/testdata/empty/ensure_directory_creation.txt
@@ -0,0 +1 @@
+File is placed to ensure directory is created on the device.
diff --git a/healthd/testdata/legacy/res/images/charger/battery_fail.png b/healthd/testdata/legacy/res/images/charger/battery_fail.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/healthd/testdata/legacy/res/images/charger/battery_fail.png
diff --git a/healthd/testdata/legacy/res/images/charger/battery_scale.png b/healthd/testdata/legacy/res/images/charger/battery_scale.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/healthd/testdata/legacy/res/images/charger/battery_scale.png
diff --git a/healthd/testdata/legacy/res/values/charger/animation.txt b/healthd/testdata/legacy/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/legacy/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt b/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/healthd/testdata/product/product/etc/res/images/charger/battery_fail.png b/healthd/testdata/product/product/etc/res/images/charger/battery_fail.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/healthd/testdata/product/product/etc/res/images/charger/battery_fail.png
diff --git a/healthd/testdata/product/product/etc/res/images/charger/battery_scale.png b/healthd/testdata/product/product/etc/res/images/charger/battery_scale.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/healthd/testdata/product/product/etc/res/images/charger/battery_scale.png
diff --git a/healthd/testdata/product/product/etc/res/values/charger/animation.txt b/healthd/testdata/product/product/etc/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/product/product/etc/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 51c5e60..2c0156e 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -559,21 +559,6 @@
return str->second.data();
}
-// This function is deprecated and replaced with android_lookupEventTag_len
-// since it will cause the map to change from Shared and backed by a file,
-// to Private Dirty and backed up by swap, albeit highly compressible. By
-// deprecating this function everywhere, we save 100s of MB of memory space.
-const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag) {
- size_t len;
- const char* tagStr = android_lookupEventTag_len(map, &len, tag);
-
- if (!tagStr) return tagStr;
- char* cp = const_cast<char*>(tagStr);
- cp += len;
- if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
- return tagStr;
-}
-
// Look up tagname, generate one if necessary, and return a tag
int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char* format, int prio) {
const char* ep = endOfTag(tagname);
diff --git a/liblog/include/log/event_tag_map.h b/liblog/include/log/event_tag_map.h
index f7ec208..4d0ebf9 100644
--- a/liblog/include/log/event_tag_map.h
+++ b/liblog/include/log/event_tag_map.h
@@ -40,14 +40,6 @@
void android_closeEventTagMap(EventTagMap* map);
/*
- * Look up a tag by index. Returns the tag string, or NULL if not found.
- */
-const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag)
- __attribute__((
- deprecated("use android_lookupEventTag_len() instead to minimize "
- "MAP_PRIVATE copy-on-write memory impact")));
-
-/*
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index f3d8022..6229e7c 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -25,7 +25,7 @@
struct backed_block {
unsigned int block;
- unsigned int len;
+ uint64_t len;
enum backed_block_type type;
union {
struct {
@@ -60,7 +60,7 @@
return bb->next;
}
-unsigned int backed_block_len(struct backed_block* bb) {
+uint64_t backed_block_len(struct backed_block* bb) {
return bb->len;
}
@@ -270,7 +270,7 @@
}
/* Queues a fill block of memory to be written to the specified data blocks */
-int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
+int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
@@ -287,7 +287,7 @@
}
/* Queues a block of memory to be written to the specified data blocks */
-int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
+int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
@@ -305,7 +305,7 @@
/* Queues a chunk of a file on disk to be written to the specified data blocks */
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
- unsigned int len, unsigned int block) {
+ uint64_t len, unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
@@ -322,7 +322,7 @@
}
/* Queues a chunk of a fd to be written to the specified data blocks */
-int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
+int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
index 3a75460..71a8969 100644
--- a/libsparse/backed_block.h
+++ b/libsparse/backed_block.h
@@ -29,18 +29,18 @@
BACKED_BLOCK_FILL,
};
-int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
+int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
unsigned int block);
-int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
+int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
unsigned int block);
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
- unsigned int len, unsigned int block);
-int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
+ uint64_t len, unsigned int block);
+int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
unsigned int block);
struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
struct backed_block* backed_block_iter_next(struct backed_block* bb);
-unsigned int backed_block_len(struct backed_block* bb);
+uint64_t backed_block_len(struct backed_block* bb);
unsigned int backed_block_block(struct backed_block* bb);
void* backed_block_data(struct backed_block* bb);
const char* backed_block_filename(struct backed_block* bb);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 3d5fb0c..2f75349 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -75,8 +75,7 @@
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_add_data(struct sparse_file *s,
- void *data, unsigned int len, unsigned int block);
+int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block);
/**
* sparse_file_add_fill - associate a fill chunk with a sparse file
@@ -93,8 +92,8 @@
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_add_fill(struct sparse_file *s,
- uint32_t fill_val, unsigned int len, unsigned int block);
+int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
+ unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
@@ -116,9 +115,8 @@
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_add_file(struct sparse_file *s,
- const char *filename, int64_t file_offset, unsigned int len,
- unsigned int block);
+int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
+ uint64_t len, unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
@@ -143,8 +141,8 @@
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_add_fd(struct sparse_file *s,
- int fd, int64_t file_offset, unsigned int len, unsigned int block);
+int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
+ unsigned int block);
/**
* sparse_file_write - write a sparse file to a file
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index b883c13..b2c5407 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -65,9 +65,9 @@
};
struct sparse_file_ops {
- int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
- int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
- int (*write_skip_chunk)(struct output_file* out, int64_t len);
+ int (*write_data_chunk)(struct output_file* out, uint64_t len, void* data);
+ int (*write_fill_chunk)(struct output_file* out, uint64_t len, uint32_t fill_val);
+ int (*write_skip_chunk)(struct output_file* out, uint64_t len);
int (*write_end_chunk)(struct output_file* out);
};
@@ -316,7 +316,7 @@
return 0;
}
-static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
+static int write_sparse_skip_chunk(struct output_file* out, uint64_t skip_len) {
chunk_header_t chunk_header;
int ret;
@@ -340,9 +340,10 @@
return 0;
}
-static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+static int write_sparse_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
chunk_header_t chunk_header;
- int rnd_up_len, count;
+ uint64_t rnd_up_len;
+ int count;
int ret;
/* Round up the fill length to a multiple of the block size */
@@ -370,9 +371,9 @@
return 0;
}
-static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_sparse_data_chunk(struct output_file* out, uint64_t len, void* data) {
chunk_header_t chunk_header;
- int rnd_up_len, zero_len;
+ uint64_t rnd_up_len, zero_len;
int ret;
/* Round up the data length to a multiple of the block size */
@@ -437,9 +438,9 @@
.write_end_chunk = write_sparse_end_chunk,
};
-static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_normal_data_chunk(struct output_file* out, uint64_t len, void* data) {
int ret;
- unsigned int rnd_up_len = ALIGN(len, out->block_size);
+ uint64_t rnd_up_len = ALIGN(len, out->block_size);
ret = out->ops->write(out, data, len);
if (ret < 0) {
@@ -453,10 +454,10 @@
return ret;
}
-static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+static int write_normal_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
int ret;
unsigned int i;
- unsigned int write_len;
+ uint64_t write_len;
/* Initialize fill_buf with the fill_val */
for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
@@ -464,7 +465,7 @@
}
while (len) {
- write_len = std::min(len, out->block_size);
+ write_len = std::min(len, (uint64_t)out->block_size);
ret = out->ops->write(out, out->fill_buf, write_len);
if (ret < 0) {
return ret;
@@ -476,7 +477,7 @@
return 0;
}
-static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
+static int write_normal_skip_chunk(struct output_file* out, uint64_t len) {
return out->ops->skip(out, len);
}
@@ -639,16 +640,16 @@
}
/* Write a contiguous region of data blocks from a memory buffer */
-int write_data_chunk(struct output_file* out, unsigned int len, void* data) {
+int write_data_chunk(struct output_file* out, uint64_t len, void* data) {
return out->sparse_ops->write_data_chunk(out, len, data);
}
/* Write a contiguous region of data blocks with a fill value */
-int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
return out->sparse_ops->write_fill_chunk(out, len, fill_val);
}
-int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
+int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
if (!m) return -errno;
@@ -656,7 +657,7 @@
}
/* Write a contiguous region of data blocks from a file */
-int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset) {
+int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset) {
int ret;
int file_fd = open(file, O_RDONLY | O_BINARY);
@@ -671,6 +672,6 @@
return ret;
}
-int write_skip_chunk(struct output_file* out, int64_t len) {
+int write_skip_chunk(struct output_file* out, uint64_t len) {
return out->sparse_ops->write_skip_chunk(out, len);
}
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 278430b..ecbcdf3 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -30,11 +30,11 @@
struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc);
-int write_data_chunk(struct output_file* out, unsigned int len, void* data);
-int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
-int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
-int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset);
-int write_skip_chunk(struct output_file* out, int64_t len);
+int write_data_chunk(struct output_file* out, uint64_t len, void* data);
+int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val);
+int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset);
+int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset);
+int write_skip_chunk(struct output_file* out, uint64_t len);
void output_file_close(struct output_file* out);
int read_all(int fd, void* buf, size_t len);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 8622b4c..396e7eb 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -50,21 +50,21 @@
free(s);
}
-int sparse_file_add_data(struct sparse_file* s, void* data, unsigned int len, unsigned int block) {
+int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block) {
return backed_block_add_data(s->backed_block_list, data, len, block);
}
-int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, unsigned int len,
+int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
unsigned int block) {
return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
}
int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
- unsigned int len, unsigned int block) {
+ uint64_t len, unsigned int block) {
return backed_block_add_file(s->backed_block_list, filename, file_offset, len, block);
}
-int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, unsigned int len,
+int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
unsigned int block) {
return backed_block_add_fd(s->backed_block_list, fd, file_offset, len, block);
}
diff --git a/logd/README.compression.md b/logd/README.compression.md
new file mode 100644
index 0000000..4ba634a
--- /dev/null
+++ b/logd/README.compression.md
@@ -0,0 +1,81 @@
+# Log Compression instead of Chatty in Android S
+
+## The problem
+
+* Log buffer space is precious, but suffers from the tragedy of the commons
+* Log spam fills the buffers making them less useful in logcat/bugreports
+* “Spam” is often in the eye of the beholder: which messages are important depends on what you’re trying to debug
+
+## The idea
+
+* Chatty isn’t helping as much as we’d hoped, and is surprisingly expensive
+* Compress logs to make more efficient use of the buffer
+* Address the root cause of log spam at its source:
+ * Do not hide log spam at runtime, which de-incentivize fixes
+ * Add presubmit coverage similar to SELinux violations to keep log spam down
+
+---
+
+## Chatty in Theory
+
+* Delete messages classified as spam to extend the range of logs from other sources
+* “Spam” defined as:
+ * Logs from UIDs whose logs consume over 12.5% of a log buffer
+ * Back-to-back exact duplicate messages
+
+## Chatty in Practice
+
+* Developer confusion about missing and de-duplicated logs
+* Lowered incentive to fix the root cause of bad logging behavior
+* High CPU overhead
+* Memory usage greatly exceeds configured buffer size
+* Only marginal increase in log range
+
+---
+
+## Log Compression in Theory
+
+* Store many more logs in the same log buffer size => better for diagnosis
+* Memory usage stays below configured log size => better system health
+* No gaps in logs, no de-duplicated logs => no developer confusion
+* No hiding bad behavior => increased accountability/incentive to fix root causes
+
+## Log Compression Preliminary Results
+
+* Captured 2, 5 day periods of full time personal usage of Pixel 4 and replayed the logs offline
+* Compression vs Chatty:
+ * **3.5x more log messages on average**
+ * **50% less CPU usage**
+ * **50% less memory usage**
+
+---
+
+## Log Messages in 1MB
+
+* The number of log messages still available in logcat after ‘Message Count’ messages have been logged to a 1MB log buffer
+* Note: ‘Simple’ is the Chatty code without log spam detection and without de-duplication.
+
+
+
+---
+
+## CPU Time
+
+* Total CPU time on ARM64 (Walleye) and 32bit x86 (Cuttlefish)
+* X axis represents different log buffer size configurations.
+ * Chatty uses significantly more CPU time at 1MB (the default Pixel configuration)
+ * Chatty scales poorly with increased log buffer sizes
+* Note: “simple” isn’t “compression without actually compressing”, it’s “chatty without doing the chatty elimination”, which is why “simple” is more expensive than “compression” on walleye.
+
+
+
+
+---
+
+## Memory Usage
+
+* The memory used by ‘Message Count’ messages, on both Walleye and Cuttlefish
+* Note: Chatty does not consider the metadata (UID, PID, timestamp, etc) in its calculation of log buffer size, so a 1MB log buffer will consume more than 1MB. Note that there are 8 log buffers, 5 of which are typically filled.
+
+
+
diff --git a/logd/doc_images/cpu_cuttlefish.png b/logd/doc_images/cpu_cuttlefish.png
new file mode 100644
index 0000000..8d809ca
--- /dev/null
+++ b/logd/doc_images/cpu_cuttlefish.png
Binary files differ
diff --git a/logd/doc_images/cpu_walleye.png b/logd/doc_images/cpu_walleye.png
new file mode 100644
index 0000000..39c951b
--- /dev/null
+++ b/logd/doc_images/cpu_walleye.png
Binary files differ
diff --git a/logd/doc_images/memory_usage.png b/logd/doc_images/memory_usage.png
new file mode 100644
index 0000000..434d6d3
--- /dev/null
+++ b/logd/doc_images/memory_usage.png
Binary files differ
diff --git a/logd/doc_images/total_log_count.png b/logd/doc_images/total_log_count.png
new file mode 100644
index 0000000..e73c2c1
--- /dev/null
+++ b/logd/doc_images/total_log_count.png
Binary files differ