diff --git a/adf/libadf/adf.cpp b/adf/libadf/adf.cpp index 60d8ef041..fd9c20895 100644 --- a/adf/libadf/adf.cpp +++ b/adf/libadf/adf.cpp @@ -132,8 +132,11 @@ int adf_get_device_data(struct adf_device *dev, struct adf_device_data *data) void adf_free_device_data(struct adf_device_data *data) { delete [] data->attachments; + data->attachments = nullptr; delete [] data->allowed_attachments; + data->allowed_attachments = nullptr; delete [] static_cast(data->custom_data); + data->custom_data = nullptr; } int adf_device_post(struct adf_device *dev, @@ -236,9 +239,10 @@ ssize_t adf_interfaces_for_overlay_engine(struct adf_device *dev, return err; std::vector ids; - for (size_t i = 0; i < data.n_allowed_attachments; i++) - if (data.allowed_attachments[i].overlay_engine == overlay_engine) - ids.push_back(data.allowed_attachments[i].interface); + if (data.allowed_attachments != nullptr) + for (size_t i = 0; i < data.n_allowed_attachments; i++) + if (data.allowed_attachments[i].overlay_engine == overlay_engine) + ids.push_back(data.allowed_attachments[i].interface); adf_free_device_data(&data); return adf_id_vector_to_array(ids, interfaces); @@ -450,9 +454,10 @@ ssize_t adf_overlay_engines_for_interface(struct adf_device *dev, return err; std::vector ids; - for (size_t i = 0; i < data.n_allowed_attachments; i++) - if (data.allowed_attachments[i].interface == interface) - ids.push_back(data.allowed_attachments[i].overlay_engine); + if (data.allowed_attachments != nullptr) + for (size_t i = 0; i < data.n_allowed_attachments; i++) + if (data.allowed_attachments[i].interface == interface) + ids.push_back(data.allowed_attachments[i].overlay_engine); return adf_id_vector_to_array(ids, overlay_engines); } @@ -551,7 +556,9 @@ int adf_get_overlay_engine_data(int fd, struct adf_overlay_engine_data *data) void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data) { delete [] data->supported_formats; + data->supported_formats = nullptr; delete [] static_cast(data->custom_data); + data->custom_data = nullptr; } bool adf_overlay_engine_supports_format(int fd, __u32 format) @@ -564,10 +571,12 @@ bool adf_overlay_engine_supports_format(int fd, __u32 format) if (err < 0) return false; - for (i = 0; i < data.n_supported_formats; i++) { - if (data.supported_formats[i] == format) { - ret = true; - break; + if (data.supported_formats != nullptr) { + for (i = 0; i < data.n_supported_formats; i++) { + if (data.supported_formats[i] == format) { + ret = true; + break; + } } } @@ -638,18 +647,18 @@ static bool adf_find_simple_post_overlay_engine(struct adf_device *dev, const __u32 *formats, size_t n_formats, adf_id_t interface, adf_id_t *overlay_engine) { - adf_id_t *engs; + adf_id_t *engs = nullptr; ssize_t n_engs = adf_overlay_engines_for_interface(dev, interface, &engs); - if (n_engs <= 0) + if (engs == nullptr) return false; - adf_id_t *filtered_engs; + adf_id_t *filtered_engs = nullptr; ssize_t n_filtered_engs = adf_overlay_engines_filter_by_format(dev, formats, n_formats, engs, n_engs, &filtered_engs); free(engs); - if (n_filtered_engs <= 0) + if (filtered_engs == nullptr) return false; *overlay_engine = filtered_engs[0]; @@ -700,17 +709,17 @@ int adf_find_simple_post_configuration(struct adf_device *dev, if (n_intfs < 0) return n_intfs; - else if (!n_intfs) + else if (!intfs) return -ENODEV; - adf_id_t *primary_intfs; + adf_id_t *primary_intfs = nullptr; ssize_t n_primary_intfs = adf_interfaces_filter_by_flag(dev, ADF_INTF_FLAG_PRIMARY, intfs, n_intfs, &primary_intfs); free(intfs); if (n_primary_intfs < 0) return n_primary_intfs; - else if (!n_primary_intfs) + else if (!primary_intfs) return -ENODEV; if (!formats) { diff --git a/bootstat/Android.bp b/bootstat/Android.bp index 8fc21713b..5e2d171ff 100644 --- a/bootstat/Android.bp +++ b/bootstat/Android.bp @@ -63,6 +63,9 @@ cc_binary { name: "bootstat", defaults: ["bootstat_defaults"], static_libs: ["libbootstat"], + shared_libs: [ + "libstatslog" + ], init_rc: ["bootstat.rc"], product_variables: { pdk: { diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index 4d9f1acf3..d909ec64c 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "boot_event_record_store.h" @@ -1026,6 +1027,16 @@ const BootloaderTimingMap GetBootLoaderTimings() { return timings; } +// Returns the total bootloader boot time from the ro.boot.boottime system property. +int32_t GetBootloaderTime(const BootloaderTimingMap& bootloader_timings) { + int32_t total_time = 0; + for (const auto& timing : bootloader_timings) { + total_time += timing.second; + } + + return total_time; +} + // Parses and records the set of bootloader stages and associated boot times // from the ro.boot.boottime system property. void RecordBootloaderTimings(BootEventRecordStore* boot_event_store, @@ -1039,11 +1050,10 @@ void RecordBootloaderTimings(BootEventRecordStore* boot_event_store, boot_event_store->AddBootEventWithValue("boottime.bootloader.total", total_time); } -// Records the closest estimation to the absolute device boot time, i.e., +// Returns the closest estimation to the absolute device boot time, i.e., // from power on to boot_complete, including bootloader times. -void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store, - const BootloaderTimingMap& bootloader_timings, - std::chrono::milliseconds uptime) { +std::chrono::milliseconds GetAbsoluteBootTime(const BootloaderTimingMap& bootloader_timings, + std::chrono::milliseconds uptime) { int32_t bootloader_time_ms = 0; for (const auto& timing : bootloader_timings) { @@ -1053,23 +1063,36 @@ void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store, } auto bootloader_duration = std::chrono::milliseconds(bootloader_time_ms); - auto absolute_total = - std::chrono::duration_cast(bootloader_duration + uptime); - boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total.count()); + return bootloader_duration + uptime; } -// Gets the boot time offset. This is useful when Android is running in a -// container, because the boot_clock is not reset when Android reboots. -std::chrono::nanoseconds GetBootTimeOffset() { - static const int64_t boottime_offset = - android::base::GetIntProperty("ro.boot.boottime_offset", 0); - return std::chrono::nanoseconds(boottime_offset); +// Records the closest estimation to the absolute device boot time in seconds. +// i.e. from power on to boot_complete, including bootloader times. +void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store, + std::chrono::milliseconds absolute_total) { + auto absolute_total_sec = std::chrono::duration_cast(absolute_total); + boot_event_store->AddBootEventWithValue("absolute_boot_time", absolute_total_sec.count()); } -// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME -// clock. -android::base::boot_clock::duration GetUptime() { - return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset(); +// Logs the total boot time and reason to statsd. +void LogBootInfoToStatsd(std::chrono::milliseconds end_time, + std::chrono::milliseconds total_duration, int32_t bootloader_duration_ms, + double time_since_last_boot_sec) { + const std::string reason(GetProperty(bootloader_reboot_reason_property)); + + if (reason.empty()) { + android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, "", "", + end_time.count(), total_duration.count(), + (int64_t)bootloader_duration_ms, + (int64_t)time_since_last_boot_sec * 1000); + return; + } + + const std::string system_reason(GetProperty(system_reboot_reason_property)); + android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, reason.c_str(), + system_reason.c_str(), end_time.count(), total_duration.count(), + (int64_t)bootloader_duration_ms, + (int64_t)time_since_last_boot_sec * 1000); } void SetSystemBootReason() { @@ -1088,6 +1111,20 @@ void SetSystemBootReason() { SetProperty(last_reboot_reason_property, ""); } +// Gets the boot time offset. This is useful when Android is running in a +// container, because the boot_clock is not reset when Android reboots. +std::chrono::nanoseconds GetBootTimeOffset() { + static const int64_t boottime_offset = + android::base::GetIntProperty("ro.boot.boottime_offset", 0); + return std::chrono::nanoseconds(boottime_offset); +} + +// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME +// clock. +android::base::boot_clock::duration GetUptime() { + return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset(); +} + // Records several metrics related to the time it takes to boot the device, // including disambiguating boot time on encrypted or non-encrypted devices. void RecordBootComplete() { @@ -1097,10 +1134,11 @@ void RecordBootComplete() { auto uptime_ns = GetUptime(); auto uptime_s = std::chrono::duration_cast(uptime_ns); time_t current_time_utc = time(nullptr); + time_t time_since_last_boot = 0; if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) { time_t last_boot_time_utc = record.second; - time_t time_since_last_boot = difftime(current_time_utc, last_boot_time_utc); + time_since_last_boot = difftime(current_time_utc, last_boot_time_utc); boot_event_store.AddBootEventWithValue("time_since_last_boot", time_since_last_boot); } @@ -1140,10 +1178,18 @@ void RecordBootComplete() { RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait"); const BootloaderTimingMap bootloader_timings = GetBootLoaderTimings(); + int32_t bootloader_boot_duration = GetBootloaderTime(bootloader_timings); RecordBootloaderTimings(&boot_event_store, bootloader_timings); auto uptime_ms = std::chrono::duration_cast(uptime_ns); - RecordAbsoluteBootTime(&boot_event_store, bootloader_timings, uptime_ms); + auto absolute_boot_time = GetAbsoluteBootTime(bootloader_timings, uptime_ms); + RecordAbsoluteBootTime(&boot_event_store, absolute_boot_time); + + auto boot_end_time_point = std::chrono::system_clock::now().time_since_epoch(); + auto boot_end_time = std::chrono::duration_cast(boot_end_time_point); + + LogBootInfoToStatsd(boot_end_time, absolute_boot_time, bootloader_boot_duration, + time_since_last_boot); } // Records the boot_reason metric by querying the ro.boot.bootreason system diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp index cc1714f01..b0ac2ef4f 100644 --- a/fastboot/fs.cpp +++ b/fastboot/fs.cpp @@ -177,6 +177,8 @@ static int generate_f2fs_image(const char* fileName, long long partSize, const s mkf2fs_args.push_back("encrypt"); mkf2fs_args.push_back("-O"); mkf2fs_args.push_back("quota"); + mkf2fs_args.push_back("-O"); + mkf2fs_args.push_back("verity"); mkf2fs_args.push_back(fileName); mkf2fs_args.push_back(nullptr); diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index 63a6839c5..845cca9dc 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp @@ -121,6 +121,7 @@ static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer) "-f", "-O", "encrypt", "-O", "quota", + "-O", "verity", "-w", "4096", fs_blkdev, size_str.c_str(), diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index afd722790..a347faf53 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -45,7 +45,7 @@ #define PWARNING PLOG(WARNING) << FS_MGR_TAG #define PERROR PLOG(ERROR) << FS_MGR_TAG -#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000" +#define CRYPTO_TMPFS_OPTIONS "size=512m,mode=0771,uid=1000,gid=1000" /* fstab has the following format: * diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk index 28f0b07ab..6d5d1eac4 100644 --- a/gatekeeperd/Android.mk +++ b/gatekeeperd/Android.mk @@ -32,6 +32,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libutils \ libcrypto \ + libkeystore_aidl \ libkeystore_binder \ libhidlbase \ libhidltransport \ diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index abb387c15..5f3ce3610 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -25,14 +25,15 @@ #include #include +#include #include #include #include #include // for password_handle_t #include #include -#include #include // For error code +#include #include #include #include @@ -317,11 +318,15 @@ public: // TODO: cache service? sp sm = defaultServiceManager(); sp binder = sm->getService(String16("android.security.keystore")); - sp service = interface_cast(binder); + sp service = + interface_cast(binder); if (service != NULL) { - auto ret = service->addAuthToken(*auth_token, *auth_token_length); - if (!ret.isOk()) { - ALOGE("Failure sending auth token to KeyStore: %" PRId32, int32_t(ret)); + std::vector auth_token_vector(*auth_token, + (*auth_token) + *auth_token_length); + int result = 0; + auto binder_result = service->addAuthToken(auth_token_vector, &result); + if (!binder_result.isOk() || !keystore::KeyStoreServiceReturnCode(result).isOk()) { + ALOGE("Failure sending auth token to KeyStore: %" PRId32, result); } } else { ALOGE("Unable to communicate with KeyStore"); diff --git a/healthd/Android.bp b/healthd/Android.bp index 7269b628c..6b00f81f1 100644 --- a/healthd/Android.bp +++ b/healthd/Android.bp @@ -1,6 +1,7 @@ cc_library_headers { name: "libhealthd_headers", vendor_available: true, + recovery_available: true, export_include_dirs: ["include"], header_libs: ["libbatteryservice_headers"], export_header_lib_headers: ["libbatteryservice_headers"], @@ -9,7 +10,9 @@ cc_library_headers { cc_library_static { name: "libbatterymonitor", srcs: ["BatteryMonitor.cpp"], + cflags: ["-Wall", "-Werror"], vendor_available: true, + recovery_available: true, export_include_dirs: ["include"], shared_libs: [ "libutils", @@ -18,3 +21,66 @@ cc_library_static { header_libs: ["libhealthd_headers"], export_header_lib_headers: ["libhealthd_headers"], } + +cc_defaults { + name: "android.hardware.health@2.0-service_defaults", + + cflags: [ + "-Wall", + "-Werror", + ], + + static_libs: [ + "android.hardware.health@2.0-impl", + "android.hardware.health@1.0-convert", + "libhealthservice", + "libhealthstoragedefault", + "libbatterymonitor", + ], + + shared_libs: [ + "libbase", + "libcutils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "android.hardware.health@2.0", + ], +} + +cc_binary { + name: "android.hardware.health@2.0-service", + defaults: ["android.hardware.health@2.0-service_defaults"], + + vendor: true, + relative_install_path: "hw", + init_rc: ["android.hardware.health@2.0-service.rc"], + srcs: [ + "HealthServiceDefault.cpp", + ], + + overrides: [ + "healthd", + ] +} + +cc_binary { + name: "healthd", + defaults: ["android.hardware.health@2.0-service_defaults"], + + init_rc: ["healthd.rc"], + srcs: [ + "HealthServiceHealthd.cpp", + ], + local_include_dirs: ["include"], + + shared_libs: [ + "android.hardware.health@1.0", + ], + + vintf_fragments: [ + "manifest_healthd.xml" + ], +} diff --git a/healthd/Android.mk b/healthd/Android.mk index 124490354..f7214c6cd 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -2,27 +2,6 @@ LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - healthd_mode_android.cpp \ - BatteryPropertiesRegistrar.cpp - -LOCAL_MODULE := libhealthd_android -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH) \ - $(LOCAL_PATH)/include - -LOCAL_STATIC_LIBRARIES := \ - libbatterymonitor \ - libbatteryservice \ - libutils \ - libbase \ - libcutils \ - liblog \ - libc \ - -include $(BUILD_STATIC_LIBRARY) - include $(CLEAR_VARS) LOCAL_MODULE := libhealthd_draw @@ -45,6 +24,8 @@ else LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0 endif +LOCAL_HEADER_LIBRARIES := libbatteryservice_headers + include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -68,6 +49,11 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ + android.hardware.health@2.0 \ + android.hardware.health@2.0-impl \ + android.hardware.health@1.0 \ + android.hardware.health@1.0-convert \ + libhealthstoragedefault \ libminui \ libpng \ libz \ @@ -92,7 +78,6 @@ LOCAL_CHARGER_NO_UI := true endif LOCAL_SRC_FILES := \ - healthd_common.cpp \ charger.cpp \ LOCAL_MODULE := charger @@ -106,14 +91,17 @@ LOCAL_CFLAGS := -Werror ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true) LOCAL_CFLAGS += -DCHARGER_NO_UI endif -ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),) -LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST) -endif -ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),) -LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW) -endif -LOCAL_STATIC_LIBRARIES := \ +CHARGER_STATIC_LIBRARIES := \ + android.hardware.health@2.0-impl \ + android.hardware.health@2.0 \ + android.hardware.health@1.0 \ + android.hardware.health@1.0-convert \ + libhidltransport \ + libhidlbase \ + libhwbinder_noltopgo \ + libhealthstoragedefault \ + libvndksupport \ libhealthd_charger \ libhealthd_draw \ libbatterymonitor \ @@ -124,6 +112,8 @@ LOCAL_STATIC_LIBRARIES := \ libm \ libc \ +LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES) + ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true) LOCAL_STATIC_LIBRARIES += \ libminui \ @@ -144,6 +134,21 @@ LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \ include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) +LOCAL_MODULE := charger_test +LOCAL_MODULE_TAGS := optional +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_CFLAGS := -Wall -Werror -DCHARGER_TEST -DCHARGER_NO_UI +LOCAL_STATIC_LIBRARIES := $(CHARGER_STATIC_LIBRARIES) +LOCAL_SRC_FILES := \ + charger.cpp \ + charger_test.cpp \ + +include $(BUILD_EXECUTABLE) + +CHARGER_STATIC_LIBRARIES := + ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true) define _add-charger-image include $$(CLEAR_VARS) @@ -171,41 +176,3 @@ include $(BUILD_PHONY_PACKAGE) _add-charger-image := _img_modules := endif # LOCAL_CHARGER_NO_UI - -### healthd ### -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - healthd_common.cpp \ - healthd.cpp \ - -LOCAL_MODULE := healthd -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include - -ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),) -LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST) -endif -ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),) -LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW) -endif - -LOCAL_STATIC_LIBRARIES := \ - libhealthd_android \ - libbatterymonitor \ - libbatteryservice \ - android.hardware.health@1.0-convert \ - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libbase \ - libutils \ - libcutils \ - liblog \ - libm \ - libc \ - libhidlbase \ - libhidltransport \ - android.hardware.health@1.0 \ - -include $(BUILD_EXECUTABLE) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index fa79d0bb2..80c5afe0d 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -88,6 +88,10 @@ BatteryMonitor::BatteryMonitor() initBatteryProperties(&props); } +struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor) { + return batteryMonitor->props; +} + int BatteryMonitor::getBatteryStatus(const char* status) { int ret; struct sysfsStringEnumMap batteryStatusMap[] = { @@ -531,12 +535,6 @@ void BatteryMonitor::init(struct healthd_config *hc) { POWER_SUPPLY_SYSFS_PATH, name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryVoltagePath = path; - } else { - path.clear(); - path.appendFormat("%s/%s/batt_vol", - POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryVoltagePath = path; } } @@ -586,12 +584,6 @@ void BatteryMonitor::init(struct healthd_config *hc) { name); if (access(path, R_OK) == 0) { mHealthdConfig->batteryTemperaturePath = path; - } else { - path.clear(); - path.appendFormat("%s/%s/batt_temp", - POWER_SUPPLY_SYSFS_PATH, name); - if (access(path, R_OK) == 0) - mHealthdConfig->batteryTemperaturePath = path; } } diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp deleted file mode 100644 index e51a06d5e..000000000 --- a/healthd/BatteryPropertiesRegistrar.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2013 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 "BatteryPropertiesRegistrar.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace android { - -void BatteryPropertiesRegistrar::publish( - const sp& service) { - defaultServiceManager()->addService(String16("batteryproperties"), service); -} - -void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) { - Vector > listenersCopy; - - // Binder currently may service an incoming oneway transaction whenever an - // outbound oneway call is made (if there is already a pending incoming - // oneway call waiting). This is considered a bug and may change in the - // future. For now, avoid recursive mutex lock while making outbound - // calls by making a local copy of the current list of listeners. - { - Mutex::Autolock _l(mRegistrationLock); - listenersCopy = mListeners; - } - for (size_t i = 0; i < listenersCopy.size(); i++) { - listenersCopy[i]->batteryPropertiesChanged(props); - } -} - -void BatteryPropertiesRegistrar::registerListener(const sp& listener) { - { - if (listener == NULL) - return; - Mutex::Autolock _l(mRegistrationLock); - // check whether this is a duplicate - for (size_t i = 0; i < mListeners.size(); i++) { - if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) { - return; - } - } - - mListeners.add(listener); - IInterface::asBinder(listener)->linkToDeath(this); - } - healthd_battery_update(); -} - -void BatteryPropertiesRegistrar::unregisterListener(const sp& listener) { - if (listener == NULL) - return; - Mutex::Autolock _l(mRegistrationLock); - for (size_t i = 0; i < mListeners.size(); i++) { - if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) { - IInterface::asBinder(mListeners[i])->unlinkToDeath(this); - mListeners.removeAt(i); - break; - } - } -} - -status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) { - return healthd_get_property(id, val); -} - -void BatteryPropertiesRegistrar::scheduleUpdate() { - healthd_battery_update(); -} - -status_t BatteryPropertiesRegistrar::dump(int fd, const Vector& /*args*/) { - IPCThreadState* self = IPCThreadState::self(); - const int pid = self->getCallingPid(); - const int uid = self->getCallingUid(); - if ((uid != AID_SHELL) && - !PermissionCache::checkPermission( - String16("android.permission.DUMP"), pid, uid)) - return PERMISSION_DENIED; - - healthd_dump_battery_state(fd); - return OK; -} - -void BatteryPropertiesRegistrar::binderDied(const wp& who) { - Mutex::Autolock _l(mRegistrationLock); - - for (size_t i = 0; i < mListeners.size(); i++) { - if (IInterface::asBinder(mListeners[i]) == who) { - mListeners.removeAt(i); - break; - } - } -} - -} // namespace android diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h deleted file mode 100644 index 14e914514..000000000 --- a/healthd/BatteryPropertiesRegistrar.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H -#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H - -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar, - public IBinder::DeathRecipient { -public: - void publish(const sp& service); - void notifyListeners(const struct BatteryProperties& props); - void scheduleUpdate(); - -private: - Mutex mRegistrationLock; - Vector > mListeners; - - void registerListener(const sp& listener); - void unregisterListener(const sp& listener); - status_t getProperty(int id, struct BatteryProperty *val); - status_t dump(int fd, const Vector& args); - void binderDied(const wp& who); -}; - -}; // namespace android - -#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H diff --git a/healthd/HealthServiceDefault.cpp b/healthd/HealthServiceDefault.cpp new file mode 100644 index 000000000..89ecc2fa4 --- /dev/null +++ b/healthd/HealthServiceDefault.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +void healthd_board_init(struct healthd_config*) { + // Implementation-defined init logic goes here. + // 1. config->periodic_chores_interval_* variables + // 2. config->battery*Path variables + // 3. config->energyCounter. In this implementation, energyCounter is not defined. + + // use defaults +} + +int healthd_board_battery_update(struct android::BatteryProperties*) { + // Implementation-defined update logic goes here. An implementation + // can make modifications to prop before broadcasting it to all callbacks. + + // return 0 to log periodic polled battery status to kernel log + return 0; +} + +int main() { + return health_service_main(); +} diff --git a/healthd/HealthServiceHealthd.cpp b/healthd/HealthServiceHealthd.cpp new file mode 100644 index 000000000..5fd2597d6 --- /dev/null +++ b/healthd/HealthServiceHealthd.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "healthd" +#include + +#include +#include +#include +#include +#include +#include + +using android::OK; +using android::NAME_NOT_FOUND; +using android::hardware::health::V1_0::HealthConfig; +using android::hardware::health::V1_0::HealthInfo; +using android::hardware::health::V1_0::Result; +using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig; +using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig; +using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo; +using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo; + +using IHealthLegacy = android::hardware::health::V1_0::IHealth; + +static android::sp gHealth_1_0; + +static int healthd_board_get_energy_counter(int64_t* energy) { + if (gHealth_1_0 == nullptr) { + return NAME_NOT_FOUND; + } + + Result result = Result::NOT_SUPPORTED; + gHealth_1_0->energyCounter([energy, &result](Result ret, int64_t energyOut) { + result = ret; + *energy = energyOut; + }); + + return result == Result::SUCCESS ? OK : NAME_NOT_FOUND; +} + +void healthd_board_init(struct healthd_config* config) { + gHealth_1_0 = IHealthLegacy::getService(); + + if (gHealth_1_0 == nullptr) { + return; + } + + HealthConfig halConfig{}; + convertToHealthConfig(config, halConfig); + gHealth_1_0->init(halConfig, [config](const auto& halConfigOut) { + convertFromHealthConfig(halConfigOut, config); + // always redirect energy counter queries + config->energyCounter = healthd_board_get_energy_counter; + }); + LOG(INFO) << LOG_TAG << ": redirecting calls to 1.0 health HAL"; +} + +// TODO(b/68724651): Move this function into healthd_mode_service_2_0_battery_update +// with logthis returned. +int healthd_board_battery_update(struct android::BatteryProperties* props) { + int logthis = 0; + + if (gHealth_1_0 == nullptr) { + return logthis; + } + + HealthInfo info; + convertToHealthInfo(props, info); + gHealth_1_0->update(info, [props, &logthis](int32_t ret, const auto& infoOut) { + logthis = ret; + convertFromHealthInfo(infoOut, props); + }); + + return logthis; +} + +int main() { + return health_service_main("backup"); +} diff --git a/healthd/android.hardware.health@2.0-service.rc b/healthd/android.hardware.health@2.0-service.rc new file mode 100644 index 000000000..dca0ccc0e --- /dev/null +++ b/healthd/android.hardware.health@2.0-service.rc @@ -0,0 +1,5 @@ +service health-hal-2-0 /vendor/bin/hw/android.hardware.health@2.0-service + class hal + user system + group system + file /dev/kmsg w diff --git a/healthd/charger.cpp b/healthd/charger.cpp index 5a8fe1a8b..43e7fd5b8 100644 --- a/healthd/charger.cpp +++ b/healthd/charger.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "charger" #define KLOG_LEVEL 6 +#include #include #include @@ -62,7 +63,9 @@ static struct healthd_mode_ops charger_ops = { }; #endif -static void healthd_mode_nop_init(struct healthd_config* /*config*/) { +static void healthd_mode_nop_init(struct healthd_config* config) { + using android::hardware::health::V2_0::implementation::Health; + Health::initInstance(config); } static int healthd_mode_nop_preparetowait(void) { @@ -76,7 +79,7 @@ static void healthd_mode_nop_battery_update( struct android::BatteryProperties* /*props*/) { } -int main(int argc, char **argv) { +int healthd_charger_main(int argc, char** argv) { int ch; healthd_mode_ops = &charger_ops; @@ -100,3 +103,9 @@ int main(int argc, char **argv) { return healthd_main(); } + +#ifndef CHARGER_TEST +int main(int argc, char** argv) { + return healthd_charger_main(argc, argv); +} +#endif diff --git a/healthd/charger_test.cpp b/healthd/charger_test.cpp new file mode 100644 index 000000000..a7e216196 --- /dev/null +++ b/healthd/charger_test.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "charger_test" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_THIS(fmt, ...) \ + ALOGE(fmt, ##__VA_ARGS__); \ + printf(fmt "\n", ##__VA_ARGS__); + +template +class Atomic { + public: + Atomic(T&& init) : mValue(std::move(init)) {} + void set(T&& newVal) { + { + std::lock_guard lock(mMutex); + mValue = std::move(newVal); + } + mChanged.notify_all(); + } + bool waitFor(long ms, const T& expectVal) { + std::unique_lock lock(mMutex); + return mChanged.wait_for(lock, std::chrono::milliseconds(ms), + [this, &expectVal] { return mValue == expectVal; }); + } + private: + std::mutex mMutex; + std::condition_variable mChanged; + T mValue; +}; + +Atomic& getUpdateNotifier() { + static Atomic val(false); + return val; +} + +int energyCounter(int64_t* counter) { + *counter = 0xEC12345; + return 0; +} + +const char* createFile(const char* path, const char* content) { + std::ofstream stream(path); + if (!stream.is_open()) { + LOG_THIS("Cannot create file %s", path); + return NULL; + } + stream << content << std::endl; + stream.close(); + return path; +} + +std::string openToString(const char* path) { + std::ifstream stream(path); + if (!stream.is_open()) { + LOG_THIS("Cannot open file %s", path); + return ""; + } + return std::string(std::istreambuf_iterator(stream), std::istreambuf_iterator()); +} + +int expectContains(const std::string& content, const std::vector& fields) { + int status = 0; + for (const auto& field : fields) { + auto pos = content.find(field); + if (pos == std::string::npos) { + LOG_THIS("Cannot find substr '%s'", field.c_str()); + status = 1; + } + } + return status; +} + +::android::hardware::hidl_handle createHidlHandle(const char* filepath) { + int fd = creat(filepath, S_IRUSR | S_IWUSR); + if (fd < 0) return {}; + native_handle_t* nativeHandle = native_handle_create(1, 0); + nativeHandle->data[0] = fd; + ::android::hardware::hidl_handle handle; + handle.setTo(nativeHandle, true /* shouldOwn */); + return handle; +} + +void healthd_board_init(struct healthd_config* config) { + config->periodic_chores_interval_fast = 60; + config->periodic_chores_interval_slow = 600; + + config->batteryStatusPath = createFile("/data/local/tmp/batteryStatus", "Not charging"); + config->batteryHealthPath = createFile("/data/local/tmp/batteryHealth", "Unspecified failure"); + config->batteryPresentPath = createFile("/data/local/tmp/batteryPresent", "1"); + config->batteryCapacityPath = createFile("/data/local/tmp/batteryCapacity", "47"); + config->batteryVoltagePath = createFile("/data/local/tmp/batteryVoltage", "45000"); + config->batteryTemperaturePath = createFile("/data/local/tmp/batteryTemperature", "987"); + config->batteryTechnologyPath = createFile("/data/local/tmp/batteryTechnology", "NiCd"); + config->batteryCurrentNowPath = createFile("/data/local/tmp/batteryCurrentNow", "99000"); + config->batteryCurrentAvgPath = createFile("/data/local/tmp/batteryCurrentAvg", "98000"); + config->batteryChargeCounterPath = createFile("/data/local/tmp/batteryChargeCounter", "600"); + config->batteryFullChargePath = createFile("/data/local/tmp/batteryFullCharge", "3515547"); + config->batteryCycleCountPath = createFile("/data/local/tmp/batteryCycleCount", "77"); + + config->energyCounter = energyCounter; + config->boot_min_cap = 50; + config->screen_on = NULL; +} + +int healthd_board_battery_update(struct android::BatteryProperties*) { + getUpdateNotifier().set(true /* updated */); + + // return 0 to log periodic polled battery status to kernel log + return 0; +} + +extern int healthd_charger_main(int argc, char** argv); + +int main(int argc, char** argv) { + using android::hardware::health::V2_0::implementation::Health; + + const char* dumpFile = "/data/local/tmp/dump.txt"; + + std::thread bgThread([=] { + healthd_charger_main(argc, argv); + }); + + // wait for healthd_init to finish + if (!getUpdateNotifier().waitFor(1000 /* wait ms */, true /* updated */)) { + LOG_THIS("Time out."); + exit(1); + } + + Health::getImplementation()->debug(createHidlHandle(dumpFile), {} /* options */); + + std::string content = openToString(dumpFile); + int status = expectContains(content, { + "status: 4", + "health: 6", + "present: 1", + "level: 47", + "voltage: 45", + "temp: 987", + "current now: 99000", + "current avg: 98000", + "charge counter: 600", + "current now: 99", + "cycle count: 77", + "Full charge: 3515547" + }); + + if (status == 0) { + LOG_THIS("Test success."); + } else { + LOG_THIS("Actual dump:\n%s", content.c_str()); + } + + exit(status); // force bgThread to exit +} diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp deleted file mode 100644 index ed1971a97..000000000 --- a/healthd/healthd.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "healthd" -#define KLOG_LEVEL 6 - -#include - -#include -#include -#include -#include - -#include -#include -#include - -using namespace android; - -using IHealth = ::android::hardware::health::V1_0::IHealth; -using Result = ::android::hardware::health::V1_0::Result; -using HealthConfig = ::android::hardware::health::V1_0::HealthConfig; -using HealthInfo = ::android::hardware::health::V1_0::HealthInfo; - -using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig; -using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig; -using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo; -using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo; - -// device specific hal interface; -static sp gHealth; - -// main healthd loop -extern int healthd_main(void); - -// Android mode -extern void healthd_mode_android_init(struct healthd_config *config); -extern int healthd_mode_android_preparetowait(void); -extern void healthd_mode_android_heartbeat(void); -extern void healthd_mode_android_battery_update( - struct android::BatteryProperties *props); - -static struct healthd_mode_ops android_ops = { - .init = healthd_mode_android_init, - .preparetowait = healthd_mode_android_preparetowait, - .heartbeat = healthd_mode_android_heartbeat, - .battery_update = healthd_mode_android_battery_update, -}; - -// default energy counter property redirect to talk to device -// HAL -static int healthd_board_get_energy_counter(int64_t *energy) { - - if (gHealth == nullptr) { - return NAME_NOT_FOUND; - } - - Result result = Result::NOT_SUPPORTED; - gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) { - result = ret; - *energy = energyOut; - }); - - return result == Result::SUCCESS ? OK : NAME_NOT_FOUND; -} - -void healthd_board_init(struct healthd_config *config) { - - // Initialize the board HAL - Equivalent of healthd_board_init(config) - // in charger/recovery mode. - - gHealth = IHealth::getService(); - if (gHealth == nullptr) { - KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n"); - return; - } - - HealthConfig halConfig; - convertToHealthConfig(config, halConfig); - gHealth->init(halConfig, [=] (const auto &halConfigOut) { - convertFromHealthConfig(halConfigOut, config); - // always redirect energy counter queries - config->energyCounter = healthd_board_get_energy_counter; - }); -} - -int healthd_board_battery_update(struct android::BatteryProperties *props) { - int logthis = 0; - - if (gHealth == nullptr) { - return logthis; - } - - HealthInfo info; - convertToHealthInfo(props, info); - gHealth->update(info, - [=, &logthis] (int32_t ret, const auto &infoOut) { - logthis = ret; - convertFromHealthInfo(infoOut, props); - }); - - return logthis; -} - -int main(int /*argc*/, char ** /*argv*/) { - - healthd_mode_ops = &android_ops; - - return healthd_main(); -} diff --git a/healthd/healthd.rc b/healthd/healthd.rc new file mode 100644 index 000000000..8e2ebb609 --- /dev/null +++ b/healthd/healthd.rc @@ -0,0 +1,4 @@ +service healthd /system/bin/healthd + class hal + critical + group root system wakelock diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp deleted file mode 100644 index 659991918..000000000 --- a/healthd/healthd_common.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "healthd-common" -#define KLOG_LEVEL 6 - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace android; - -#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST - // Periodic chores fast interval in seconds - #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1) -#else - #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST) -#endif - -#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW - // Periodic chores fast interval in seconds - #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10) -#else - #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW) -#endif - -static struct healthd_config healthd_config = { - .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST, - .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW, - .batteryStatusPath = String8(String8::kEmptyString), - .batteryHealthPath = String8(String8::kEmptyString), - .batteryPresentPath = String8(String8::kEmptyString), - .batteryCapacityPath = String8(String8::kEmptyString), - .batteryVoltagePath = String8(String8::kEmptyString), - .batteryTemperaturePath = String8(String8::kEmptyString), - .batteryTechnologyPath = String8(String8::kEmptyString), - .batteryCurrentNowPath = String8(String8::kEmptyString), - .batteryCurrentAvgPath = String8(String8::kEmptyString), - .batteryChargeCounterPath = String8(String8::kEmptyString), - .batteryFullChargePath = String8(String8::kEmptyString), - .batteryCycleCountPath = String8(String8::kEmptyString), - .energyCounter = NULL, - .boot_min_cap = 0, - .screen_on = NULL, -}; - -static int eventct; -static int epollfd; - -#define POWER_SUPPLY_SUBSYSTEM "power_supply" - -// epoll_create() parameter is actually unused -#define MAX_EPOLL_EVENTS 40 -static int uevent_fd; -static int wakealarm_fd; - -// -1 for no epoll timeout -static int awake_poll_interval = -1; - -static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST; - -static BatteryMonitor* gBatteryMonitor; - -struct healthd_mode_ops *healthd_mode_ops; - -int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) { - struct epoll_event ev; - - ev.events = EPOLLIN; - - if (wakeup == EVENT_WAKEUP_FD) - ev.events |= EPOLLWAKEUP; - - ev.data.ptr = (void *)handler; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { - KLOG_ERROR(LOG_TAG, - "epoll_ctl failed; errno=%d\n", errno); - return -1; - } - - eventct++; - return 0; -} - -static void wakealarm_set_interval(int interval) { - struct itimerspec itval; - - if (wakealarm_fd == -1) - return; - - wakealarm_wake_interval = interval; - - if (interval == -1) - interval = 0; - - itval.it_interval.tv_sec = interval; - itval.it_interval.tv_nsec = 0; - itval.it_value.tv_sec = interval; - itval.it_value.tv_nsec = 0; - - if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1) - KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n"); -} - -status_t healthd_get_property(int id, struct BatteryProperty *val) { - return gBatteryMonitor->getProperty(id, val); -} - -void healthd_battery_update(void) { - // Fast wake interval when on charger (watch for overheat); - // slow wake interval when on battery (watch for drained battery). - - int new_wake_interval = gBatteryMonitor->update() ? - healthd_config.periodic_chores_interval_fast : - healthd_config.periodic_chores_interval_slow; - - if (new_wake_interval != wakealarm_wake_interval) - wakealarm_set_interval(new_wake_interval); - - // During awake periods poll at fast rate. If wake alarm is set at fast - // rate then just use the alarm; if wake alarm is set at slow rate then - // poll at fast rate while awake and let alarm wake up at slow rate when - // asleep. - - if (healthd_config.periodic_chores_interval_fast == -1) - awake_poll_interval = -1; - else - awake_poll_interval = - new_wake_interval == healthd_config.periodic_chores_interval_fast ? - -1 : healthd_config.periodic_chores_interval_fast * 1000; -} - -void healthd_dump_battery_state(int fd) { - gBatteryMonitor->dumpState(fd); - fsync(fd); -} - -static void periodic_chores() { - healthd_battery_update(); -} - -#define UEVENT_MSG_LEN 2048 -static void uevent_event(uint32_t /*epevents*/) { - char msg[UEVENT_MSG_LEN+2]; - char *cp; - int n; - - n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN); - if (n <= 0) - return; - if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ - return; - - msg[n] = '\0'; - msg[n+1] = '\0'; - cp = msg; - - while (*cp) { - if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) { - healthd_battery_update(); - break; - } - - /* advance to after the next \0 */ - while (*cp++) - ; - } -} - -static void uevent_init(void) { - uevent_fd = uevent_open_socket(64*1024, true); - - if (uevent_fd < 0) { - KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); - return; - } - - fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD)) - KLOG_ERROR(LOG_TAG, - "register for uevent events failed\n"); -} - -static void wakealarm_event(uint32_t /*epevents*/) { - unsigned long long wakeups; - - if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) { - KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n"); - return; - } - - periodic_chores(); -} - -static void wakealarm_init(void) { - wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); - if (wakealarm_fd == -1) { - KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); - return; - } - - if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD)) - KLOG_ERROR(LOG_TAG, - "Registration of wakealarm event failed\n"); - - wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); -} - -static void healthd_mainloop(void) { - int nevents = 0; - while (1) { - struct epoll_event events[eventct]; - int timeout = awake_poll_interval; - int mode_timeout; - - /* Don't wait for first timer timeout to run periodic chores */ - if (!nevents) - periodic_chores(); - - healthd_mode_ops->heartbeat(); - - mode_timeout = healthd_mode_ops->preparetowait(); - if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) - timeout = mode_timeout; - nevents = epoll_wait(epollfd, events, eventct, timeout); - if (nevents == -1) { - if (errno == EINTR) - continue; - KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n"); - break; - } - - for (int n = 0; n < nevents; ++n) { - if (events[n].data.ptr) - (*(void (*)(int))events[n].data.ptr)(events[n].events); - } - } - - return; -} - -static int healthd_init() { - epollfd = epoll_create(MAX_EPOLL_EVENTS); - if (epollfd == -1) { - KLOG_ERROR(LOG_TAG, - "epoll_create failed; errno=%d\n", - errno); - return -1; - } - - healthd_board_init(&healthd_config); - healthd_mode_ops->init(&healthd_config); - wakealarm_init(); - uevent_init(); - gBatteryMonitor = new BatteryMonitor(); - gBatteryMonitor->init(&healthd_config); - return 0; -} - -int healthd_main() { - int ret; - - klog_set_level(KLOG_LEVEL); - - if (!healthd_mode_ops) { - KLOG_ERROR("healthd ops not set, exiting\n"); - exit(1); - } - - ret = healthd_init(); - if (ret) { - KLOG_ERROR("Initialization failed, exiting\n"); - exit(2); - } - - healthd_mainloop(); - KLOG_ERROR("Main loop terminated, exiting\n"); - return 3; -} diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp deleted file mode 100644 index c6123137a..000000000 --- a/healthd/healthd_mode_android.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "healthd-android" - -#include -#include "BatteryPropertiesRegistrar.h" - -#include -#include -#include -#include - -using namespace android; - -static int gBinderFd; -static sp gBatteryPropertiesRegistrar; - -void healthd_mode_android_battery_update( - struct android::BatteryProperties *props) { - if (gBatteryPropertiesRegistrar != NULL) - gBatteryPropertiesRegistrar->notifyListeners(*props); - - return; -} - -int healthd_mode_android_preparetowait(void) { - IPCThreadState::self()->flushCommands(); - return -1; -} - -void healthd_mode_android_heartbeat(void) { -} - -static void binder_event(uint32_t /*epevents*/) { - IPCThreadState::self()->handlePolledCommands(); -} - -void healthd_mode_android_init(struct healthd_config* /*config*/) { - ProcessState::self()->setThreadPoolMaxThreadCount(0); - IPCThreadState::self()->disableBackgroundScheduling(true); - IPCThreadState::self()->setupPolling(&gBinderFd); - - if (gBinderFd >= 0) { - if (healthd_register_event(gBinderFd, binder_event)) - KLOG_ERROR(LOG_TAG, - "Register for binder events failed\n"); - } - - gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); - gBatteryPropertiesRegistrar->publish(gBatteryPropertiesRegistrar); -} diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp index f1fe5cd21..56a9f8691 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -49,6 +49,7 @@ #include "AnimationParser.h" #include "healthd_draw.h" +#include #include using namespace android; @@ -612,6 +613,8 @@ animation* init_animation() { } void healthd_mode_charger_init(struct healthd_config* config) { + using android::hardware::health::V2_0::implementation::Health; + int ret; charger* charger = &charger_state; int i; @@ -666,6 +669,10 @@ void healthd_mode_charger_init(struct healthd_config* config) { charger->next_screen_transition = -1; charger->next_key_check = -1; charger->next_pwr_check = -1; + + // Initialize Health implementation (which initializes the internal BatteryMonitor). + Health::initInstance(config); + healthd_config = config; charger->boot_min_cap = config->boot_min_cap; } diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h index 97435c752..4d1d53f2c 100644 --- a/healthd/include/healthd/BatteryMonitor.h +++ b/healthd/include/healthd/BatteryMonitor.h @@ -42,6 +42,7 @@ class BatteryMonitor { int getChargeStatus(); status_t getProperty(int id, struct BatteryProperty *val); void dumpState(int fd); + friend struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor); private: struct healthd_config *mHealthdConfig; diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h index 17efbd62a..c01e8d747 100644 --- a/healthd/include/healthd/healthd.h +++ b/healthd/include/healthd/healthd.h @@ -81,10 +81,6 @@ enum EventWakeup { // Global helper functions int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup = EVENT_NO_WAKEUP_FD); -void healthd_battery_update(); -android::status_t healthd_get_property(int id, - struct android::BatteryProperty *val); -void healthd_dump_battery_state(int fd); struct healthd_mode_ops { void (*init)(struct healthd_config *config); diff --git a/healthd/manifest_healthd.xml b/healthd/manifest_healthd.xml new file mode 100644 index 000000000..097a7d87a --- /dev/null +++ b/healthd/manifest_healthd.xml @@ -0,0 +1,11 @@ + + + android.hardware.health + hwbinder + 2.0 + + IHealth + backup + + + diff --git a/init/stable_properties.h b/init/stable_properties.h index 05b2acb60..4972d101f 100644 --- a/init/stable_properties.h +++ b/init/stable_properties.h @@ -36,6 +36,7 @@ static const std::set kExportedActionableProperties = { "init.svc.zygote", "persist.bluetooth.btsnoopenable", "persist.sys.crash_rcu", + "persist.sys.usb.usbradio.config", "persist.sys.zram_enabled", "ro.board.platform", "ro.bootmode", diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc index 1eab46cb4..1915f22ba 100644 --- a/libappfuse/FuseBuffer.cc +++ b/libappfuse/FuseBuffer.cc @@ -149,8 +149,8 @@ bool SetupMessageSockets(base::unique_fd (*result)[2]) { } constexpr int kMaxMessageSize = sizeof(FuseBuffer); - if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0 || - setsockopt(fds[1], SOL_SOCKET, SO_SNDBUFFORCE, &kMaxMessageSize, sizeof(int)) != 0) { + if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0 || + setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, &kMaxMessageSize, sizeof(int)) != 0) { PLOG(ERROR) << "Failed to update buffer size for socket"; return false; } diff --git a/libappfuse/include/libappfuse/FuseBuffer.h b/libappfuse/include/libappfuse/FuseBuffer.h index 7a70bf3b4..30638155f 100644 --- a/libappfuse/include/libappfuse/FuseBuffer.h +++ b/libappfuse/include/libappfuse/FuseBuffer.h @@ -25,7 +25,7 @@ namespace fuse { // The numbers came from sdcard.c. // Maximum number of bytes to write/read in one request/one reply. -constexpr size_t kFuseMaxWrite = 256 * 1024; +constexpr size_t kFuseMaxWrite = 128 * 1024; constexpr size_t kFuseMaxRead = 128 * 1024; constexpr int32_t kFuseSuccess = 0; diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 48def6f95..af8f0a2f2 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -62,7 +62,7 @@ static inline uint64_t get8LE(const uint8_t* src) { static const struct fs_path_config android_dirs[] = { // clang-format off { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, - { 00500, AID_ROOT, AID_ROOT, 0, "config" }, + { 00555, AID_ROOT, AID_ROOT, 0, "config" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" }, diff --git a/libmetricslogger/OWNERS b/libmetricslogger/OWNERS index 7fe044326..6a6fba2ad 100644 --- a/libmetricslogger/OWNERS +++ b/libmetricslogger/OWNERS @@ -1 +1,2 @@ +cwren@google.com jhawkins@google.com diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h index 2c768695d..c305db2da 100644 --- a/libmetricslogger/include/metricslogger/metrics_logger.h +++ b/libmetricslogger/include/metricslogger/metrics_logger.h @@ -47,6 +47,8 @@ class ComplexEventLogger { public: // Create a complex event with category|category|. explicit ComplexEventLogger(int category); + // Set the package name that this event originates from. + void SetPackageName(const std::string& package_name); // Add tagged data to the event, with the given tag and integer value. void AddTaggedData(int tag, int32_t value); // Add tagged data to the event, with the given tag and string value. @@ -70,14 +72,49 @@ enum { LOGBUILDER_VALUE = 802, LOGBUILDER_COUNTER = 803, LOGBUILDER_HISTOGRAM = 804, + LOGBUILDER_PACKAGENAME = 806, ACTION_BOOT = 1098, FIELD_PLATFORM_REASON = 1099, + FIELD_DURATION_MILLIS = 1304, + + FIELD_END_BATTERY_PERCENT = 1308, + ACTION_HIDDEN_API_ACCESSED = 1391, FIELD_HIDDEN_API_ACCESS_METHOD = 1392, FIELD_HIDDEN_API_ACCESS_DENIED = 1393, FIELD_HIDDEN_API_SIGNATURE = 1394, + + ACTION_USB_CONNECTOR_CONNECTED = 1422, + ACTION_USB_CONNECTOR_DISCONNECTED = 1423, + ACTION_USB_AUDIO_CONNECTED = 1424, + FIELD_USB_AUDIO_VIDPID = 1425, + ACTION_USB_AUDIO_DISCONNECTED = 1426, + ACTION_HARDWARE_FAILED = 1427, + FIELD_HARDWARE_TYPE = 1428, + FIELD_HARDWARE_FAILURE_CODE = 1429, + ACTION_PHYSICAL_DROP = 1430, + FIELD_CONFIDENCE_PERCENT = 1431, + FIELD_ACCEL_MILLI_G = 1432, + ACTION_BATTERY_HEALTH = 1433, + FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434, + FIELD_BATTERY_TEMPERATURE_DECI_C = 1435, + FIELD_BATTERY_VOLTAGE_UV = 1436, + FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE_UV = 1437, + ACTION_BATTERY_CHARGE_CYCLES = 1438, + FIELD_BATTERY_CHARGE_CYCLES = 1439, + + ACTION_SLOW_IO = 1442, + FIELD_IO_OPERATION_TYPE = 1443, + FIELD_IO_OPERATION_COUNT = 1444, + ACTION_SPEAKER_IMPEDANCE = 1445, + FIELD_SPEAKER_IMPEDANCE_MILLIOHMS = 1446, + FIELD_SPEAKER_LOCATION = 1447, + FIELD_BATTERY_RESISTANCE_UOHMS = 1448, + FIELD_BATTERY_CURRENT_UA = 1449, + FIELD_HARDWARE_LOCATION = 1450, + ACTION_BATTERY_CAUSED_SHUTDOWN = 1441, }; enum { @@ -91,5 +128,30 @@ enum { ACCESS_METHOD_LINKING = 3, }; +enum HardwareType { + HARDWARE_UNKNOWN = 0, + HARDWARE_MICROPHONE = 1, + HARDWARE_CODEC = 2, + HARDWARE_SPEAKER = 3, + HARDWARE_FINGERPRINT = 4, +}; + +enum HardwareFailureCode { + HARDWARE_FAILURE_UNKNOWN = 0, + HARDWARE_FAILURE_COMPLETE = 1, + HARDWARE_FAILURE_SPEAKER_HIGH_Z = 2, + HARDWARE_FAILURE_SPEAKER_SHORT = 3, + HARDWARE_FAILURE_FINGERPRINT_SENSOR_BROKEN = 4, + HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5, +}; + +enum IoOperation { + IOOP_UNKNOWN = 0, + IOOP_READ = 1, + IOOP_WRITE = 2, + IOOP_UNMAP = 3, + IOOP_SYNC = 4, +}; + } // namespace metricslogger } // namespace android diff --git a/libmetricslogger/metrics_logger.cpp b/libmetricslogger/metrics_logger.cpp index 912fa1281..6a32153c6 100644 --- a/libmetricslogger/metrics_logger.cpp +++ b/libmetricslogger/metrics_logger.cpp @@ -62,6 +62,10 @@ ComplexEventLogger::ComplexEventLogger(int category) : logger(kSysuiMultiActionT logger << LOGBUILDER_CATEGORY << category; } +void ComplexEventLogger::SetPackageName(const std::string& package_name) { + logger << LOGBUILDER_PACKAGENAME << package_name; +} + void ComplexEventLogger::AddTaggedData(int tag, int32_t value) { logger << tag << value; } diff --git a/libnetutils/packet.c b/libnetutils/packet.c index e53a4c84f..9ecdd4f4e 100644 --- a/libnetutils/packet.c +++ b/libnetutils/packet.c @@ -218,6 +218,20 @@ int receive_packet(int s, struct dhcp_msg *msg) * to construct the pseudo header used in the checksum calculation. */ dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp); + /* + * check validity of dhcp_size. + * 1) cannot be negative or zero. + * 2) src buffer contains enough bytes to copy + * 3) cannot exceed destination buffer + */ + if ((dhcp_size <= 0) || + ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) || + ((int)sizeof(struct dhcp_msg) < dhcp_size)) { +#if VERBOSE + ALOGD("Malformed Packet"); +#endif + return -1; + } saddr = packet.ip.saddr; daddr = packet.ip.daddr; nread = ntohs(packet.ip.tot_len); diff --git a/libsystem/include/system/camera.h b/libsystem/include/system/camera.h index 5d0873ac4..7d796737c 100644 --- a/libsystem/include/system/camera.h +++ b/libsystem/include/system/camera.h @@ -203,6 +203,15 @@ enum { * (except disconnect and sending CAMERA_CMD_PING) after getting this. */ CAMERA_ERROR_RELEASED = 2, + + /** + * Camera was released because device policy change or the client application + * is going to background. The client should call Camera::disconnect + * immediately after getting this notification. Otherwise, the camera will be + * released by camera service in a short time. The client should not call any + * method (except disconnect and sending CAMERA_CMD_PING) after getting this. + */ + CAMERA_ERROR_DISABLED = 3, CAMERA_ERROR_SERVER_DIED = 100 }; diff --git a/libsystem/include/system/graphics-base-v1.0.h b/libsystem/include/system/graphics-base-v1.0.h new file mode 100644 index 000000000..44913cc61 --- /dev/null +++ b/libsystem/include/system/graphics-base-v1.0.h @@ -0,0 +1,140 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. +// Source: android.hardware.graphics.common@1.0 +// Location: hardware/interfaces/graphics/common/1.0/ + +#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ +#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, + HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, + HAL_PIXEL_FORMAT_YCBCR_422_I = 20, + HAL_PIXEL_FORMAT_RGBA_FP16 = 22, + HAL_PIXEL_FORMAT_RAW16 = 32, + HAL_PIXEL_FORMAT_BLOB = 33, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, + HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, + HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, + HAL_PIXEL_FORMAT_RAW10 = 37, + HAL_PIXEL_FORMAT_RAW12 = 38, + HAL_PIXEL_FORMAT_RGBA_1010102 = 43, + HAL_PIXEL_FORMAT_Y8 = 538982489, + HAL_PIXEL_FORMAT_Y16 = 540422489, + HAL_PIXEL_FORMAT_YV12 = 842094169, +} android_pixel_format_t; + +typedef enum { + HAL_TRANSFORM_FLIP_H = 1, // (1 << 0) + HAL_TRANSFORM_FLIP_V = 2, // (1 << 1) + HAL_TRANSFORM_ROT_90 = 4, // (1 << 2) + HAL_TRANSFORM_ROT_180 = 3, // (FLIP_H | FLIP_V) + HAL_TRANSFORM_ROT_270 = 7, // ((FLIP_H | FLIP_V) | ROT_90) +} android_transform_t; + +typedef enum { + HAL_DATASPACE_UNKNOWN = 0, + HAL_DATASPACE_ARBITRARY = 1, + HAL_DATASPACE_STANDARD_SHIFT = 16, + HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT) + HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT) + HAL_DATASPACE_TRANSFER_SHIFT = 22, + HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT) + HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT) + HAL_DATASPACE_RANGE_SHIFT = 27, + HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT) + HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT) + HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT) + HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT) + HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT) + HAL_DATASPACE_SRGB_LINEAR = 512, + HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL) + HAL_DATASPACE_V0_SCRGB_LINEAR = + 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED) + HAL_DATASPACE_SRGB = 513, + HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL) + HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED) + HAL_DATASPACE_JFIF = 257, + HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL) + HAL_DATASPACE_BT601_625 = 258, + HAL_DATASPACE_V0_BT601_625 = + 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) + HAL_DATASPACE_BT601_525 = 259, + HAL_DATASPACE_V0_BT601_525 = + 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) + HAL_DATASPACE_BT709 = 260, + HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) + HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL) + HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL) + HAL_DATASPACE_DISPLAY_P3_LINEAR = + 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL) + HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | RANGE_FULL) + HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL) + HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL) + HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL) + HAL_DATASPACE_BT2020_PQ = 163971072, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_FULL) + HAL_DATASPACE_DEPTH = 4096, + HAL_DATASPACE_SENSOR = 4097, +} android_dataspace_t; + +typedef enum { + HAL_COLOR_MODE_NATIVE = 0, + HAL_COLOR_MODE_STANDARD_BT601_625 = 1, + HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2, + HAL_COLOR_MODE_STANDARD_BT601_525 = 3, + HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4, + HAL_COLOR_MODE_STANDARD_BT709 = 5, + HAL_COLOR_MODE_DCI_P3 = 6, + HAL_COLOR_MODE_SRGB = 7, + HAL_COLOR_MODE_ADOBE_RGB = 8, + HAL_COLOR_MODE_DISPLAY_P3 = 9, +} android_color_mode_t; + +typedef enum { + HAL_COLOR_TRANSFORM_IDENTITY = 0, + HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1, + HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2, + HAL_COLOR_TRANSFORM_GRAYSCALE = 3, + HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4, + HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5, + HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6, +} android_color_transform_t; + +typedef enum { + HAL_HDR_DOLBY_VISION = 1, + HAL_HDR_HDR10 = 2, + HAL_HDR_HLG = 3, +} android_hdr_t; + +#ifdef __cplusplus +} +#endif + +#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ diff --git a/libsystem/include/system/graphics-base-v1.1.h b/libsystem/include/system/graphics-base-v1.1.h new file mode 100644 index 000000000..f95b9ba21 --- /dev/null +++ b/libsystem/include/system/graphics-base-v1.1.h @@ -0,0 +1,48 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. +// Source: android.hardware.graphics.common@1.1 +// Location: hardware/interfaces/graphics/common/1.1/ + +#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_ +#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + HAL_PIXEL_FORMAT_DEPTH_16 = 48, + HAL_PIXEL_FORMAT_DEPTH_24 = 49, + HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = 50, + HAL_PIXEL_FORMAT_DEPTH_32F = 51, + HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 = 52, + HAL_PIXEL_FORMAT_STENCIL_8 = 53, + HAL_PIXEL_FORMAT_YCBCR_P010 = 54, +} android_pixel_format_v1_1_t; + +typedef enum { + HAL_DATASPACE_BT2020_ITU = + 281411584, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) + HAL_DATASPACE_BT2020_ITU_PQ = + 298188800, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_LIMITED) + HAL_DATASPACE_BT2020_ITU_HLG = 302383104, // ((STANDARD_BT2020 | TRANSFER_HLG) | RANGE_LIMITED) + HAL_DATASPACE_BT2020_HLG = 168165376, // ((STANDARD_BT2020 | TRANSFER_HLG) | RANGE_FULL) +} android_dataspace_v1_1_t; + +typedef enum { + HAL_COLOR_MODE_BT2020 = 10, + HAL_COLOR_MODE_BT2100_PQ = 11, + HAL_COLOR_MODE_BT2100_HLG = 12, +} android_color_mode_v1_1_t; + +typedef enum { + HAL_RENDER_INTENT_COLORIMETRIC = 0, + HAL_RENDER_INTENT_ENHANCE = 1, + HAL_RENDER_INTENT_TONE_MAP_COLORIMETRIC = 2, + HAL_RENDER_INTENT_TONE_MAP_ENHANCE = 3, +} android_render_intent_v1_1_t; + +#ifdef __cplusplus +} +#endif + +#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_1_EXPORTED_CONSTANTS_H_ diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h index 2a44fafdf..ea920071c 100644 --- a/libsystem/include/system/graphics-base.h +++ b/libsystem/include/system/graphics-base.h @@ -1,141 +1,7 @@ -// This file is autogenerated by hidl-gen. Do not edit manually. -// Source: android.hardware.graphics.common@1.0 -// Root: android.hardware:hardware/interfaces +#ifndef SYSTEM_CORE_GRAPHICS_BASE_H_ +#define SYSTEM_CORE_GRAPHICS_BASE_H_ -#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ -#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ +#include "graphics-base-v1.0.h" +#include "graphics-base-v1.1.h" -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - HAL_PIXEL_FORMAT_RGBA_8888 = 1, - HAL_PIXEL_FORMAT_RGBX_8888 = 2, - HAL_PIXEL_FORMAT_RGB_888 = 3, - HAL_PIXEL_FORMAT_RGB_565 = 4, - HAL_PIXEL_FORMAT_BGRA_8888 = 5, - HAL_PIXEL_FORMAT_RGBA_1010102 = 43, // 0x2B - HAL_PIXEL_FORMAT_RGBA_FP16 = 22, // 0x16 - HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659 - HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859 - HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159 - HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20 - HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25 - HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26 - HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24 - HAL_PIXEL_FORMAT_BLOB = 33, // 0x21 - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22 - HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23 - HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27 - HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28 - HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29 - HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A - HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10 - HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11 - HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14 - HAL_PIXEL_FORMAT_JPEG = 256, // 0x100 -} android_pixel_format_t; - -typedef enum { - HAL_TRANSFORM_FLIP_H = 1, // 0x01 - HAL_TRANSFORM_FLIP_V = 2, // 0x02 - HAL_TRANSFORM_ROT_90 = 4, // 0x04 - HAL_TRANSFORM_ROT_180 = 3, // 0x03 - HAL_TRANSFORM_ROT_270 = 7, // 0x07 -} android_transform_t; - -typedef enum { - HAL_DATASPACE_UNKNOWN = 0, // 0x0 - HAL_DATASPACE_ARBITRARY = 1, // 0x1 - HAL_DATASPACE_STANDARD_SHIFT = 16, - HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT) - HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT) - HAL_DATASPACE_TRANSFER_SHIFT = 22, - HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT) - HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT) - HAL_DATASPACE_RANGE_SHIFT = 27, - HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT) - HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT) - HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT) - HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT) - HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT) - HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200 - HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL) - HAL_DATASPACE_V0_SCRGB_LINEAR = 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED) - HAL_DATASPACE_SRGB = 513, // 0x201 - HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL) - HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED) - HAL_DATASPACE_JFIF = 257, // 0x101 - HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL) - HAL_DATASPACE_BT601_625 = 258, // 0x102 - HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) - HAL_DATASPACE_BT601_525 = 259, // 0x103 - HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) - HAL_DATASPACE_BT709 = 260, // 0x104 - HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED) - HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL) - HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL) - HAL_DATASPACE_DISPLAY_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL) - HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | RANGE_FULL) - HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL) - HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL) - HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL) - HAL_DATASPACE_BT2020_PQ = 163971072, // ((STANDARD_BT2020 | TRANSFER_ST2084) | RANGE_FULL) - HAL_DATASPACE_DEPTH = 4096, // 0x1000 - HAL_DATASPACE_SENSOR = 4097, // 0x1001 -} android_dataspace_t; - -typedef enum { - HAL_COLOR_MODE_NATIVE = 0, - HAL_COLOR_MODE_STANDARD_BT601_625 = 1, - HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2, - HAL_COLOR_MODE_STANDARD_BT601_525 = 3, - HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4, - HAL_COLOR_MODE_STANDARD_BT709 = 5, - HAL_COLOR_MODE_DCI_P3 = 6, - HAL_COLOR_MODE_SRGB = 7, - HAL_COLOR_MODE_ADOBE_RGB = 8, - HAL_COLOR_MODE_DISPLAY_P3 = 9, -} android_color_mode_t; - -typedef enum { - HAL_COLOR_TRANSFORM_IDENTITY = 0, - HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1, - HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2, - HAL_COLOR_TRANSFORM_GRAYSCALE = 3, - HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4, - HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5, - HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6, -} android_color_transform_t; - -typedef enum { - HAL_HDR_DOLBY_VISION = 1, - HAL_HDR_HDR10 = 2, - HAL_HDR_HLG = 3, -} android_hdr_t; - -#ifdef __cplusplus -} -#endif - -#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_ +#endif // SYSTEM_CORE_GRAPHICS_BASE_H_ diff --git a/libsystem/include/system/graphics-sw.h b/libsystem/include/system/graphics-sw.h new file mode 100644 index 000000000..9e1a88e9e --- /dev/null +++ b/libsystem/include/system/graphics-sw.h @@ -0,0 +1,16 @@ +#ifndef SYSTEM_CORE_GRAPHICS_SW_H_ +#define SYSTEM_CORE_GRAPHICS_SW_H_ + +/* Software formats not in the HAL definitions. */ +typedef enum { + HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27 + HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28 + HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29 + HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A +} android_pixel_format_sw_t; + +/* for compatibility */ +#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888 +#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888 + +#endif // SYSTEM_CORE_GRAPHICS_SW_H_ diff --git a/libsystem/include/system/graphics.h b/libsystem/include/system/graphics.h index 1a9918797..1b6060a4e 100644 --- a/libsystem/include/system/graphics.h +++ b/libsystem/include/system/graphics.h @@ -25,6 +25,7 @@ * generated. */ #include "graphics-base.h" +#include "graphics-sw.h" #ifdef __cplusplus extern "C" { @@ -32,8 +33,6 @@ extern "C" { /* for compatibility */ #define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888 -#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888 -#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888 #define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP #define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP #define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I @@ -257,6 +256,11 @@ struct android_smpte2086_metadata { float minLuminance; }; +struct android_cta861_3_metadata { + float maxContentLightLevel; + float maxFrameAverageLightLevel; +}; + #ifdef __cplusplus } #endif diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h index 9758b1882..7e62542ce 100644 --- a/libusbhost/include/usbhost/usbhost.h +++ b/libusbhost/include/usbhost/usbhost.h @@ -137,6 +137,7 @@ uint16_t usb_device_get_vendor_id(struct usb_device *device); /* Returns the USB product ID from the device descriptor for the USB device */ uint16_t usb_device_get_product_id(struct usb_device *device); +/* Returns a pointer to device descriptor */ const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device); /* Returns a USB descriptor string for the given string ID. @@ -156,6 +157,12 @@ const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_ int usb_device_get_string_ucs2(struct usb_device* device, int id, int timeout, void** ucs2_out, size_t* response_size); +/* Returns the length in bytes read into the raw descriptors array */ +size_t usb_device_get_descriptors_length(const struct usb_device* device); + +/* Returns a pointer to the raw descriptors array */ +const unsigned char* usb_device_get_raw_descriptors(const struct usb_device* device); + /* Returns a USB descriptor string for the given string ID. * Used to implement usb_device_get_manufacturer_name, * usb_device_get_product_name and usb_device_get_serial. diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c index cb8d430db..415488fc0 100644 --- a/libusbhost/usbhost.c +++ b/libusbhost/usbhost.c @@ -76,9 +76,11 @@ struct usb_host_context { int wddbus; }; +#define MAX_DESCRIPTORS_LENGTH 4096 + struct usb_device { char dev_name[64]; - unsigned char desc[4096]; + unsigned char desc[MAX_DESCRIPTORS_LENGTH]; int desc_length; int fd; int writeable; @@ -387,6 +389,8 @@ struct usb_device *usb_device_new(const char *dev_name, int fd) return device; failed: + // TODO It would be more appropriate to have callers do this + // since this function doesn't "own" this file descriptor. close(fd); free(device); return NULL; @@ -455,11 +459,18 @@ uint16_t usb_device_get_product_id(struct usb_device *device) return __le16_to_cpu(desc->idProduct); } -const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device) -{ +const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device* device) { return (struct usb_device_descriptor*)device->desc; } +size_t usb_device_get_descriptors_length(const struct usb_device* device) { + return device->desc_length; +} + +const unsigned char* usb_device_get_raw_descriptors(const struct usb_device* device) { + return device->desc; +} + /* Returns a USB descriptor string for the given string ID. * Return value: < 0 on error. 0 on success. * The string is returned in ucs2_out in USB-native UCS-2 encoding. diff --git a/libutils/String16.cpp b/libutils/String16.cpp index f820b8b89..5c0b406ca 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -66,6 +66,23 @@ static char16_t* allocFromUTF8(const char* u8str, size_t u8len) return getEmptyString(); } +static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) { + if (u16len >= SIZE_MAX / sizeof(char16_t)) { + android_errorWriteLog(0x534e4554, "73826242"); + abort(); + } + + SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t)); + ALOG_ASSERT(buf, "Unable to allocate shared buffer"); + if (buf) { + char16_t* str = (char16_t*)buf->data(); + memcpy(str, u16str, u16len * sizeof(char16_t)); + str[u16len] = 0; + return str; + } + return getEmptyString(); +} + // --------------------------------------------------------------------------- String16::String16() @@ -98,35 +115,9 @@ String16::String16(const String16& o, size_t len, size_t begin) setTo(o, len, begin); } -String16::String16(const char16_t* o) -{ - size_t len = strlen16(o); - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - strcpy16(str, o); - mString = str; - return; - } +String16::String16(const char16_t* o) : mString(allocFromUTF16(o, strlen16(o))) {} - mString = getEmptyString(); -} - -String16::String16(const char16_t* o, size_t len) -{ - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - ALOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str, o, len*sizeof(char16_t)); - str[len] = 0; - mString = str; - return; - } - - mString = getEmptyString(); -} +String16::String16(const char16_t* o, size_t len) : mString(allocFromUTF16(o, len)) {} String16::String16(const String8& o) : mString(allocFromUTF8(o.string(), o.size())) @@ -188,6 +179,11 @@ status_t String16::setTo(const char16_t* other) status_t String16::setTo(const char16_t* other, size_t len) { + if (len >= SIZE_MAX / sizeof(char16_t)) { + android_errorWriteLog(0x534e4554, "73826242"); + abort(); + } + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) ->editResize((len+1)*sizeof(char16_t)); if (buf) { @@ -211,6 +207,11 @@ status_t String16::append(const String16& other) return NO_ERROR; } + if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) { + android_errorWriteLog(0x534e4554, "73826242"); + abort(); + } + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) ->editResize((myLen+otherLen+1)*sizeof(char16_t)); if (buf) { @@ -232,6 +233,11 @@ status_t String16::append(const char16_t* chrs, size_t otherLen) return NO_ERROR; } + if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) { + android_errorWriteLog(0x534e4554, "73826242"); + abort(); + } + SharedBuffer* buf = SharedBuffer::bufferFromData(mString) ->editResize((myLen+otherLen+1)*sizeof(char16_t)); if (buf) { diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc index 377479f1c..23dd5dc84 100644 --- a/libziparchive/zip_archive_test.cc +++ b/libziparchive/zip_archive_test.cc @@ -643,6 +643,55 @@ TEST(ziparchive, ErrorCodeString) { ASSERT_STREQ("I/O error", ErrorCodeString(kIoError)); } +// A zip file whose local file header at offset zero is corrupted. +// +// --------------- +// cat foo > a.txt +// zip a.zip a.txt +// cat a.zip | xxd -i +// +// Manual changes : +// [2] = 0xff // Corrupt the LFH signature of entry 0. +// [3] = 0xff // Corrupt the LFH signature of entry 0. +static const std::vector kZipFileWithBrokenLfhSignature{ + //[lfh-sig-----------], [lfh contents--------------------------------- + 0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, + //-------------------------------------------------------------------- + 0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, + //-------------------------------] [file-name-----------------], [--- + 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, + // entry-contents------------------------------------------------------ + 0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59, + //-------------------------------------------------------------------- + 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, + //-------------------------------------], [cd-record-sig-------], [--- + 0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e, + // cd-record----------------------------------------------------------- + 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8, + //-------------------------------------------------------------------- + 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, + //-------------------------------------------------------------------- + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, + //-] [lfh-file-header-off-], [file-name-----------------], [extra---- + 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, + //-------------------------------------------------------------------- + 0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01, + //-------------------------------------------------------], [eocd-sig- + 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b, + //-------], [--------------------------------------------------------- + 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00, + //-------------------------------------------] + 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00}; + +TEST(ziparchive, BrokenLfhSignature) { + TemporaryFile tmp_file; + ASSERT_NE(-1, tmp_file.fd); + ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0], + kZipFileWithBrokenLfhSignature.size())); + ZipArchiveHandle handle; + ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle)); +} + class VectorReader : public zip_archive::Reader { public: VectorReader(const std::vector& input) : Reader(), input_(input) {} diff --git a/lmkd/Android.bp b/lmkd/Android.bp index 9ac082f54..1369b8b40 100644 --- a/lmkd/Android.bp +++ b/lmkd/Android.bp @@ -6,9 +6,33 @@ cc_binary { "libcutils", "liblog", ], + static_libs: [ + "libstatslogc", + "libstatssocket", + ], local_include_dirs: ["include"], cflags: ["-Werror", "-DLMKD_TRACE_KILLS"], init_rc: ["lmkd.rc"], + product_variables: { + use_lmkd_stats_log: { + cflags: [ + "-DLMKD_LOG_STATS" + ], + }, + }, +} + +cc_library_static { + name: "libstatslogc", + srcs: ["statslog.c"], + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "liblog", + ], + static_libs: ["libstatssocket",], } cc_library_static { diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 1a14be3e1..8fda5636f 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -38,6 +38,10 @@ #include #include +#ifdef LMKD_LOG_STATS +#include "statslog.h" +#endif + /* * Define LMKD_TRACE_KILLS to record lmkd kills in kernel traces * to profile and correlate with OOM kills @@ -246,6 +250,11 @@ struct reread_data { int fd; }; +#ifdef LMKD_LOG_STATS +static bool enable_stats_log; +static android_log_context log_ctx; +#endif + #define PIDHASH_SZ 1024 static struct proc *pidhash[PIDHASH_SZ]; #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) @@ -719,6 +728,51 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused) { maxevents++; } +#ifdef LMKD_LOG_STATS +static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { + char key[LINE_MAX]; + int64_t value; + + sscanf(line,"%s %" SCNd64 "", key, &value); + + if (strcmp(key, "total_") < 0) { + return; + } + + if (!strcmp(key, "total_pgfault")) + mem_st->pgfault = value; + else if (!strcmp(key, "total_pgmajfault")) + mem_st->pgmajfault = value; + else if (!strcmp(key, "total_rss")) + mem_st->rss_in_bytes = value; + else if (!strcmp(key, "total_cache")) + mem_st->cache_in_bytes = value; + else if (!strcmp(key, "total_swap")) + mem_st->swap_in_bytes = value; +} + +static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { + FILE *fp; + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); + + fp = fopen(buf, "r"); + + if (fp == NULL) { + ALOGE("%s open failed: %s", buf, strerror(errno)); + return -1; + } + + while (fgets(buf, PAGE_SIZE, fp) != NULL ) { + memory_stat_parse_line(buf, mem_st); + } + fclose(fp); + + return 0; +} +#endif + /* /prop/zoneinfo parsing routines */ static int64_t zoneinfo_parse_protection(char *cp) { int64_t max = 0; @@ -944,6 +998,11 @@ static int kill_one_process(struct proc* procp, int min_score_adj, int tasksize; int r; +#ifdef LMKD_LOG_STATS + struct memory_stat mem_st = {}; + int memory_stat_parse_result = -1; +#endif + taskname = proc_get_name(pid); if (!taskname) { pid_remove(pid); @@ -956,6 +1015,12 @@ static int kill_one_process(struct proc* procp, int min_score_adj, return -1; } +#ifdef LMKD_LOG_STATS + if (enable_stats_log) { + memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid); + } +#endif + TRACE_KILL_START(pid); /* CAP_KILL required */ @@ -972,6 +1037,15 @@ static int kill_one_process(struct proc* procp, int min_score_adj, if (r) { ALOGE("kill(%d): errno=%d", pid, errno); return -1; + } else { +#ifdef LMKD_LOG_STATS + if (memory_stat_parse_result == 0) { + stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, + procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, + mem_st.cache_in_bytes, mem_st.swap_in_bytes); + } +#endif + return tasksize; } return tasksize; @@ -988,6 +1062,10 @@ static int find_and_kill_processes(enum vmpressure_level level, int killed_size; int pages_freed = 0; +#ifdef LMKD_LOG_STATS + bool lmk_state_change_start = false; +#endif + for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) { struct proc *procp; @@ -1000,14 +1078,35 @@ static int find_and_kill_processes(enum vmpressure_level level, killed_size = kill_one_process(procp, min_score_adj, level); if (killed_size >= 0) { +#ifdef LMKD_LOG_STATS + if (enable_stats_log && !lmk_state_change_start) { + lmk_state_change_start = true; + stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED, + LMK_STATE_CHANGE_START); + } +#endif + pages_freed += killed_size; if (pages_freed >= pages_to_free) { + +#ifdef LMKD_LOG_STATS + if (enable_stats_log && lmk_state_change_start) { + stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED, + LMK_STATE_CHANGE_STOP); + } +#endif return pages_freed; } } } } +#ifdef LMKD_LOG_STATS + if (enable_stats_log && lmk_state_change_start) { + stats_write_lmk_state_changed(log_ctx, LMK_STATE_CHANGED, LMK_STATE_CHANGE_STOP); + } +#endif + return pages_freed; } @@ -1122,10 +1221,8 @@ static void mp_event_common(int data, uint32_t events __unused) { } if (skip_count > 0) { - if (debug_process_killing) { - ALOGI("%lu memory pressure events were skipped after a kill!", - skip_count); - } + ALOGI("%lu memory pressure events were skipped after a kill!", + skip_count); skip_count = 0; } @@ -1250,25 +1347,24 @@ do_kill: return; } min_score_adj = level_oomadj[level]; - } else { - if (debug_process_killing) { - ALOGI("Killing because cache %ldkB is below " - "limit %ldkB for oom_adj %d\n" - " Free memory is %ldkB %s reserved", - other_file * page_k, minfree * page_k, min_score_adj, - other_free * page_k, other_free >= 0 ? "above" : "below"); - } } - if (debug_process_killing) { - ALOGI("Trying to free %d pages", pages_to_free); - } pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free); + + if (use_minfree_levels) { + ALOGI("Killing because cache %ldkB is below " + "limit %ldkB for oom_adj %d\n" + " Free memory is %ldkB %s reserved", + other_file * page_k, minfree * page_k, min_score_adj, + other_free * page_k, other_free >= 0 ? "above" : "below"); + } + if (pages_freed < pages_to_free) { - if (debug_process_killing) { - ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed); - } + ALOGI("Unable to free enough memory (pages to free=%d, pages freed=%d)", + pages_to_free, pages_freed); } else { + ALOGI("Reclaimed enough memory (pages to free=%d, pages freed=%d)", + pages_to_free, pages_freed); gettimeofday(&last_report_tm, NULL); } } @@ -1485,6 +1581,10 @@ int main(int argc __unused, char **argv __unused) { per_app_memcg = property_get_bool("ro.config.per_app_memcg", low_ram_device); +#ifdef LMKD_LOG_STATS + statslog_init(&log_ctx, &enable_stats_log); +#endif + if (!init()) { if (!use_inkernel_interface) { /* @@ -1512,6 +1612,10 @@ int main(int argc __unused, char **argv __unused) { mainloop(); } +#ifdef LMKD_LOG_STATS + statslog_destroy(&log_ctx); +#endif + ALOGI("exiting"); return 0; } diff --git a/lmkd/statslog.c b/lmkd/statslog.c new file mode 100644 index 000000000..66d11647b --- /dev/null +++ b/lmkd/statslog.c @@ -0,0 +1,117 @@ +/* + * Copyright 2018 Google, Inc + * + * 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 +#include +#include +#include +#include + +static int64_t getElapsedRealTimeNs() { + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_BOOTTIME, &t); + return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec; +} + +/** + * Logs the change in LMKD state which is used as start/stop boundaries for logging + * LMK_KILL_OCCURRED event. + * Code: LMK_STATE_CHANGED = 54 + */ +int +stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state) { + assert(ctx != NULL); + int ret = -EINVAL; + if (!ctx) { + return ret; + } + + reset_log_context(ctx); + + if ((ret = android_log_write_int64(ctx, getElapsedRealTimeNs())) < 0) { + return ret; + } + + if ((ret = android_log_write_int32(ctx, code)) < 0) { + return ret; + } + + if ((ret = android_log_write_int32(ctx, state)) < 0) { + return ret; + } + + return write_to_logger(ctx, LOG_ID_STATS); +} + +/** + * Logs the event when LMKD kills a process to reduce memory pressure. + * Code: LMK_KILL_OCCURRED = 51 + */ +int +stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, + char const* process_name, int32_t oom_score, int64_t pgfault, + int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, + int64_t swap_in_bytes) { + assert(ctx != NULL); + int ret = -EINVAL; + if (!ctx) { + return ret; + } + reset_log_context(ctx); + + if ((ret = android_log_write_int64(ctx, getElapsedRealTimeNs())) < 0) { + return ret; + } + + if ((ret = android_log_write_int32(ctx, code)) < 0) { + return ret; + } + + if ((ret = android_log_write_int32(ctx, uid)) < 0) { + return ret; + } + + if ((ret = android_log_write_string8(ctx, (process_name == NULL) ? "" : process_name)) < 0) { + return ret; + } + + if ((ret = android_log_write_int32(ctx, oom_score)) < 0) { + return ret; + } + + if ((ret = android_log_write_int64(ctx, pgfault)) < 0) { + return ret; + } + + if ((ret = android_log_write_int64(ctx, pgmajfault)) < 0) { + return ret; + } + + if ((ret = android_log_write_int64(ctx, rss_in_bytes)) < 0) { + return ret; + } + + if ((ret = android_log_write_int64(ctx, cache_in_bytes)) < 0) { + return ret; + } + + if ((ret = android_log_write_int64(ctx, swap_in_bytes)) < 0) { + return ret; + } + + return write_to_logger(ctx, LOG_ID_STATS); +} diff --git a/lmkd/statslog.h b/lmkd/statslog.h new file mode 100644 index 000000000..edebb195b --- /dev/null +++ b/lmkd/statslog.h @@ -0,0 +1,91 @@ +/* + * Copyright 2018 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _STATSLOG_H_ +#define _STATSLOG_H_ + +#include +#include +#include +#include + +#include + +__BEGIN_DECLS + +/* + * These are defined in + * http://cs/android/frameworks/base/cmds/statsd/src/atoms.proto + */ +#define LMK_KILL_OCCURRED 51 +#define LMK_STATE_CHANGED 54 +#define LMK_STATE_CHANGE_START 1 +#define LMK_STATE_CHANGE_STOP 2 + +/* + * The single event tag id for all stats logs. + * Keep this in sync with system/core/logcat/event.logtags + */ +const static int kStatsEventTag = 1937006964; + +static inline void statslog_init(android_log_context* log_ctx, bool* enable_stats_log) { + assert(log_ctx != NULL); + assert(enable_stats_log != NULL); + *enable_stats_log = property_get_bool("ro.lmk.log_stats", false); + + if (*enable_stats_log) { + *log_ctx = create_android_logger(kStatsEventTag); + } +} + +static inline void statslog_destroy(android_log_context* log_ctx) { + assert(log_ctx != NULL); + if (*log_ctx) { + android_log_destroy(log_ctx); + } +} + +struct memory_stat { + int64_t pgfault; + int64_t pgmajfault; + int64_t rss_in_bytes; + int64_t cache_in_bytes; + int64_t swap_in_bytes; +}; + +#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" + +/** + * Logs the change in LMKD state which is used as start/stop boundaries for logging + * LMK_KILL_OCCURRED event. + * Code: LMK_STATE_CHANGED = 54 + */ +int +stats_write_lmk_state_changed(android_log_context ctx, int32_t code, int32_t state); + +/** + * Logs the event when LMKD kills a process to reduce memory pressure. + * Code: LMK_KILL_OCCURRED = 51 + */ +int +stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, + char const* process_name, int32_t oom_score, int64_t pgfault, + int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, + int64_t swap_in_bytes); + +__END_DECLS + +#endif /* _STATSLOG_H_ */ diff --git a/lmkd/tests/lmkd_test.cpp b/lmkd/tests/lmkd_test.cpp index 8c7a75fa1..1996bae29 100644 --- a/lmkd/tests/lmkd_test.cpp +++ b/lmkd/tests/lmkd_test.cpp @@ -110,9 +110,14 @@ std::string getTextAround(const std::string& text, size_t pos, } bool getExecPath(std::string &path) { - // exec path as utf8z c_str(). - // std::string contains _all_ nul terminated argv[] strings. - return android::base::ReadFileToString("/proc/self/cmdline", &path); + char buf[PATH_MAX + 1]; + int ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (ret < 0) { + return false; + } + buf[ret] = '\0'; + path = buf; + return true; } /* Child synchronization primitives */ @@ -310,8 +315,8 @@ TEST(lmkd, check_for_oom) { if (getuid() != static_cast(AID_ROOT)) { // if not root respawn itself as root and capture output std::string command = StringPrintf( - "%s=true su root %s --gtest_filter=lmkd.check_for_oom 2>&1", - LMKDTEST_RESPAWN_FLAG, test_path.c_str()); + "%s=true su root %s 2>&1", LMKDTEST_RESPAWN_FLAG, + test_path.c_str()); std::string test_output = readCommand(command); GTEST_LOG_(INFO) << test_output; } else { diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index a78319ff4..9b0436367 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -1115,9 +1115,6 @@ log_time LogBuffer::flushTo(SocketClient* reader, const log_time& start, // client wants to start from the beginning it = mLogElements.begin(); } else { - // 3 second limit to continue search for out-of-order entries. - log_time min = start - pruneMargin; - // Cap to 300 iterations we look back for out-of-order entries. size_t count = 300; @@ -1133,7 +1130,7 @@ log_time LogBuffer::flushTo(SocketClient* reader, const log_time& start, } else if (element->getRealTime() == start) { last = ++it; break; - } else if (!--count || (element->getRealTime() < min)) { + } else if (!--count) { break; } } diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 763dc790f..3a6a5e8af 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -98,6 +98,9 @@ ifdef BOARD_USES_PRODUCT_SERVICESIMAGE else LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product-services $(TARGET_ROOT_OUT)/product-services endif +ifdef BOARD_USES_METADATA_PARTITION + LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata +endif # For /odm partition. LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm diff --git a/rootdir/init.rc b/rootdir/init.rc index 486d096ab..bc4a309cc 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -84,7 +84,7 @@ on init restorecon_recursive /mnt mount configfs none /config nodev noexec nosuid - chmod 0775 /config/sdcardfs + chmod 0770 /config/sdcardfs chown system package_info /config/sdcardfs mkdir /mnt/secure 0700 root root @@ -180,6 +180,12 @@ on init copy /dev/cpuset/cpus /dev/cpuset/system-background/cpus copy /dev/cpuset/mems /dev/cpuset/system-background/mems + # restricted is for system tasks that are being throttled + # due to screen off. + mkdir /dev/cpuset/restricted + copy /dev/cpuset/cpus /dev/cpuset/restricted/cpus + copy /dev/cpuset/mems /dev/cpuset/restricted/mems + mkdir /dev/cpuset/top-app copy /dev/cpuset/cpus /dev/cpuset/top-app/cpus copy /dev/cpuset/mems /dev/cpuset/top-app/mems @@ -190,11 +196,13 @@ on init chown system system /dev/cpuset/background chown system system /dev/cpuset/system-background chown system system /dev/cpuset/top-app + chown system system /dev/cpuset/restricted chown system system /dev/cpuset/tasks chown system system /dev/cpuset/foreground/tasks chown system system /dev/cpuset/background/tasks chown system system /dev/cpuset/system-background/tasks chown system system /dev/cpuset/top-app/tasks + chown system system /dev/cpuset/restricted/tasks # set system-background to 0775 so SurfaceFlinger can touch it chmod 0775 /dev/cpuset/system-background @@ -203,6 +211,7 @@ on init chmod 0664 /dev/cpuset/background/tasks chmod 0664 /dev/cpuset/system-background/tasks chmod 0664 /dev/cpuset/top-app/tasks + chmod 0664 /dev/cpuset/restricted/tasks chmod 0664 /dev/cpuset/tasks @@ -366,6 +375,10 @@ on post-fs # create the lost+found directories, so as to enforce our permissions mkdir /cache/lost+found 0770 root root + restorecon_recursive /metadata + mkdir /metadata/vold + chmod 0700 /metadata/vold + on late-fs # Ensure that tracefs has the correct permissions. # This does not work correctly if it is called in post-fs. @@ -424,6 +437,7 @@ on post-fs-data mkdir /data/misc/carrierid 0770 system radio mkdir /data/misc/apns 0770 system radio mkdir /data/misc/zoneinfo 0775 system system + mkdir /data/misc/network_watchlist 0774 system system mkdir /data/misc/textclassifier 0771 system system mkdir /data/misc/vpn 0770 system vpn mkdir /data/misc/shared_relro 0771 shared_relro shared_relro @@ -456,6 +470,8 @@ on post-fs-data mkdir /data/misc/gcov 0770 root root mkdir /data/vendor 0771 root root + mkdir /data/vendor_ce 0771 root root + mkdir /data/vendor_de 0771 root root mkdir /data/vendor/hardware 0771 root root # For security reasons, /data/local/tmp should always be empty. @@ -688,6 +704,7 @@ on property:vold.decrypt=trigger_load_persist_props on property:vold.decrypt=trigger_post_fs_data trigger post-fs-data + trigger zygote-start on property:vold.decrypt=trigger_restart_min_framework # A/B update verifier that marks a successful boot. @@ -695,6 +712,8 @@ on property:vold.decrypt=trigger_restart_min_framework class_start main on property:vold.decrypt=trigger_restart_framework + stop surfaceflinger + start surfaceflinger # A/B update verifier that marks a successful boot. exec_start update_verifier class_start main @@ -738,11 +757,6 @@ service ueventd /sbin/ueventd seclabel u:r:ueventd:s0 shutdown critical -service healthd /system/bin/healthd - class core - critical - group root system wakelock - service console /system/bin/sh class core console diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc index de1aab328..3a33c94d3 100644 --- a/rootdir/init.usb.configfs.rc +++ b/rootdir/init.usb.configfs.rc @@ -2,7 +2,6 @@ on property:sys.usb.config=none && property:sys.usb.configfs=1 write /config/usb_gadget/g1/UDC "none" stop adbd setprop sys.usb.ffs.ready 0 - setprop sys.usb.ffs.mtp.ready 0 write /config/usb_gadget/g1/bDeviceClass 0 write /config/usb_gadget/g1/bDeviceSubClass 0 write /config/usb_gadget/g1/bDeviceProtocol 0 @@ -24,7 +23,7 @@ on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.u write /config/usb_gadget/g1/UDC ${sys.usb.controller} setprop sys.usb.state ${sys.usb.config} -on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=mtp && property:sys.usb.configfs=1 +on property:sys.usb.config=mtp && property:sys.usb.configfs=1 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp" symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1 write /config/usb_gadget/g1/UDC ${sys.usb.controller} @@ -33,15 +32,14 @@ on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=mtp && property:s on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1 start adbd -on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \ -property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1 +on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb" symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1 symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2 write /config/usb_gadget/g1/UDC ${sys.usb.controller} setprop sys.usb.state ${sys.usb.config} -on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=ptp && property:sys.usb.configfs=1 +on property:sys.usb.config=ptp && property:sys.usb.configfs=1 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp" symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1 write /config/usb_gadget/g1/UDC ${sys.usb.controller} @@ -50,8 +48,7 @@ on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=ptp && property:s on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1 start adbd -on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \ -property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1 +on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb" symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1 symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2 diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp index 574bbfee9..dc36596b1 100644 --- a/sdcard/sdcard.cpp +++ b/sdcard/sdcard.cpp @@ -43,6 +43,44 @@ #include +#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs" +#define PROP_SDCARDFS_USER "persist.sys.sdcardfs" + +static bool supports_esdfs(void) { + std::string filesystems; + if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) { + PLOG(ERROR) << "Could not read /proc/filesystems"; + return false; + } + for (const auto& fs : android::base::Split(filesystems, "\n")) { + if (fs.find("esdfs") != std::string::npos) return true; + } + return false; +} + +static bool should_use_sdcardfs(void) { + char property[PROPERTY_VALUE_MAX]; + + // Allow user to have a strong opinion about state + property_get(PROP_SDCARDFS_USER, property, ""); + if (!strcmp(property, "force_on")) { + LOG(WARNING) << "User explicitly enabled sdcardfs"; + return true; + } else if (!strcmp(property, "force_off")) { + LOG(WARNING) << "User explicitly disabled sdcardfs"; + return !supports_esdfs(); + } + + // Fall back to device opinion about state + if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) { + LOG(WARNING) << "Device explicitly enabled sdcardfs"; + return true; + } else { + LOG(WARNING) << "Device explicitly disabled sdcardfs"; + return !supports_esdfs(); + } +} + // NOTE: This is a vestigial program that simply exists to mount the in-kernel // sdcardfs filesystem. The older FUSE-based design that used to live here has // been completely removed to avoid confusion. @@ -61,7 +99,7 @@ static void drop_privs(uid_t uid, gid_t gid) { static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, - mode_t mask, bool derive_gid, bool default_normal) { + mode_t mask, bool derive_gid, bool default_normal, bool use_esdfs) { // Try several attempts, each time with one less option, to gracefully // handle older kernels that aren't updated yet. for (int i = 0; i < 4; i++) { @@ -72,7 +110,7 @@ static bool sdcardfs_setup(const std::string& source_path, const std::string& de auto opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d", fsuid, fsgid, new_opts.c_str(), mask, userid, gid); - if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs", + if (mount(source_path.c_str(), dest_path.c_str(), use_esdfs ? "esdfs" : "sdcardfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) { PLOG(WARNING) << "Failed to mount sdcardfs with options " << opts; } else { @@ -104,9 +142,21 @@ static bool sdcardfs_setup_bind_remount(const std::string& source_path, const st return true; } +static bool sdcardfs_setup_secondary(const std::string& default_path, const std::string& source_path, + const std::string& dest_path, uid_t fsuid, gid_t fsgid, + bool multi_user, userid_t userid, gid_t gid, mode_t mask, + bool derive_gid, bool default_normal, bool use_esdfs) { + if (use_esdfs) { + return sdcardfs_setup(source_path, dest_path, fsuid, fsgid, multi_user, userid, gid, mask, + derive_gid, default_normal, use_esdfs); + } else { + return sdcardfs_setup_bind_remount(default_path, dest_path, gid, mask); + } +} + static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid, gid_t gid, userid_t userid, bool multi_user, bool full_write, - bool derive_gid, bool default_normal) { + bool derive_gid, bool default_normal, bool use_esdfs) { std::string dest_path_default = "/mnt/runtime/default/" + label; std::string dest_path_read = "/mnt/runtime/read/" + label; std::string dest_path_write = "/mnt/runtime/write/" + label; @@ -116,10 +166,13 @@ static void run_sdcardfs(const std::string& source_path, const std::string& labe // Multi-user storage is fully isolated per user, so "other" // permissions are completely masked off. if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, - AID_SDCARD_RW, 0006, derive_gid, default_normal) || - !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) || - !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY, - full_write ? 0007 : 0027)) { + AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) || + !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid, + multi_user, userid, AID_EVERYBODY, 0027, derive_gid, + default_normal, use_esdfs) || + !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid, + multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0027, + derive_gid, default_normal, use_esdfs)) { LOG(FATAL) << "failed to sdcardfs_setup"; } } else { @@ -127,11 +180,13 @@ static void run_sdcardfs(const std::string& source_path, const std::string& labe // the Android directories are masked off to a single user // deep inside attr_from_stat(). if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, - AID_SDCARD_RW, 0006, derive_gid, default_normal) || - !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, - full_write ? 0027 : 0022) || - !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY, - full_write ? 0007 : 0022)) { + AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) || + !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid, + multi_user, userid, AID_EVERYBODY, full_write ? 0027 : 0022, + derive_gid, default_normal, use_esdfs) || + !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid, + multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0022, + derive_gid, default_normal, use_esdfs)) { LOG(FATAL) << "failed to sdcardfs_setup"; } } @@ -242,6 +297,6 @@ int main(int argc, char **argv) { } run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid, - default_normal); + default_normal, !should_use_sdcardfs()); return 1; } diff --git a/storaged/Android.bp b/storaged/Android.bp new file mode 100644 index 000000000..7466728d9 --- /dev/null +++ b/storaged/Android.bp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +cc_defaults { + name: "storaged_defaults", + + shared_libs: [ + "android.hardware.health@1.0", + "android.hardware.health@2.0", + "libbase", + "libbinder", + "libcutils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libprotobuf-cpp-lite", + "libsysutils", + "libutils", + "libz", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + "-Wno-unused-parameter" + ], +} + +cc_library_static { + name: "libstoraged", + + defaults: ["storaged_defaults"], + + aidl: { + export_aidl_headers: true, + local_include_dirs: ["binder"], + include_dirs: ["frameworks/native/aidl/binder"], + }, + + srcs: [ + "storaged.cpp", + "storaged_diskstats.cpp", + "storaged_info.cpp", + "storaged_service.cpp", + "storaged_utils.cpp", + "storaged_uid_monitor.cpp", + "uid_info.cpp", + "storaged.proto", + ":storaged_aidl", + "binder/android/os/storaged/IStoragedPrivate.aidl", + ], + + static_libs: ["libhealthhalutils"], + header_libs: ["libbatteryservice_headers"], + + logtags: ["EventLogTags.logtags"], + + proto: { + type: "lite", + export_proto_headers: true, + }, + + export_include_dirs: ["include"], +} + +cc_binary { + name: "storaged", + + defaults: ["storaged_defaults"], + + init_rc: ["storaged.rc"], + + srcs: ["main.cpp"], + + static_libs: [ + "libhealthhalutils", + "libstoraged", + ], +} + +/* + * Run with: + * adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests + */ +cc_test { + name: "storaged-unit-tests", + + defaults: ["storaged_defaults"], + + srcs: ["tests/storaged_test.cpp"], + + static_libs: [ + "libhealthhalutils", + "libstoraged", + ], +} + +// AIDL interface between storaged and framework.jar +filegroup { + name: "storaged_aidl", + srcs: [ + "binder/android/os/IStoraged.aidl", + ], +} diff --git a/storaged/Android.mk b/storaged/Android.mk deleted file mode 100644 index a1abe0fd1..000000000 --- a/storaged/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2016 The Android Open Source Project - -LOCAL_PATH := $(call my-dir) - -LIBSTORAGED_SHARED_LIBRARIES := \ - libbinder \ - libbase \ - libutils \ - libcutils \ - liblog \ - libsysutils \ - libbatteryservice \ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - storaged.cpp \ - storaged_info.cpp \ - storaged_service.cpp \ - storaged_utils.cpp \ - storaged_uid_monitor.cpp \ - EventLogTags.logtags - -LOCAL_MODULE := libstoraged -LOCAL_CFLAGS := -Werror -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES) -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_MODULE := storaged -LOCAL_INIT_RC := storaged.rc -LOCAL_SRC_FILES := main.cpp -# libstoraged is an internal static library, only main.cpp and storaged_test.cpp should be using it -LOCAL_STATIC_LIBRARIES := libstoraged -LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES) -LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -LOCAL_C_INCLUDES := external/googletest/googletest/include - -include $(BUILD_EXECUTABLE) - -include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/storaged/binder/android/os/IStoraged.aidl b/storaged/binder/android/os/IStoraged.aidl new file mode 100644 index 000000000..0bcc70c36 --- /dev/null +++ b/storaged/binder/android/os/IStoraged.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** {@hide} */ +interface IStoraged { + void onUserStarted(int userId); + void onUserStopped(int userId); + int getRecentPerf(); +} \ No newline at end of file diff --git a/storaged/binder/android/os/storaged/IStoragedPrivate.aidl b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl new file mode 100644 index 000000000..9c888e32f --- /dev/null +++ b/storaged/binder/android/os/storaged/IStoragedPrivate.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storaged; + +import android.os.storaged.UidInfo; + +/** {@hide} */ +interface IStoragedPrivate { + UidInfo[] dumpUids(); + int[] dumpPerfHistory(); +} \ No newline at end of file diff --git a/storaged/binder/android/os/storaged/UidInfo.aidl b/storaged/binder/android/os/storaged/UidInfo.aidl new file mode 100644 index 000000000..440f38697 --- /dev/null +++ b/storaged/binder/android/os/storaged/UidInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storaged; + +parcelable UidInfo cpp_header "include/uid_info.h"; diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index fa6840638..6f9204879 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -26,28 +26,18 @@ #include #include -#include -#include +#include -#include "storaged_info.h" -#include "storaged_uid_monitor.h" - -using namespace android; +#include #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test -/* For debug */ -#ifdef DEBUG -#define debuginfo(fmt, ...) \ - do {printf("%s():\t" fmt "\t[%s:%d]\n", __FUNCTION__, ##__VA_ARGS__, __FILE__, __LINE__);} \ - while(0) -#else -#define debuginfo(...) -#endif - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define IS_ALIGNED(x, align) (!((x) & ((align) - 1))) +#define ROUND_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + #define SECTOR_SIZE ( 512 ) #define SEC_TO_MSEC ( 1000 ) #define MSEC_TO_USEC ( 1000 ) @@ -55,184 +45,24 @@ friend class test_case_name##_##test_name##_Test #define SEC_TO_USEC ( 1000000 ) #define HOUR_TO_SEC ( 3600 ) #define DAY_TO_SEC ( 3600 * 24 ) +#define WEEK_TO_DAYS ( 7 ) +#define YEAR_TO_WEEKS ( 52 ) -// number of attributes diskstats has -#define DISK_STATS_SIZE ( 11 ) -// maximum size limit of a stats file -#define DISK_STATS_FILE_MAX_SIZE ( 256 ) -#define DISK_STATS_IO_IN_FLIGHT_IDX ( 8 ) -struct disk_stats { - /* It will be extremely unlikely for any of the following entries to overflow. - * For read_bytes(which will be greater than any of the following entries), it - * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which - * is the peak memory transfer rate for current memory. - * The diskstats entries (first 11) need to be at top in this structure _after_ - * compiler's optimization. - */ - uint64_t read_ios; // number of read I/Os processed - uint64_t read_merges; // number of read I/Os merged with in-queue I/Os - uint64_t read_sectors; // number of sectors read - uint64_t read_ticks; // total wait time for read requests - uint64_t write_ios; // number of write I/Os processed - uint64_t write_merges; // number of write I/Os merged with in-queue I/Os - uint64_t write_sectors; // number of sectors written - uint64_t write_ticks; // total wait time for write requests - uint64_t io_in_flight; // number of I/Os currently in flight - uint64_t io_ticks; // total time this block device has been active - uint64_t io_in_queue; // total wait time for all requests +#include "storaged_diskstats.h" +#include "storaged_info.h" +#include "storaged_uid_monitor.h" +#include "storaged.pb.h" +#include "uid_info.h" - uint64_t start_time; // monotonic time accounting starts - uint64_t end_time; // monotonic time accounting ends - uint32_t counter; // private counter for accumulate calculations - double io_avg; // average io_in_flight for accumulate calculations -}; - - - -struct disk_perf { - uint32_t read_perf; // read speed (kbytes/s) - uint32_t read_ios; // read I/Os per second - uint32_t write_perf; // write speed (kbytes/s) - uint32_t write_ios; // write I/Os per second - uint32_t queue; // I/Os in queue -}; - -#define CMD_MAX_LEN ( 64 ) -struct task_info { - uint32_t pid; // task id - uint64_t rchar; // characters read - uint64_t wchar; // characters written - uint64_t syscr; // read syscalls - uint64_t syscw; // write syscalls - uint64_t read_bytes; // bytes read (from storage layer) - uint64_t write_bytes; // bytes written (to storage layer) - uint64_t cancelled_write_bytes; // cancelled write byte by truncate - - uint64_t starttime; // start time of task - - char cmd[CMD_MAX_LEN]; // filename of the executable -}; - -class lock_t { - sem_t* mSem; -public: - lock_t(sem_t* sem) { - mSem = sem; - sem_wait(mSem); - } - ~lock_t() { - sem_post(mSem); - } -}; - -class stream_stats { -private: - double mSum; - double mSquareSum; - uint32_t mCnt; -public: - stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {}; - ~stream_stats() {}; - double get_mean() { - return mSum / mCnt; - } - double get_std() { - return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt)); - } - void add(uint32_t num) { - mSum += (double)num; - mSquareSum += (double)num * (double)num; - mCnt++; - } - void evict(uint32_t num) { - if (mSum < num || mSquareSum < (double)num * (double)num) return; - mSum -= (double)num; - mSquareSum -= (double)num * (double)num; - mCnt--; - } -}; - -#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" -#define SDA_DISK_STATS_PATH "/sys/block/sda/stat" -#define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd" -#define UID_IO_STATS_PATH "/proc/uid_io/stats" - -class disk_stats_monitor { -private: - FRIEND_TEST(storaged_test, disk_stats_monitor); - const char* DISK_STATS_PATH; - struct disk_stats mPrevious; - struct disk_stats mAccumulate; - bool mStall; - std::queue mBuffer; - struct { - stream_stats read_perf; // read speed (bytes/s) - stream_stats read_ios; // read I/Os per second - stream_stats write_perf; // write speed (bytes/s) - stream_stats write_ios; // write I/O per second - stream_stats queue; // I/Os in queue - } mStats; - bool mValid; - const uint32_t mWindow; - const double mSigma; - struct disk_perf mMean; - struct disk_perf mStd; - - void update_mean(); - void update_std(); - void add(struct disk_perf* perf); - void evict(struct disk_perf* perf); - bool detect(struct disk_perf* perf); - - void update(struct disk_stats* stats); - -public: - disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) : - mStall(false), - mValid(false), - mWindow(window_size), - mSigma(sigma) { - memset(&mPrevious, 0, sizeof(mPrevious)); - memset(&mMean, 0, sizeof(mMean)); - memset(&mStd, 0, sizeof(mStd)); - - if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) { - DISK_STATS_PATH = MMC_DISK_STATS_PATH; - } else { - DISK_STATS_PATH = SDA_DISK_STATS_PATH; - } - } - void update(void); -}; - -class disk_stats_publisher { -private: - FRIEND_TEST(storaged_test, disk_stats_publisher); - const char* DISK_STATS_PATH; - struct disk_stats mAccumulate; - struct disk_stats mPrevious; -public: - disk_stats_publisher(void) { - memset(&mAccumulate, 0, sizeof(struct disk_stats)); - memset(&mPrevious, 0, sizeof(struct disk_stats)); - - if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) { - DISK_STATS_PATH = MMC_DISK_STATS_PATH; - } else { - DISK_STATS_PATH = SDA_DISK_STATS_PATH; - } - } - - ~disk_stats_publisher(void) {} - void publish(void); - void update(void); -}; +using namespace std; +using namespace android; // Periodic chores intervals in seconds #define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 ) -#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT ( 300 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO ( 3600 ) // UID IO threshold in bytes #define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL ) @@ -241,25 +71,35 @@ struct storaged_config { int periodic_chores_interval_unit; int periodic_chores_interval_disk_stats_publish; int periodic_chores_interval_uid_io; - bool proc_uid_io_available; // whether uid_io is accessible - bool diskstats_available; // whether diskstats is accessible + int periodic_chores_interval_flush_proto; int event_time_check_usec; // check how much cputime spent in event loop }; -class storaged_t : public BnBatteryPropertiesListener, - public IBinder::DeathRecipient { -private: +class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback, + public android::hardware::hidl_death_recipient { + private: time_t mTimer; storaged_config mConfig; - disk_stats_publisher mDiskStats; - disk_stats_monitor mDsm; + unique_ptr mDsm; uid_monitor mUidm; time_t mStarttime; - sp battery_properties; - std::unique_ptr storage_info; -public: + sp health; + unique_ptr storage_info; + static const uint32_t current_version; + unordered_map proto_loaded; + void load_proto(userid_t user_id); + char* prepare_proto(userid_t user_id, StoragedProto* proto); + void flush_proto(userid_t user_id, StoragedProto* proto); + void flush_proto_data(userid_t user_id, const char* data, ssize_t size); + string proto_path(userid_t user_id) { + return string("/data/misc_ce/") + to_string(user_id) + + "/storaged/storaged.proto"; + } + void init_health_service(); + + public: storaged_t(void); - ~storaged_t() {} + void init(void); void event(void); void event_checked(void); void pause(void) { @@ -270,24 +110,37 @@ public: return mStarttime; } - std::unordered_map get_uids(void) { + unordered_map get_uids(void) { return mUidm.get_uid_io_stats(); } - std::map get_uid_records( + + vector get_perf_history(void) { + return storage_info->get_perf_history(); + } + + uint32_t get_recent_perf(void) { return storage_info->get_recent_perf(); } + + map get_uid_records( double hours, uint64_t threshold, bool force_report) { return mUidm.dump(hours, threshold, force_report); } + void update_uid_io_interval(int interval) { if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) { mConfig.periodic_chores_interval_uid_io = interval; } } - void init_battery_service(); - virtual void batteryPropertiesChanged(struct BatteryProperties props); - void binderDied(const wp& who); + void add_user_ce(userid_t user_id); + void remove_user_ce(userid_t user_id); + + virtual ::android::hardware::Return healthInfoChanged( + const ::android::hardware::health::V2_0::HealthInfo& info); + void serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who); void report_storage_info(); + + void flush_protos(unordered_map* protos); }; // Eventlog tag diff --git a/storaged/include/storaged_diskstats.h b/storaged/include/storaged_diskstats.h new file mode 100644 index 000000000..0b93ba6c5 --- /dev/null +++ b/storaged/include/storaged_diskstats.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _STORAGED_DISKSTATS_H_ +#define _STORAGED_DISKSTATS_H_ + +#include + +#include + +// number of attributes diskstats has +#define DISK_STATS_SIZE ( 11 ) + +#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" +#define SDA_DISK_STATS_PATH "/sys/block/sda/stat" + +struct disk_stats { + /* It will be extremely unlikely for any of the following entries to overflow. + * For read_bytes(which will be greater than any of the following entries), it + * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which + * is the peak memory transfer rate for current memory. + * The diskstats entries (first 11) need to be at top in this structure _after_ + * compiler's optimization. + */ + uint64_t read_ios; // number of read I/Os processed + uint64_t read_merges; // number of read I/Os merged with in-queue I/Os + uint64_t read_sectors; // number of sectors read + uint64_t read_ticks; // total wait time for read requests + uint64_t write_ios; // number of write I/Os processed + uint64_t write_merges; // number of write I/Os merged with in-queue I/Os + uint64_t write_sectors; // number of sectors written + uint64_t write_ticks; // total wait time for write requests + uint64_t io_in_flight; // number of I/Os currently in flight + uint64_t io_ticks; // total time this block device has been active + uint64_t io_in_queue; // total wait time for all requests + + uint64_t start_time; // monotonic time accounting starts + uint64_t end_time; // monotonic time accounting ends + uint32_t counter; // private counter for accumulate calculations + double io_avg; // average io_in_flight for accumulate calculations + + bool is_zero() { + return read_ios == 0 && write_ios == 0 && + io_in_flight == 0 && io_ticks == 0 && io_in_queue == 0; + } + + friend disk_stats operator- (disk_stats curr, const disk_stats& prev) { + curr.read_ios -= prev.read_ios; + curr.read_merges -= prev.read_merges; + curr.read_sectors -= prev.read_sectors; + curr.read_ticks -= prev.read_ticks; + curr.write_ios -= prev.write_ios; + curr.write_merges -= prev.write_merges; + curr.write_sectors -= prev.write_sectors; + curr.write_ticks -= prev.write_ticks; + /* skips io_in_flight, use current value */ + curr.io_ticks -= prev.io_ticks; + curr.io_in_queue -= prev.io_in_queue; + return curr; + } + + friend bool operator== (const disk_stats& a, const disk_stats& b) { + return a.read_ios == b.read_ios && + a.read_merges == b.read_merges && + a.read_sectors == b.read_sectors && + a.read_ticks == b.read_ticks && + a.write_ios == b.write_ios && + a.write_merges == b.write_merges && + a.write_sectors == b.write_sectors && + a.write_ticks == b.write_ticks && + /* skips io_in_flight */ + a.io_ticks == b.io_ticks && + a.io_in_queue == b.io_in_queue; + } + + disk_stats& operator+= (const disk_stats& stats) { + read_ios += stats.read_ios; + read_merges += stats.read_merges; + read_sectors += stats.read_sectors; + read_ticks += stats.read_ticks; + write_ios += stats.write_ios; + write_merges += stats.write_merges; + write_sectors += stats.write_sectors; + write_ticks += stats.write_ticks; + /* skips io_in_flight, use current value */ + io_ticks += stats.io_ticks; + io_in_queue += stats.io_in_queue; + return *this; + } +}; + +struct disk_perf { + uint32_t read_perf; // read speed (kbytes/s) + uint32_t read_ios; // read I/Os per second + uint32_t write_perf; // write speed (kbytes/s) + uint32_t write_ios; // write I/Os per second + uint32_t queue; // I/Os in queue + bool is_zero() { + return read_perf == 0 && read_ios == 0 && + write_perf == 0 && write_ios == 0 && queue == 0; + } +}; + +class stream_stats { +private: + double mSum; + double mSquareSum; + uint32_t mCnt; +public: + stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {}; + ~stream_stats() {}; + double get_mean() { + return mSum / mCnt; + } + double get_std() { + return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt)); + } + void add(uint32_t num) { + mSum += (double)num; + mSquareSum += (double)num * (double)num; + mCnt++; + } + void evict(uint32_t num) { + if (mSum < num || mSquareSum < (double)num * (double)num) return; + mSum -= (double)num; + mSquareSum -= (double)num * (double)num; + mCnt--; + } +}; + +class disk_stats_monitor { +private: + FRIEND_TEST(storaged_test, disk_stats_monitor); + const char* const DISK_STATS_PATH; + struct disk_stats mPrevious; + struct disk_stats mAccumulate; /* reset after stall */ + struct disk_stats mAccumulate_pub; /* reset after publish */ + bool mStall; + std::queue mBuffer; + struct { + stream_stats read_perf; // read speed (bytes/s) + stream_stats read_ios; // read I/Os per second + stream_stats write_perf; // write speed (bytes/s) + stream_stats write_ios; // write I/O per second + stream_stats queue; // I/Os in queue + } mStats; + bool mValid; + const uint32_t mWindow; + const double mSigma; + struct disk_perf mMean; + struct disk_perf mStd; + android::sp mHealth; + + void update_mean(); + void update_std(); + void add(struct disk_perf* perf); + void evict(struct disk_perf* perf); + bool detect(struct disk_perf* perf); + + void update(struct disk_stats* stats); + +public: + disk_stats_monitor(const android::sp& healthService, + uint32_t window_size = 5, double sigma = 1.0) + : DISK_STATS_PATH( + healthService != nullptr + ? nullptr + : (access(MMC_DISK_STATS_PATH, R_OK) == 0 + ? MMC_DISK_STATS_PATH + : (access(SDA_DISK_STATS_PATH, R_OK) == 0 ? SDA_DISK_STATS_PATH : nullptr))), + mPrevious(), + mAccumulate(), + mAccumulate_pub(), + mStall(false), + mValid(false), + mWindow(window_size), + mSigma(sigma), + mMean(), + mStd(), + mHealth(healthService) {} + bool enabled() { return mHealth != nullptr || DISK_STATS_PATH != nullptr; } + void update(void); + void publish(void); +}; + +#endif /* _STORAGED_DISKSTATS_H_ */ diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h index 7d04c7a0d..9c3d0e784 100644 --- a/storaged/include/storaged_info.h +++ b/storaged/include/storaged_info.h @@ -19,14 +19,26 @@ #include +#include + +#include +#include + +#include "storaged.h" +#include "storaged.pb.h" + #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test using namespace std; +using namespace android; +using namespace chrono; +using namespace storaged_proto; class storage_info_t { -protected: + protected: FRIEND_TEST(storaged_test, storage_info_t); + FRIEND_TEST(storaged_test, storage_info_t_proto); // emmc lifetime uint16_t eol; // pre-eol (end of life) information uint16_t lifetime_a; // device life time estimation (type A) @@ -36,16 +48,38 @@ protected: const string userdata_path = "/data"; uint64_t userdata_total_kb; uint64_t userdata_free_kb; + // io perf history + time_point day_start_tp; + vector recent_perf; + uint32_t nr_samples; + vector daily_perf; + uint32_t nr_days; + vector weekly_perf; + uint32_t nr_weeks; + Mutex si_mutex; storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0), - userdata_total_kb(0), userdata_free_kb(0) {} + userdata_total_kb(0), userdata_free_kb(0), nr_samples(0), + daily_perf(WEEK_TO_DAYS, 0), nr_days(0), + weekly_perf(YEAR_TO_WEEKS, 0), nr_weeks(0) { + day_start_tp = system_clock::now(); + day_start_tp -= chrono::seconds(duration_cast( + day_start_tp.time_since_epoch()).count() % DAY_TO_SEC); + } void publish(); storage_info_t* s_info; -public: - static storage_info_t* get_storage_info(); - virtual ~storage_info_t() {} + + public: + static storage_info_t* get_storage_info( + const sp& healthService); + virtual ~storage_info_t() {}; virtual void report() {}; - void refresh(); + void load_perf_history_proto(const IOPerfHistory& perf_history); + void refresh(IOPerfHistory* perf_history); + void update_perf_history(uint32_t bw, + const time_point& tp); + vector get_perf_history(); + uint32_t get_recent_perf(); }; class emmc_info_t : public storage_info_t { @@ -69,4 +103,18 @@ public: virtual void report(); }; +class health_storage_info_t : public storage_info_t { + private: + using IHealth = hardware::health::V2_0::IHealth; + using StorageInfo = hardware::health::V2_0::StorageInfo; + + sp mHealth; + void set_values_from_hal_storage_info(const StorageInfo& halInfo); + + public: + health_storage_info_t(const sp& service) : mHealth(service){}; + virtual ~health_storage_info_t() {} + virtual void report(); +}; + #endif /* _STORAGED_INFO_H_ */ diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h index a8ddf4c32..7ec686415 100644 --- a/storaged/include/storaged_service.h +++ b/storaged/include/storaged_service.h @@ -19,42 +19,38 @@ #include -#include -#include +#include -#include "storaged.h" +#include "android/os/BnStoraged.h" +#include "android/os/storaged/BnStoragedPrivate.h" -using namespace android; +using namespace std; +using namespace android::os; +using namespace android::os::storaged; -// Interface -class IStoraged : public IInterface { +class StoragedService : public BinderService, public BnStoraged { +private: + void dumpUidRecordsDebug(int fd, const vector& entries); + void dumpUidRecords(int fd, const vector& entries); public: - enum { - DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION, - }; - // Request the service to run the test function - virtual std::vector dump_uids(const char* option) = 0; + static status_t start(); + static char const* getServiceName() { return "storaged"; } + virtual status_t dump(int fd, const Vector &args) override; - DECLARE_META_INTERFACE(Storaged); + binder::Status onUserStarted(int32_t userId); + binder::Status onUserStopped(int32_t userId); + binder::Status getRecentPerf(int32_t* _aidl_return); }; -// Client -class BpStoraged : public BpInterface { +class StoragedPrivateService : public BinderService, public BnStoragedPrivate { public: - BpStoraged(const sp& impl) : BpInterface(impl){}; - virtual std::vector dump_uids(const char* option); + static status_t start(); + static char const* getServiceName() { return "storaged_pri"; } + + binder::Status dumpUids(vector* _aidl_return); + binder::Status dumpPerfHistory(vector* _aidl_return); }; -// Server -class BnStoraged : public BnInterface { - virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); -}; - -class Storaged : public BnStoraged { - virtual std::vector dump_uids(const char* option); - virtual status_t dump(int fd, const Vector& args); -}; - -sp get_storaged_service(); +sp get_storaged_pri_service(); #endif /* _STORAGED_SERVICE_H_ */ \ No newline at end of file diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index 901a8721b..3a718fa60 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -23,88 +23,103 @@ #include #include -enum uid_stat_t { - FOREGROUND = 0, - BACKGROUND = 1, - UID_STATS = 2 +#include +#include + +#include "storaged.pb.h" +#include "uid_info.h" + +#define FRIEND_TEST(test_case_name, test_name) \ +friend class test_case_name##_##test_name##_Test + +using namespace std; +using namespace storaged_proto; +using namespace android; +using namespace android::os::storaged; + +class uid_info : public UidInfo { +public: + bool parse_uid_io_stats(string&& s); }; -enum charger_stat_t { - CHARGER_OFF = 0, - CHARGER_ON = 1, - CHARGER_STATS = 2 -}; - -enum io_type_t { - READ = 0, - WRITE = 1, - IO_TYPES = 2 -}; - -struct uid_io_stats { - uint64_t rchar; // characters read - uint64_t wchar; // characters written - uint64_t read_bytes; // bytes read (from storage layer) - uint64_t write_bytes; // bytes written (to storage layer) - uint64_t fsync; // number of fsync syscalls -}; - -struct uid_info { - uint32_t uid; // user id - std::string name; // package name - struct uid_io_stats io[UID_STATS]; // [0]:foreground [1]:background +class io_usage { +public: + io_usage() : bytes{{{0}}} {}; + uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS]; + bool is_zero() const; + io_usage& operator+= (const io_usage& stats) { + for (int i = 0; i < IO_TYPES; i++) { + for (int j = 0; j < UID_STATS; j++) { + for (int k = 0; k < CHARGER_STATS; k++) { + bytes[i][j][k] += stats.bytes[i][j][k]; + } + } + } + return *this; + } }; struct uid_io_usage { - uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS]; + userid_t user_id; + io_usage uid_ios; + // mapped from task comm to task io usage + map task_ios; }; struct uid_record { - std::string name; + string name; struct uid_io_usage ios; }; struct uid_records { uint64_t start_ts; - std::vector entries; + vector entries; }; class uid_monitor { private: + FRIEND_TEST(storaged_test, uid_monitor); // last dump from /proc/uid_io/stats, uid -> uid_info - std::unordered_map last_uid_io_stats; + unordered_map last_uid_io_stats; // current io usage for next report, app name -> uid_io_usage - std::unordered_map curr_io_stats; + unordered_map curr_io_stats; // io usage records, end timestamp -> {start timestamp, vector of records} - std::map records; + map io_history; // charger ON/OFF charger_stat_t charger_stat; // protects curr_io_stats, last_uid_io_stats, records and charger_stat - sem_t um_lock; + Mutex uidm_mutex; // start time for IO records uint64_t start_ts; + // true if UID_IO_STATS_PATH is accessible + const bool enable; // reads from /proc/uid_io/stats - std::unordered_map get_uid_io_stats_locked(); + unordered_map get_uid_io_stats_locked(); // flushes curr_io_stats to records void add_records_locked(uint64_t curr_ts); // updates curr_io_stats and set last_uid_io_stats void update_curr_io_stats_locked(); + // writes io_history to protobuf + void update_uid_io_proto(unordered_map* protos); public: uid_monitor(); - ~uid_monitor(); // called by storaged main thread void init(charger_stat_t stat); // called by storaged -u - std::unordered_map get_uid_io_stats(); + unordered_map get_uid_io_stats(); // called by dumpsys - std::map dump( + map dump( double hours, uint64_t threshold, bool force_report); // called by battery properties listener void set_charger_state(charger_stat_t stat); // called by storaged periodic_chore or dump with force_report - void report(); + bool enabled() { return enable; }; + void report(unordered_map* protos); + // restores io_history from protobuf + void load_uid_io_proto(const UidIOUsage& proto); + void clear_user_history(userid_t user_id); }; #endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h index 2161c4008..62cb12d1c 100644 --- a/storaged/include/storaged_utils.h +++ b/storaged/include/storaged_utils.h @@ -24,21 +24,20 @@ #include "storaged.h" +using namespace android::os::storaged; + // Diskstats bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats); struct disk_perf get_disk_perf(struct disk_stats* stats); -struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr); +void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr, struct disk_stats* inc); void add_disk_stats(struct disk_stats* src, struct disk_stats* dst); -bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info); // UID I/O -void sort_running_uids_info(std::vector &uids); +map merge_io_usage(const vector& entries); +void sort_running_uids_info(std::vector &uids); // Logging -void log_console_running_uids_info(std::vector uids); +void log_console_running_uids_info(const std::vector& uids, bool flag_dump_task); +void log_console_perf_history(const vector& perf_history); -void log_debug_disk_perf(struct disk_perf* perf, const char* type); - -void log_event_disk_stats(struct disk_stats* stats, const char* type); -void log_event_emmc_info(struct emmc_info* info_); #endif /* _STORAGED_UTILS_H_ */ diff --git a/storaged/include/uid_info.h b/storaged/include/uid_info.h new file mode 100644 index 000000000..c5533acb1 --- /dev/null +++ b/storaged/include/uid_info.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _UID_INFO_H_ +#define _UID_INFO_H_ + +#include +#include + +#include + +namespace android { +namespace os { +namespace storaged { + +enum uid_stat_t { + FOREGROUND = 0, + BACKGROUND = 1, + UID_STATS = 2 +}; + +enum charger_stat_t { + CHARGER_OFF = 0, + CHARGER_ON = 1, + CHARGER_STATS = 2 +}; + +enum io_type_t { + READ = 0, + WRITE = 1, + IO_TYPES = 2 +}; + +struct io_stats { + uint64_t rchar; // characters read + uint64_t wchar; // characters written + uint64_t read_bytes; // bytes read (from storage layer) + uint64_t write_bytes; // bytes written (to storage layer) + uint64_t fsync; // number of fsync syscalls +}; + +class task_info { +public: + std::string comm; + pid_t pid; + io_stats io[UID_STATS]; + bool parse_task_io_stats(std::string&& s); +}; + +class UidInfo : public Parcelable { +public: + uint32_t uid; // user id + std::string name; // package name + io_stats io[UID_STATS]; // [0]:foreground [1]:background + std::unordered_map tasks; // mapped from pid + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; +}; + +} // namespace storaged +} // namespace os +} // namespace android + +#endif /* _UID_INFO_H_ */ \ No newline at end of file diff --git a/storaged/main.cpp b/storaged/main.cpp index 72ec58fc4..3817fb580 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -39,72 +39,81 @@ #include #include -sp storaged; +using namespace std; +using namespace android; + +sp storaged_sp; // Function of storaged's main thread void* storaged_main(void* /* unused */) { - storaged = new storaged_t(); + storaged_sp = new storaged_t(); - storaged->init_battery_service(); - storaged->report_storage_info(); + storaged_sp->init(); + storaged_sp->report_storage_info(); LOG_TO(SYSTEM, INFO) << "storaged: Start"; for (;;) { - storaged->event_checked(); - storaged->pause(); + storaged_sp->event_checked(); + storaged_sp->pause(); } return NULL; } -static void help_message(void) { +void help_message(void) { printf("usage: storaged [OPTION]\n"); printf(" -u --uid Dump uid I/O usage to stdout\n"); + printf(" -t --task Dump task I/O usage to stdout\n"); + printf(" -p --perf Dump I/O perf history to stdout\n"); printf(" -s --start Start storaged (default)\n"); fflush(stdout); } int main(int argc, char** argv) { - int flag_main_service = 0; - int flag_dump_uid = 0; + bool flag_main_service = false; + bool flag_dump_uid = false; + bool flag_dump_task = false; + bool flag_dump_perf = false; int opt; for (;;) { int opt_idx = 0; static struct option long_options[] = { - {"start", no_argument, 0, 's'}, - {"kill", no_argument, 0, 'k'}, - {"uid", no_argument, 0, 'u'}, - {"help", no_argument, 0, 'h'} + {"perf", no_argument, nullptr, 'p'}, + {"start", no_argument, nullptr, 's'}, + {"task", no_argument, nullptr, 't'}, + {"uid", no_argument, nullptr, 'u'}, + {nullptr, 0, nullptr, 0} }; - opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx); + opt = getopt_long(argc, argv, ":pstu", long_options, &opt_idx); if (opt == -1) { break; } switch (opt) { + case 'p': + flag_dump_perf = true; + break; case 's': - flag_main_service = 1; + flag_main_service = true; + break; + case 't': + flag_dump_task = true; break; case 'u': - flag_dump_uid = 1; + flag_dump_uid = true; break; - case 'h': + default: help_message(); return 0; - case '?': - default: - fprintf(stderr, "no supported option\n"); - help_message(); - return -1; } } if (argc == 1) { - flag_main_service = 1; + flag_main_service = true; } - if (flag_main_service && flag_dump_uid) { + if (flag_main_service && (flag_dump_uid || flag_dump_task)) { fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n"); help_message(); return -1; @@ -119,7 +128,12 @@ int main(int argc, char** argv) { return -1; } - defaultServiceManager()->addService(String16("storaged"), new Storaged()); + if (StoragedService::start() != android::OK || + StoragedPrivateService::start() != android::OK) { + PLOG_TO(SYSTEM, ERROR) << "Failed to start storaged service"; + return -1; + } + android::ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); pthread_join(storaged_main_thread, NULL); @@ -127,23 +141,33 @@ int main(int argc, char** argv) { return 0; } - if (flag_dump_uid) { - sp storaged_service = get_storaged_service(); - if (storaged_service == NULL) { - fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n"); - return -1; - } - std::vector res = storaged_service->dump_uids(NULL); + sp storaged_service = get_storaged_pri_service(); + if (storaged_service == NULL) { + fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n"); + return -1; + } - if (res.size() == 0) { - fprintf(stderr, "UID I/O is not readable in this version of kernel.\n"); + if (flag_dump_uid || flag_dump_task) { + vector uid_io; + binder::Status status = storaged_service->dumpUids(&uid_io); + if (!status.isOk() || uid_io.size() == 0) { + fprintf(stderr, "UID I/O info is not available.\n"); return 0; } - sort_running_uids_info(res); - log_console_running_uids_info(res); + sort_running_uids_info(uid_io); + log_console_running_uids_info(uid_io, flag_dump_task); + } - return 0; + if (flag_dump_perf) { + vector perf_history; + binder::Status status = storaged_service->dumpPerfHistory(&perf_history); + if (!status.isOk() || perf_history.size() == 0) { + fprintf(stderr, "I/O perf history is not available.\n"); + return 0; + } + + log_console_perf_history(perf_history); } return 0; diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 06afea693..f346c387b 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -16,184 +16,118 @@ #define LOG_TAG "storaged" +#include #include +#include #include #include +#include +#include +#include +#include +#include + +#include #include +#include +#include #include -#include -#include -#include #include +#include +#include +#include #include #include #include -/* disk_stats_publisher */ -void disk_stats_publisher::publish(void) { - // Logging - struct disk_perf perf = get_disk_perf(&mAccumulate); - log_debug_disk_perf(&perf, "regular"); - log_event_disk_stats(&mAccumulate, "regular"); - // Reset global structures - memset(&mAccumulate, 0, sizeof(struct disk_stats)); -} +using namespace android::base; +using namespace chrono; +using namespace google::protobuf::io; +using namespace storaged_proto; -void disk_stats_publisher::update(void) { - struct disk_stats curr; - if (parse_disk_stats(DISK_STATS_PATH, &curr)) { - struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr); - add_disk_stats(&inc, &mAccumulate); -#ifdef DEBUG -// log_kernel_disk_stats(&mPrevious, "prev stats"); -// log_kernel_disk_stats(&curr, "curr stats"); -// log_kernel_disk_stats(&inc, "inc stats"); -// log_kernel_disk_stats(&mAccumulate, "accumulated stats"); -#endif - mPrevious = curr; - } -} +namespace { -/* disk_stats_monitor */ -void disk_stats_monitor::update_mean() { - CHECK(mValid); - mMean.read_perf = (uint32_t)mStats.read_perf.get_mean(); - mMean.read_ios = (uint32_t)mStats.read_ios.get_mean(); - mMean.write_perf = (uint32_t)mStats.write_perf.get_mean(); - mMean.write_ios = (uint32_t)mStats.write_ios.get_mean(); - mMean.queue = (uint32_t)mStats.queue.get_mean(); -} +/* + * The system user is the initial user that is implicitly created on first boot + * and hosts most of the system services. Keep this in sync with + * frameworks/base/core/java/android/os/UserManager.java + */ +constexpr int USER_SYSTEM = 0; -void disk_stats_monitor::update_std() { - CHECK(mValid); - mStd.read_perf = (uint32_t)mStats.read_perf.get_std(); - mStd.read_ios = (uint32_t)mStats.read_ios.get_std(); - mStd.write_perf = (uint32_t)mStats.write_perf.get_std(); - mStd.write_ios = (uint32_t)mStats.write_ios.get_std(); - mStd.queue = (uint32_t)mStats.queue.get_std(); -} +constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB -void disk_stats_monitor::add(struct disk_perf* perf) { - mStats.read_perf.add(perf->read_perf); - mStats.read_ios.add(perf->read_ios); - mStats.write_perf.add(perf->write_perf); - mStats.write_ios.add(perf->write_ios); - mStats.queue.add(perf->queue); -} +constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB -void disk_stats_monitor::evict(struct disk_perf* perf) { - mStats.read_perf.evict(perf->read_perf); - mStats.read_ios.evict(perf->read_ios); - mStats.write_perf.evict(perf->write_perf); - mStats.write_ios.evict(perf->write_ios); - mStats.queue.evict(perf->queue); -} +} // namespace -bool disk_stats_monitor::detect(struct disk_perf* perf) { - return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) && - ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) && - ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf); -} +const uint32_t storaged_t::current_version = 4; -void disk_stats_monitor::update(struct disk_stats* stats) { - struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats); - struct disk_perf perf = get_disk_perf(&inc); - // Update internal data structures - if (LIKELY(mValid)) { - CHECK_EQ(mBuffer.size(), mWindow); +using android::hardware::interfacesEqual; +using android::hardware::Return; +using android::hardware::health::V1_0::BatteryStatus; +using android::hardware::health::V1_0::toString; +using android::hardware::health::V2_0::get_health_service; +using android::hardware::health::V2_0::HealthInfo; +using android::hardware::health::V2_0::IHealth; +using android::hardware::health::V2_0::Result; +using android::hidl::manager::V1_0::IServiceManager; - if (UNLIKELY(detect(&perf))) { - mStall = true; - add_disk_stats(&inc, &mAccumulate); - log_debug_disk_perf(&mMean, "stalled_mean"); - log_debug_disk_perf(&mStd, "stalled_std"); - } else { - if (mStall) { - struct disk_perf acc_perf = get_disk_perf(&mAccumulate); - log_debug_disk_perf(&acc_perf, "stalled"); - log_event_disk_stats(&mAccumulate, "stalled"); - mStall = false; - memset(&mAccumulate, 0, sizeof(mAccumulate)); - } - } - evict(&mBuffer.front()); - mBuffer.pop(); - add(&perf); - mBuffer.push(perf); - - update_mean(); - update_std(); - - } else { /* mValid == false */ - CHECK_LT(mBuffer.size(), mWindow); - add(&perf); - mBuffer.push(perf); - if (mBuffer.size() == mWindow) { - mValid = true; - update_mean(); - update_std(); - } - } - - mPrevious = *stats; -} - -void disk_stats_monitor::update(void) { - struct disk_stats curr; - if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) { - update(&curr); - } -} - -static sp get_battery_properties_service() { - sp sm = defaultServiceManager(); - if (sm == NULL) return NULL; - - sp binder = sm->getService(String16("batteryproperties")); - if (binder == NULL) return NULL; - - sp battery_properties = - interface_cast(binder); - - return battery_properties; -} - -static inline charger_stat_t is_charger_on(int64_t prop) { - return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ? +inline charger_stat_t is_charger_on(BatteryStatus prop) { + return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ? CHARGER_ON : CHARGER_OFF; } -void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) { - mUidm.set_charger_state(is_charger_on(props.batteryStatus)); +Return storaged_t::healthInfoChanged(const HealthInfo& props) { + mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus)); + return android::hardware::Void(); } -void storaged_t::init_battery_service() { - if (!mConfig.proc_uid_io_available) +void storaged_t::init() { + init_health_service(); + mDsm = std::make_unique(health); + storage_info.reset(storage_info_t::get_storage_info(health)); +} + +void storaged_t::init_health_service() { + if (!mUidm.enabled()) return; - battery_properties = get_battery_properties_service(); - if (battery_properties == NULL) { - LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service"; + health = get_health_service(); + if (health == NULL) { + LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service"; return; } - struct BatteryProperty val; - battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val); - mUidm.init(is_charger_on(val.valueInt64)); + BatteryStatus status = BatteryStatus::UNKNOWN; + auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) { + if (r != Result::SUCCESS) { + LOG_TO(SYSTEM, WARNING) + << "health: cannot get battery status " << toString(r); + return; + } + if (v == BatteryStatus::UNKNOWN) { + LOG_TO(SYSTEM, WARNING) << "health: invalid battery status"; + } + status = v; + }); + if (!ret.isOk()) { + LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error " + << ret.description(); + } + mUidm.init(is_charger_on(status)); // register listener after init uid_monitor - battery_properties->registerListener(this); - IInterface::asBinder(battery_properties)->linkToDeath(this); + health->registerCallback(this); + health->linkToDeath(this, 0 /* cookie */); } -void storaged_t::binderDied(const wp& who) { - if (battery_properties != NULL && - IInterface::asBinder(battery_properties) == who) { - LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting"; - IPCThreadState::self()->stopProcess(); +void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) { + if (health != NULL && interfacesEqual(health, who.promote())) { + LOG_TO(SYSTEM, ERROR) << "health service died, exiting"; + android::hardware::IPCThreadState::self()->stopProcess(); exit(1); } else { LOG_TO(SYSTEM, ERROR) << "unknown service died"; @@ -206,44 +140,195 @@ void storaged_t::report_storage_info() { /* storaged_t */ storaged_t::storaged_t(void) { - if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) { - mConfig.diskstats_available = false; - } else { - mConfig.diskstats_available = true; - } - - mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); - mConfig.periodic_chores_interval_unit = - property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); + property_get_int32("ro.storaged.event.interval", + DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); mConfig.event_time_check_usec = property_get_int32("ro.storaged.event.perf_check", 0); mConfig.periodic_chores_interval_disk_stats_publish = - property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); + property_get_int32("ro.storaged.disk_stats_pub", + DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); mConfig.periodic_chores_interval_uid_io = - property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); + property_get_int32("ro.storaged.uid_io.interval", + DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); - storage_info.reset(storage_info_t::get_storage_info()); + mConfig.periodic_chores_interval_flush_proto = + property_get_int32("ro.storaged.flush_proto.interval", + DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO); mStarttime = time(NULL); + mTimer = 0; } -void storaged_t::event(void) { - if (mConfig.diskstats_available) { - mDiskStats.update(); - mDsm.update(); - storage_info->refresh(); - if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) { - mDiskStats.publish(); +void storaged_t::add_user_ce(userid_t user_id) { + load_proto(user_id); + proto_loaded[user_id] = true; +} + +void storaged_t::remove_user_ce(userid_t user_id) { + proto_loaded[user_id] = false; + mUidm.clear_user_history(user_id); + RemoveFileIfExists(proto_path(user_id), nullptr); +} + +void storaged_t::load_proto(userid_t user_id) { + string proto_file = proto_path(user_id); + ifstream in(proto_file, ofstream::in | ofstream::binary); + + if (!in.good()) return; + + stringstream ss; + ss << in.rdbuf(); + StoragedProto proto; + proto.ParseFromString(ss.str()); + + const UidIOUsage& uid_io_usage = proto.uid_io_usage(); + uint32_t computed_crc = crc32(current_version, + reinterpret_cast(uid_io_usage.SerializeAsString().c_str()), + uid_io_usage.ByteSize()); + if (proto.crc() != computed_crc) { + LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file; + return; + } + + mUidm.load_uid_io_proto(proto.uid_io_usage()); + + if (user_id == USER_SYSTEM) { + storage_info->load_perf_history_proto(proto.perf_history()); + } +} + +char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) { + proto->set_version(current_version); + + const UidIOUsage& uid_io_usage = proto->uid_io_usage(); + proto->set_crc(crc32(current_version, + reinterpret_cast(uid_io_usage.SerializeAsString().c_str()), + uid_io_usage.ByteSize())); + + uint32_t pagesize = sysconf(_SC_PAGESIZE); + if (user_id == USER_SYSTEM) { + proto->set_padding("", 1); + vector padding; + ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()), + pagesize); + padding = vector(size - proto->ByteSize(), 0xFD); + proto->set_padding(padding.data(), padding.size()); + while (!IS_ALIGNED(proto->ByteSize(), pagesize)) { + padding.push_back(0xFD); + proto->set_padding(padding.data(), padding.size()); } } - if (mConfig.proc_uid_io_available && mTimer && - (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { - mUidm.report(); + char* data = nullptr; + if (posix_memalign(reinterpret_cast(&data), + pagesize, proto->ByteSize())) { + PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: " + << proto->ByteSize() << ")"; + return data; + } + + proto->SerializeToArray(data, proto->ByteSize()); + return data; +} + +void storaged_t::flush_proto_data(userid_t user_id, + const char* data, ssize_t size) { + string proto_file = proto_path(user_id); + string tmp_file = proto_file + "_tmp"; + unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(), + O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC | + (user_id == USER_SYSTEM ? O_DIRECT : 0), + S_IRUSR | S_IWUSR))); + if (fd == -1) { + PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file; + return; + } + + if (user_id == USER_SYSTEM) { + time_point start, end; + uint32_t benchmark_size = 0; + uint64_t benchmark_time_ns = 0; + ssize_t ret; + bool first_write = true; + + while (size > 0) { + start = steady_clock::now(); + ret = write(fd, data, MIN(benchmark_unit_size, size)); + if (ret <= 0) { + PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file; + return; + } + end = steady_clock::now(); + /* + * compute bandwidth after the first write and if write returns + * exactly unit size. + */ + if (!first_write && ret == benchmark_unit_size) { + benchmark_size += benchmark_unit_size; + benchmark_time_ns += duration_cast(end - start).count(); + } + size -= ret; + data += ret; + first_write = false; + } + + if (benchmark_size) { + int perf = benchmark_size * 1000000LLU / benchmark_time_ns; + storage_info->update_perf_history(perf, system_clock::now()); + } + } else { + if (!WriteFully(fd, data, size)) { + PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file; + return; + } + } + + fd.reset(-1); + rename(tmp_file.c_str(), proto_file.c_str()); +} + +void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) { + unique_ptr proto_data(prepare_proto(user_id, proto)); + if (proto_data == nullptr) return; + + flush_proto_data(user_id, proto_data.get(), proto->ByteSize()); +} + +void storaged_t::flush_protos(unordered_map* protos) { + for (auto& it : *protos) { + /* + * Don't flush proto if we haven't attempted to load it from file. + */ + if (proto_loaded[it.first]) { + flush_proto(it.first, &it.second); + } + } +} + +void storaged_t::event(void) { + unordered_map protos; + + if (mDsm->enabled()) { + mDsm->update(); + if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) { + mDsm->publish(); + } + } + + if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) { + mUidm.report(&protos); + } + + if (storage_info) { + storage_info->refresh(protos[USER_SYSTEM].mutable_perf_history()); + } + + if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) { + flush_protos(&protos); } mTimer += mConfig.periodic_chores_interval_unit; diff --git a/storaged/storaged.proto b/storaged/storaged.proto new file mode 100644 index 000000000..2000c0b92 --- /dev/null +++ b/storaged/storaged.proto @@ -0,0 +1,60 @@ +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; +package storaged_proto; +option java_package = "com.android.storaged.proto"; +option java_outer_classname = "Storaged"; + +message IOUsage { + optional uint64 rd_fg_chg_on = 1; + optional uint64 rd_fg_chg_off = 2; + optional uint64 rd_bg_chg_on = 3; + optional uint64 rd_bg_chg_off = 4; + optional uint64 wr_fg_chg_on = 5; + optional uint64 wr_fg_chg_off = 6; + optional uint64 wr_bg_chg_on = 7; + optional uint64 wr_bg_chg_off = 8; +} + +message TaskIOUsage { + optional string task_name = 1; + optional IOUsage ios = 2; +} + +message UidRecord { + optional string uid_name = 1; + optional uint32 user_id = 2; + optional IOUsage uid_io = 3; + repeated TaskIOUsage task_io = 4; +} + +message UidIORecords { + optional uint64 start_ts = 1; + repeated UidRecord entries = 2; +} + +message UidIOItem { + optional uint64 end_ts = 1; + optional UidIORecords records = 2; +} + +message UidIOUsage { + repeated UidIOItem uid_io_items = 2; +} + +message IOPerfHistory { + optional uint64 day_start_sec = 1; + repeated uint32 recent_perf = 2; + optional uint32 nr_samples = 3; + repeated uint32 daily_perf = 4; + optional uint32 nr_days = 5; + repeated uint32 weekly_perf = 6; + optional uint32 nr_weeks = 7; +} + +message StoragedProto { + optional uint32 crc = 1; + optional uint32 version = 2; + optional UidIOUsage uid_io_usage = 3; + optional IOPerfHistory perf_history = 4; + optional bytes padding = 5; +} diff --git a/storaged/storaged.rc b/storaged/storaged.rc index ed2cf145a..0614fadd1 100644 --- a/storaged/storaged.rc +++ b/storaged/storaged.rc @@ -5,4 +5,4 @@ service storaged /system/bin/storaged file /d/mmc0/mmc0:0001/ext_csd r writepid /dev/cpuset/system-background/tasks user root - group package_info \ No newline at end of file + group package_info diff --git a/storaged/storaged_diskstats.cpp b/storaged/storaged_diskstats.cpp new file mode 100644 index 000000000..105003340 --- /dev/null +++ b/storaged/storaged_diskstats.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "storaged" + +#include +#include + +#include + +#include +#include +#include + +#include "storaged.h" +#include "storaged_diskstats.h" + +namespace { + +using android::sp; +using android::hardware::health::V2_0::DiskStats; +using android::hardware::health::V2_0::IHealth; +using android::hardware::health::V2_0::Result; +using android::hardware::health::V2_0::toString; + +#ifdef DEBUG +void log_debug_disk_perf(struct disk_perf* perf, const char* type) { + // skip if the input structure are all zeros + if (perf == NULL || perf->is_zero()) return; + + LOG_TO(SYSTEM, INFO) << "disk_perf " << type + << " rd: " << perf->read_perf << " kbps, " << perf->read_ios << " iops" + << " wr: " << perf->write_perf << " kbps, " << perf->write_ios << " iops" + << " q: " << perf->queue; +} +#else +void log_debug_disk_perf(struct disk_perf* perf, const char* type) {} +#endif + +void log_event_disk_stats(struct disk_stats* stats, const char* type) { + // skip if the input structure are all zeros + if (stats == NULL || stats->is_zero()) return; + + android_log_event_list(EVENTLOGTAG_DISKSTATS) + << type << stats->start_time << stats->end_time + << stats->read_ios << stats->read_merges + << stats->read_sectors << stats->read_ticks + << stats->write_ios << stats->write_merges + << stats->write_sectors << stats->write_ticks + << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue + << LOG_ID_EVENTS; +} + +} // namespace + +bool get_time(struct timespec* ts) { + // Use monotonic to exclude suspend time so that we measure IO bytes/sec + // when system is running. + int ret = clock_gettime(CLOCK_MONOTONIC, ts); + if (ret < 0) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + return false; + } + return true; +} + +void init_disk_stats_other(const struct timespec& ts, struct disk_stats* stats) { + stats->start_time = 0; + stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC + ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC); + stats->counter = 1; + stats->io_avg = (double)stats->io_in_flight; +} + +bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) { + // Get time + struct timespec ts; + if (!get_time(&ts)) { + return false; + } + + std::string buffer; + if (!android::base::ReadFileToString(disk_stats_path, &buffer)) { + PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed."; + return false; + } + + // Regular diskstats entries + std::stringstream ss(buffer); + for (uint i = 0; i < DISK_STATS_SIZE; ++i) { + ss >> *((uint64_t*)stats + i); + } + // Other entries + init_disk_stats_other(ts, stats); + return true; +} + +void convert_hal_disk_stats(struct disk_stats* dst, const DiskStats& src) { + dst->read_ios = src.reads; + dst->read_merges = src.readMerges; + dst->read_sectors = src.readSectors; + dst->read_ticks = src.readTicks; + dst->write_ios = src.writes; + dst->write_merges = src.writeMerges; + dst->write_sectors = src.writeSectors; + dst->write_ticks = src.writeTicks; + dst->io_in_flight = src.ioInFlight; + dst->io_ticks = src.ioTicks; + dst->io_in_queue = src.ioInQueue; +} + +bool get_disk_stats_from_health_hal(const sp& service, struct disk_stats* stats) { + struct timespec ts; + if (!get_time(&ts)) { + return false; + } + + bool success = false; + auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) { + if (result != Result::SUCCESS || halStats.size() == 0) { + LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with result " << toString(result) + << " and size " << halStats.size(); + return; + } + + convert_hal_disk_stats(stats, halStats[0]); + success = true; + }); + + if (!ret.isOk()) { + LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with " << ret.description(); + return false; + } + + if (!success) { + return false; + } + + init_disk_stats_other(ts, stats); + return true; +} + +struct disk_perf get_disk_perf(struct disk_stats* stats) +{ + struct disk_perf perf = {}; + + if (stats->io_ticks) { + if (stats->read_ticks) { + unsigned long long divisor = stats->read_ticks * stats->io_ticks; + perf.read_perf = ((unsigned long long)SECTOR_SIZE * + stats->read_sectors * stats->io_in_queue + + (divisor >> 1)) / divisor; + perf.read_ios = ((unsigned long long)SEC_TO_MSEC * + stats->read_ios * stats->io_in_queue + + (divisor >> 1)) / divisor; + } + if (stats->write_ticks) { + unsigned long long divisor = stats->write_ticks * stats->io_ticks; + perf.write_perf = ((unsigned long long)SECTOR_SIZE * + stats->write_sectors * stats->io_in_queue + + (divisor >> 1)) / divisor; + perf.write_ios = ((unsigned long long)SEC_TO_MSEC * + stats->write_ios * stats->io_in_queue + + (divisor >> 1)) / divisor; + } + perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) / + stats->io_ticks; + } + return perf; +} + +void get_inc_disk_stats(const struct disk_stats* prev, const struct disk_stats* curr, + struct disk_stats* inc) +{ + *inc = *curr - *prev; + inc->start_time = prev->end_time; + inc->end_time = curr->end_time; + inc->io_avg = curr->io_avg; + inc->counter = 1; +} + +// Add src to dst +void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) +{ + if (dst->end_time != 0 && dst->end_time != src->start_time) { + LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats" + << " are added. dst end with " << dst->end_time + << ", src start with " << src->start_time; + } + + *dst += *src; + + dst->io_in_flight = src->io_in_flight; + if (dst->counter + src->counter) { + dst->io_avg = + ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) / + (dst->counter + src->counter); + } + dst->counter += src->counter; + dst->end_time = src->end_time; + if (dst->start_time == 0) { + dst->start_time = src->start_time; + } +} + +/* disk_stats_monitor */ +void disk_stats_monitor::update_mean() +{ + CHECK(mValid); + mMean.read_perf = (uint32_t)mStats.read_perf.get_mean(); + mMean.read_ios = (uint32_t)mStats.read_ios.get_mean(); + mMean.write_perf = (uint32_t)mStats.write_perf.get_mean(); + mMean.write_ios = (uint32_t)mStats.write_ios.get_mean(); + mMean.queue = (uint32_t)mStats.queue.get_mean(); +} + +void disk_stats_monitor::update_std() +{ + CHECK(mValid); + mStd.read_perf = (uint32_t)mStats.read_perf.get_std(); + mStd.read_ios = (uint32_t)mStats.read_ios.get_std(); + mStd.write_perf = (uint32_t)mStats.write_perf.get_std(); + mStd.write_ios = (uint32_t)mStats.write_ios.get_std(); + mStd.queue = (uint32_t)mStats.queue.get_std(); +} + +void disk_stats_monitor::add(struct disk_perf* perf) +{ + mStats.read_perf.add(perf->read_perf); + mStats.read_ios.add(perf->read_ios); + mStats.write_perf.add(perf->write_perf); + mStats.write_ios.add(perf->write_ios); + mStats.queue.add(perf->queue); +} + +void disk_stats_monitor::evict(struct disk_perf* perf) { + mStats.read_perf.evict(perf->read_perf); + mStats.read_ios.evict(perf->read_ios); + mStats.write_perf.evict(perf->write_perf); + mStats.write_ios.evict(perf->write_ios); + mStats.queue.evict(perf->queue); +} + +bool disk_stats_monitor::detect(struct disk_perf* perf) +{ + return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) && + ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) && + ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf); +} + +void disk_stats_monitor::update(struct disk_stats* curr) +{ + disk_stats inc; + get_inc_disk_stats(&mPrevious, curr, &inc); + add_disk_stats(&inc, &mAccumulate_pub); + + struct disk_perf perf = get_disk_perf(&inc); + log_debug_disk_perf(&perf, "regular"); + + add(&perf); + mBuffer.push(perf); + if (mBuffer.size() > mWindow) { + evict(&mBuffer.front()); + mBuffer.pop(); + mValid = true; + } + + // Update internal data structures + if (LIKELY(mValid)) { + CHECK_EQ(mBuffer.size(), mWindow); + update_mean(); + update_std(); + if (UNLIKELY(detect(&perf))) { + mStall = true; + add_disk_stats(&inc, &mAccumulate); + log_debug_disk_perf(&mMean, "stalled_mean"); + log_debug_disk_perf(&mStd, "stalled_std"); + } else { + if (mStall) { + struct disk_perf acc_perf = get_disk_perf(&mAccumulate); + log_debug_disk_perf(&acc_perf, "stalled"); + log_event_disk_stats(&mAccumulate, "stalled"); + mStall = false; + memset(&mAccumulate, 0, sizeof(mAccumulate)); + } + } + } + + mPrevious = *curr; +} + +void disk_stats_monitor::update() { + disk_stats curr; + if (mHealth != nullptr) { + if (!get_disk_stats_from_health_hal(mHealth, &curr)) { + return; + } + } else { + if (!parse_disk_stats(DISK_STATS_PATH, &curr)) { + return; + } + } + + update(&curr); +} + +void disk_stats_monitor::publish(void) +{ + struct disk_perf perf = get_disk_perf(&mAccumulate_pub); + log_debug_disk_perf(&perf, "regular"); + log_event_disk_stats(&mAccumulate, "regular"); + // Reset global structures + memset(&mAccumulate_pub, 0, sizeof(struct disk_stats)); +} diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp index b5fb13e0c..5605f667c 100644 --- a/storaged/storaged_info.cpp +++ b/storaged/storaged_info.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include #include #include @@ -27,9 +29,16 @@ #include #include "storaged.h" +#include "storaged_info.h" using namespace std; +using namespace chrono; using namespace android::base; +using namespace storaged_proto; + +using android::hardware::health::V2_0::IHealth; +using android::hardware::health::V2_0::Result; +using android::hardware::health::V2_0::StorageInfo; const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/"; const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd"; @@ -39,14 +48,20 @@ const char* emmc_info_t::emmc_ver_str[9] = { const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health"; -static bool FileExists(const std::string& filename) +namespace { + +bool FileExists(const std::string& filename) { struct stat buffer; return stat(filename.c_str(), &buffer) == 0; } -storage_info_t* storage_info_t::get_storage_info() -{ +} // namespace + +storage_info_t* storage_info_t::get_storage_info(const sp& healthService) { + if (healthService != nullptr) { + return new health_storage_info_t(healthService); + } if (FileExists(emmc_info_t::emmc_sysfs) || FileExists(emmc_info_t::emmc_debugfs)) { return new emmc_info_t; @@ -57,7 +72,39 @@ storage_info_t* storage_info_t::get_storage_info() return new storage_info_t; } -void storage_info_t::refresh() +void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history) +{ + Mutex::Autolock _l(si_mutex); + + if (!perf_history.has_day_start_sec() || + perf_history.daily_perf_size() > (int)daily_perf.size() || + perf_history.weekly_perf_size() > (int)weekly_perf.size()) { + LOG_TO(SYSTEM, ERROR) << "Invalid IOPerfHistory proto"; + return; + } + + day_start_tp = {}; + day_start_tp += chrono::seconds(perf_history.day_start_sec()); + + nr_samples = perf_history.nr_samples(); + for (auto bw : perf_history.recent_perf()) { + recent_perf.push_back(bw); + } + + nr_days = perf_history.nr_days(); + int i = 0; + for (auto bw : perf_history.daily_perf()) { + daily_perf[i++] = bw; + } + + nr_weeks = perf_history.nr_weeks(); + i = 0; + for (auto bw : perf_history.weekly_perf()) { + weekly_perf[i++] = bw; + } +} + +void storage_info_t::refresh(IOPerfHistory* perf_history) { struct statvfs buf; if (statvfs(userdata_path.c_str(), &buf) != 0) { @@ -67,6 +114,24 @@ void storage_info_t::refresh() userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10; userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10; + + Mutex::Autolock _l(si_mutex); + + perf_history->Clear(); + perf_history->set_day_start_sec( + duration_cast(day_start_tp.time_since_epoch()).count()); + for (const uint32_t& bw : recent_perf) { + perf_history->add_recent_perf(bw); + } + perf_history->set_nr_samples(nr_samples); + for (const uint32_t& bw : daily_perf) { + perf_history->add_daily_perf(bw); + } + perf_history->set_nr_days(nr_days); + for (const uint32_t& bw : weekly_perf) { + perf_history->add_weekly_perf(bw); + } + perf_history->set_nr_weeks(nr_weeks); } void storage_info_t::publish() @@ -76,6 +141,95 @@ void storage_info_t::publish() << LOG_ID_EVENTS; } +void storage_info_t::update_perf_history(uint32_t bw, + const time_point& tp) +{ + Mutex::Autolock _l(si_mutex); + + if (tp > day_start_tp && + duration_cast(tp - day_start_tp).count() < DAY_TO_SEC) { + if (nr_samples >= recent_perf.size()) { + recent_perf.push_back(bw); + } else { + recent_perf[nr_samples] = bw; + } + nr_samples++; + return; + } + + if (nr_samples < recent_perf.size()) { + recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end()); + } + + uint32_t daily_avg_bw = 0; + if (!recent_perf.empty()) { + daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size(); + } + + day_start_tp = tp - chrono::seconds(duration_cast( + tp.time_since_epoch()).count() % DAY_TO_SEC); + + nr_samples = 0; + if (recent_perf.empty()) + recent_perf.resize(1); + recent_perf[nr_samples++] = bw; + + if (nr_days < WEEK_TO_DAYS) { + daily_perf[nr_days++] = daily_avg_bw; + return; + } + + DCHECK(nr_days > 0); + uint32_t week_avg_bw = accumulate(daily_perf.begin(), + daily_perf.begin() + nr_days, 0) / nr_days; + + nr_days = 0; + daily_perf[nr_days++] = daily_avg_bw; + + if (nr_weeks >= YEAR_TO_WEEKS) { + nr_weeks = 0; + } + weekly_perf[nr_weeks++] = week_avg_bw; +} + +vector storage_info_t::get_perf_history() +{ + Mutex::Autolock _l(si_mutex); + + vector ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size()); + + ret[0] = recent_perf.size(); + ret[1] = daily_perf.size(); + ret[2] = weekly_perf.size(); + + int start = 3; + for (size_t i = 0; i < recent_perf.size(); i++) { + int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size(); + ret[start + i] = recent_perf[idx]; + } + + start += recent_perf.size(); + for (size_t i = 0; i < daily_perf.size(); i++) { + int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size(); + ret[start + i] = daily_perf[idx]; + } + + start += daily_perf.size(); + for (size_t i = 0; i < weekly_perf.size(); i++) { + int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size(); + ret[start + i] = weekly_perf[idx]; + } + + return ret; +} + +uint32_t storage_info_t::get_recent_perf() { + Mutex::Autolock _l(si_mutex); + if (recent_perf.size() == 0) return 0; + return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) / + recent_perf.size(); +} + void emmc_info_t::report() { if (!report_sysfs() && !report_debugfs()) @@ -121,6 +275,8 @@ bool emmc_info_t::report_sysfs() return true; } +namespace { + const size_t EXT_CSD_FILE_MIN_SIZE = 1024; /* 2 characters in string for each byte */ const size_t EXT_CSD_REV_IDX = 192 * 2; @@ -128,6 +284,8 @@ const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2; const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2; const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2; +} // namespace + bool emmc_info_t::report_debugfs() { string buffer; @@ -210,3 +368,25 @@ void ufs_info_t::report() publish(); } +void health_storage_info_t::report() { + auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) { + if (result != Result::SUCCESS || halInfos.size() == 0) { + LOG_TO(SYSTEM, DEBUG) << "getStorageInfo failed with result " << toString(result) + << " and size " << halInfos.size(); + return; + } + set_values_from_hal_storage_info(halInfos[0]); + publish(); + }); + + if (!ret.isOk()) { + LOG_TO(SYSTEM, DEBUG) << "getStorageInfo failed with " << ret.description(); + } +} + +void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) { + eol = halInfo.eol; + lifetime_a = halInfo.lifetimeA; + lifetime_b = halInfo.lifetimeB; + version = halInfo.version; +} diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp index b1d3bfd24..17ea25b82 100644 --- a/storaged/storaged_service.cpp +++ b/storaged/storaged_service.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -29,60 +30,69 @@ #include #include +#include #include +using namespace std; using namespace android::base; -extern sp storaged; +extern sp storaged_sp; -std::vector BpStoraged::dump_uids(const char* /*option*/) { - Parcel data, reply; - data.writeInterfaceToken(IStoraged::getInterfaceDescriptor()); - - remote()->transact(DUMPUIDS, data, &reply); - - uint32_t res_size = reply.readInt32(); - std::vector res(res_size); - for (auto&& uid : res) { - uid.uid = reply.readInt32(); - uid.name = reply.readCString(); - reply.read(&uid.io, sizeof(uid.io)); - } - return res; +status_t StoragedService::start() { + return BinderService::publish(); } -IMPLEMENT_META_INTERFACE(Storaged, "Storaged"); -status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch(code) { - case DUMPUIDS: { - if (!data.checkInterface(this)) - return BAD_TYPE; - std::vector res = dump_uids(NULL); - reply->writeInt32(res.size()); - for (auto uid : res) { - reply->writeInt32(uid.uid); - reply->writeCString(uid.name.c_str()); - reply->write(&uid.io, sizeof(uid.io)); - } - return NO_ERROR; - } - break; - default: - return BBinder::onTransact(code, data, reply, flags); +void StoragedService::dumpUidRecords(int fd, const vector& entries) { + map merged_entries = merge_io_usage(entries); + for (const auto& rec : merged_entries) { + dprintf(fd, "%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + rec.first.c_str(), + rec.second.bytes[READ][FOREGROUND][CHARGER_OFF], + rec.second.bytes[WRITE][FOREGROUND][CHARGER_OFF], + rec.second.bytes[READ][BACKGROUND][CHARGER_OFF], + rec.second.bytes[WRITE][BACKGROUND][CHARGER_OFF], + rec.second.bytes[READ][FOREGROUND][CHARGER_ON], + rec.second.bytes[WRITE][FOREGROUND][CHARGER_ON], + rec.second.bytes[READ][BACKGROUND][CHARGER_ON], + rec.second.bytes[WRITE][BACKGROUND][CHARGER_ON]); } } -std::vector Storaged::dump_uids(const char* /* option */) { - std::vector uids_v; - std::unordered_map uids_m = storaged->get_uids(); +void StoragedService::dumpUidRecordsDebug(int fd, const vector& entries) { + for (const auto& record : entries) { + const io_usage& uid_usage = record.ios.uid_ios; + dprintf(fd, "%s_%d %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + record.name.c_str(), record.ios.user_id, + uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF], + uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF], + uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF], + uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF], + uid_usage.bytes[READ][FOREGROUND][CHARGER_ON], + uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON], + uid_usage.bytes[READ][BACKGROUND][CHARGER_ON], + uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON]); - for (const auto& it : uids_m) { - uids_v.push_back(it.second); + for (const auto& task_it : record.ios.task_ios) { + const io_usage& task_usage = task_it.second; + const string& comm = task_it.first; + dprintf(fd, "-> %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + comm.c_str(), + task_usage.bytes[READ][FOREGROUND][CHARGER_OFF], + task_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF], + task_usage.bytes[READ][BACKGROUND][CHARGER_OFF], + task_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF], + task_usage.bytes[READ][FOREGROUND][CHARGER_ON], + task_usage.bytes[WRITE][FOREGROUND][CHARGER_ON], + task_usage.bytes[READ][BACKGROUND][CHARGER_ON], + task_usage.bytes[WRITE][BACKGROUND][CHARGER_ON]); + } } - return uids_v; } -status_t Storaged::dump(int fd, const Vector& args) { +status_t StoragedService::dump(int fd, const Vector& args) { IPCThreadState* self = IPCThreadState::self(); const int pid = self->getCallingPid(); const int uid = self->getCallingUid(); @@ -96,6 +106,7 @@ status_t Storaged::dump(int fd, const Vector& args) { int time_window = 0; uint64_t threshold = 0; bool force_report = false; + bool debug = false; for (size_t i = 0; i < args.size(); i++) { const auto& arg = args[i]; if (arg == String16("--hours")) { @@ -123,47 +134,87 @@ status_t Storaged::dump(int fd, const Vector& args) { force_report = true; continue; } + if (arg == String16("--debug")) { + debug = true; + continue; + } } uint64_t last_ts = 0; - const std::map& records = - storaged->get_uid_records(hours, threshold, force_report); + map records = + storaged_sp->get_uid_records(hours, threshold, force_report); for (const auto& it : records) { if (last_ts != it.second.start_ts) { - dprintf(fd, "%llu", (unsigned long long)it.second.start_ts); + dprintf(fd, "%" PRIu64, it.second.start_ts); } - dprintf(fd, ",%llu\n", (unsigned long long)it.first); + dprintf(fd, ",%" PRIu64 "\n", it.first); last_ts = it.first; - for (const auto& record : it.second.entries) { - dprintf(fd, "%s %ju %ju %ju %ju %ju %ju %ju %ju\n", - record.name.c_str(), - record.ios.bytes[READ][FOREGROUND][CHARGER_OFF], - record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], - record.ios.bytes[READ][BACKGROUND][CHARGER_OFF], - record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF], - record.ios.bytes[READ][FOREGROUND][CHARGER_ON], - record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON], - record.ios.bytes[READ][BACKGROUND][CHARGER_ON], - record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]); + if (!debug) { + dumpUidRecords(fd, it.second.entries); + } else { + dumpUidRecordsDebug(fd, it.second.entries); } } if (time_window) { - storaged->update_uid_io_interval(time_window); + storaged_sp->update_uid_io_interval(time_window); } return NO_ERROR; } -sp get_storaged_service() { +binder::Status StoragedService::onUserStarted(int32_t userId) { + storaged_sp->add_user_ce(userId); + return binder::Status::ok(); +} + +binder::Status StoragedService::onUserStopped(int32_t userId) { + storaged_sp->remove_user_ce(userId); + return binder::Status::ok(); +} + +binder::Status StoragedService::getRecentPerf(int32_t* _aidl_return) { + uint32_t recent_perf = storaged_sp->get_recent_perf(); + if (recent_perf > INT32_MAX) { + *_aidl_return = INT32_MAX; + } else { + *_aidl_return = static_cast(recent_perf); + } + return binder::Status::ok(); +} + +status_t StoragedPrivateService::start() { + return BinderService::publish(); +} + +binder::Status StoragedPrivateService::dumpUids( + vector<::android::os::storaged::UidInfo>* _aidl_return) { + unordered_map uids_m = storaged_sp->get_uids(); + + for (const auto& it : uids_m) { + UidInfo uinfo; + uinfo.uid = it.second.uid; + uinfo.name = it.second.name; + uinfo.tasks = it.second.tasks; + memcpy(&uinfo.io, &it.second.io, sizeof(uinfo.io)); + _aidl_return->push_back(uinfo); + } + return binder::Status::ok(); +} + +binder::Status StoragedPrivateService::dumpPerfHistory( + vector* _aidl_return) { + *_aidl_return = storaged_sp->get_perf_history(); + return binder::Status::ok(); +} + +sp get_storaged_pri_service() { sp sm = defaultServiceManager(); if (sm == NULL) return NULL; - sp binder = sm->getService(String16("storaged")); + sp binder = sm->getService(String16("storaged_pri")); if (binder == NULL) return NULL; - sp storaged = interface_cast(binder); - - return storaged; + return interface_cast(binder); } diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index dd8bdd6e8..5745782b2 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -38,16 +38,87 @@ using namespace android; using namespace android::base; using namespace android::content::pm; +using namespace android::os::storaged; +using namespace storaged_proto; -static bool refresh_uid_names; +namespace { -std::unordered_map uid_monitor::get_uid_io_stats() +bool refresh_uid_names; +const char* UID_IO_STATS_PATH = "/proc/uid_io/stats"; + +} // namepsace + +std::unordered_map uid_monitor::get_uid_io_stats() { - std::unique_ptr lock(new lock_t(&um_lock)); + Mutex::Autolock _l(uidm_mutex); return get_uid_io_stats_locked(); }; -static void get_uid_names(const vector& uids, const vector& uid_names) +/* return true on parse success and false on failure */ +bool uid_info::parse_uid_io_stats(std::string&& s) +{ + std::vector fields = Split(s, " "); + if (fields.size() < 11 || + !ParseUint(fields[0], &uid) || + !ParseUint(fields[1], &io[FOREGROUND].rchar) || + !ParseUint(fields[2], &io[FOREGROUND].wchar) || + !ParseUint(fields[3], &io[FOREGROUND].read_bytes) || + !ParseUint(fields[4], &io[FOREGROUND].write_bytes) || + !ParseUint(fields[5], &io[BACKGROUND].rchar) || + !ParseUint(fields[6], &io[BACKGROUND].wchar) || + !ParseUint(fields[7], &io[BACKGROUND].read_bytes) || + !ParseUint(fields[8], &io[BACKGROUND].write_bytes) || + !ParseUint(fields[9], &io[FOREGROUND].fsync) || + !ParseUint(fields[10], &io[BACKGROUND].fsync)) { + LOG_TO(SYSTEM, WARNING) << "Invalid uid I/O stats: \"" + << s << "\""; + return false; + } + return true; +} + +/* return true on parse success and false on failure */ +bool task_info::parse_task_io_stats(std::string&& s) +{ + std::vector fields = Split(s, ","); + size_t size = fields.size(); + if (size < 13 || + !ParseInt(fields[size - 11], &pid) || + !ParseUint(fields[size - 10], &io[FOREGROUND].rchar) || + !ParseUint(fields[size - 9], &io[FOREGROUND].wchar) || + !ParseUint(fields[size - 8], &io[FOREGROUND].read_bytes) || + !ParseUint(fields[size - 7], &io[FOREGROUND].write_bytes) || + !ParseUint(fields[size - 6], &io[BACKGROUND].rchar) || + !ParseUint(fields[size - 5], &io[BACKGROUND].wchar) || + !ParseUint(fields[size - 4], &io[BACKGROUND].read_bytes) || + !ParseUint(fields[size - 3], &io[BACKGROUND].write_bytes) || + !ParseUint(fields[size - 2], &io[FOREGROUND].fsync) || + !ParseUint(fields[size - 1], &io[BACKGROUND].fsync)) { + LOG_TO(SYSTEM, WARNING) << "Invalid task I/O stats: \"" + << s << "\""; + return false; + } + comm = Join(std::vector( + fields.begin() + 1, fields.end() - 11), ','); + return true; +} + +bool io_usage::is_zero() const +{ + for (int i = 0; i < IO_TYPES; i++) { + for (int j = 0; j < UID_STATS; j++) { + for (int k = 0; k < CHARGER_STATS; k++) { + if (bytes[i][j][k]) + return false; + } + } + } + return true; +} + +namespace { + +void get_uid_names(const vector& uids, const vector& uid_names) { sp sm = defaultServiceManager(); if (sm == NULL) { @@ -79,17 +150,19 @@ static void get_uid_names(const vector& uids, const vector& u refresh_uid_names = false; } -std::unordered_map uid_monitor::get_uid_io_stats_locked() +} // namespace + +std::unordered_map uid_monitor::get_uid_io_stats_locked() { - std::unordered_map uid_io_stats; + std::unordered_map uid_io_stats; std::string buffer; if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) { PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; return uid_io_stats; } - std::vector io_stats = Split(buffer, "\n"); - struct uid_info u; + std::vector io_stats = Split(std::move(buffer), "\n"); + uid_info u; vector uids; vector uid_names; @@ -97,32 +170,24 @@ std::unordered_map uid_monitor::get_uid_io_stats_lock if (io_stats[i].empty()) { continue; } - std::vector fields = Split(io_stats[i], " "); - if (fields.size() < 11 || - !ParseUint(fields[0], &u.uid) || - !ParseUint(fields[1], &u.io[FOREGROUND].rchar) || - !ParseUint(fields[2], &u.io[FOREGROUND].wchar) || - !ParseUint(fields[3], &u.io[FOREGROUND].read_bytes) || - !ParseUint(fields[4], &u.io[FOREGROUND].write_bytes) || - !ParseUint(fields[5], &u.io[BACKGROUND].rchar) || - !ParseUint(fields[6], &u.io[BACKGROUND].wchar) || - !ParseUint(fields[7], &u.io[BACKGROUND].read_bytes) || - !ParseUint(fields[8], &u.io[BACKGROUND].write_bytes) || - !ParseUint(fields[9], &u.io[FOREGROUND].fsync) || - !ParseUint(fields[10], &u.io[BACKGROUND].fsync)) { - LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \"" - << io_stats[i] << "\""; - continue; - } - uid_io_stats[u.uid] = u; - uid_io_stats[u.uid].name = std::to_string(u.uid); - uids.push_back(u.uid); - uid_names.push_back(&uid_io_stats[u.uid].name); - if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) { - refresh_uid_names = true; + if (io_stats[i].compare(0, 4, "task")) { + if (!u.parse_uid_io_stats(std::move(io_stats[i]))) + continue; + uid_io_stats[u.uid] = u; + uid_io_stats[u.uid].name = std::to_string(u.uid); + uids.push_back(u.uid); + uid_names.push_back(&uid_io_stats[u.uid].name); + if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) { + refresh_uid_names = true; + } else { + uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name; + } } else { - uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name; + task_info t; + if (!t.parse_task_io_stats(std::move(io_stats[i]))) + continue; + uid_io_stats[u.uid].tasks[t.pid] = t; } } @@ -133,34 +198,41 @@ std::unordered_map uid_monitor::get_uid_io_stats_lock return uid_io_stats; } -static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours +namespace { -static inline int records_size( - const std::map& curr_records) +const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours + +inline size_t history_size( + const std::map& history) { - int count = 0; - for (auto const& it : curr_records) { + size_t count = 0; + for (auto const& it : history) { count += it.second.entries.size(); } return count; } -static struct uid_io_usage zero_io_usage; +} // namespace void uid_monitor::add_records_locked(uint64_t curr_ts) { // remove records more than 5 days old if (curr_ts > 5 * DAY_TO_SEC) { - auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC); - records.erase(records.begin(), it); + auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC); + io_history.erase(io_history.begin(), it); } struct uid_records new_records; for (const auto& p : curr_io_stats) { struct uid_record record = {}; record.name = p.first; - record.ios = p.second; - if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) { + if (!p.second.uid_ios.is_zero()) { + record.ios.user_id = p.second.user_id; + record.ios.uid_ios = p.second.uid_ios; + for (const auto& p_task : p.second.task_ios) { + if (!p_task.second.is_zero()) + record.ios.task_ios[p_task.first] = p_task.second; + } new_records.entries.push_back(record); } } @@ -173,25 +245,25 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) return; // make some room for new records - int overflow = records_size(records) + + ssize_t overflow = history_size(io_history) + new_records.entries.size() - MAX_UID_RECORDS_SIZE; - while (overflow > 0 && records.size() > 0) { - auto del_it = records.begin(); + while (overflow > 0 && io_history.size() > 0) { + auto del_it = io_history.begin(); overflow -= del_it->second.entries.size(); - records.erase(records.begin()); + io_history.erase(io_history.begin()); } - records[curr_ts] = new_records; + io_history[curr_ts] = new_records; } std::map uid_monitor::dump( double hours, uint64_t threshold, bool force_report) { if (force_report) { - report(); + report(nullptr); } - std::unique_ptr lock(new lock_t(&um_lock)); + Mutex::Autolock _l(uidm_mutex); std::map dump_records; uint64_t first_ts = 0; @@ -200,19 +272,20 @@ std::map uid_monitor::dump( first_ts = time(NULL) - hours * HOUR_TO_SEC; } - for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) { + for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) { const std::vector& recs = it->second.entries; struct uid_records filtered; for (const auto& rec : recs) { - if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] + - rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] + - rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] + - rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] + - rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] + - rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] + - rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] + - rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) { + const io_usage& uid_usage = rec.ios.uid_ios; + if (uid_usage.bytes[READ][FOREGROUND][CHARGER_ON] + + uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF] + + uid_usage.bytes[READ][BACKGROUND][CHARGER_ON] + + uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF] + + uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON] + + uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF] + + uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON] + + uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) { filtered.entries.push_back(rec); } } @@ -230,20 +303,21 @@ std::map uid_monitor::dump( void uid_monitor::update_curr_io_stats_locked() { - std::unordered_map uid_io_stats = + std::unordered_map uid_io_stats = get_uid_io_stats_locked(); if (uid_io_stats.empty()) { return; } for (const auto& it : uid_io_stats) { - const struct uid_info& uid = it.second; - + const uid_info& uid = it.second; if (curr_io_stats.find(uid.name) == curr_io_stats.end()) { - curr_io_stats[uid.name] = {}; + curr_io_stats[uid.name] = {}; } struct uid_io_usage& usage = curr_io_stats[uid.name]; + usage.user_id = multiuser_get_user_id(uid.uid); + int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes - last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes; int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes - @@ -253,30 +327,177 @@ void uid_monitor::update_curr_io_stats_locked() int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes - last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes; - usage.bytes[READ][FOREGROUND][charger_stat] += + usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] += (fg_rd_delta < 0) ? 0 : fg_rd_delta; - usage.bytes[READ][BACKGROUND][charger_stat] += + usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] += (bg_rd_delta < 0) ? 0 : bg_rd_delta; - usage.bytes[WRITE][FOREGROUND][charger_stat] += + usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] += (fg_wr_delta < 0) ? 0 : fg_wr_delta; - usage.bytes[WRITE][BACKGROUND][charger_stat] += + usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] += (bg_wr_delta < 0) ? 0 : bg_wr_delta; + + for (const auto& task_it : uid.tasks) { + const task_info& task = task_it.second; + const pid_t pid = task_it.first; + const std::string& comm = task_it.second.comm; + int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes - + last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes; + int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes - + last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes; + int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes - + last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes; + int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes - + last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes; + + io_usage& task_usage = usage.task_ios[comm]; + task_usage.bytes[READ][FOREGROUND][charger_stat] += + (task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta; + task_usage.bytes[READ][BACKGROUND][charger_stat] += + (task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta; + task_usage.bytes[WRITE][FOREGROUND][charger_stat] += + (task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta; + task_usage.bytes[WRITE][BACKGROUND][charger_stat] += + (task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta; + } } last_uid_io_stats = uid_io_stats; } -void uid_monitor::report() +void uid_monitor::report(unordered_map* protos) { - std::unique_ptr lock(new lock_t(&um_lock)); + if (!enabled()) return; + + Mutex::Autolock _l(uidm_mutex); update_curr_io_stats_locked(); add_records_locked(time(NULL)); + + if (protos) { + update_uid_io_proto(protos); + } +} + +namespace { + +void set_io_usage_proto(IOUsage* usage_proto, const io_usage& usage) +{ + usage_proto->set_rd_fg_chg_on(usage.bytes[READ][FOREGROUND][CHARGER_ON]); + usage_proto->set_rd_fg_chg_off(usage.bytes[READ][FOREGROUND][CHARGER_OFF]); + usage_proto->set_rd_bg_chg_on(usage.bytes[READ][BACKGROUND][CHARGER_ON]); + usage_proto->set_rd_bg_chg_off(usage.bytes[READ][BACKGROUND][CHARGER_OFF]); + usage_proto->set_wr_fg_chg_on(usage.bytes[WRITE][FOREGROUND][CHARGER_ON]); + usage_proto->set_wr_fg_chg_off(usage.bytes[WRITE][FOREGROUND][CHARGER_OFF]); + usage_proto->set_wr_bg_chg_on(usage.bytes[WRITE][BACKGROUND][CHARGER_ON]); + usage_proto->set_wr_bg_chg_off(usage.bytes[WRITE][BACKGROUND][CHARGER_OFF]); +} + +void get_io_usage_proto(io_usage* usage, const IOUsage& io_proto) +{ + usage->bytes[READ][FOREGROUND][CHARGER_ON] = io_proto.rd_fg_chg_on(); + usage->bytes[READ][FOREGROUND][CHARGER_OFF] = io_proto.rd_fg_chg_off(); + usage->bytes[READ][BACKGROUND][CHARGER_ON] = io_proto.rd_bg_chg_on(); + usage->bytes[READ][BACKGROUND][CHARGER_OFF] = io_proto.rd_bg_chg_off(); + usage->bytes[WRITE][FOREGROUND][CHARGER_ON] = io_proto.wr_fg_chg_on(); + usage->bytes[WRITE][FOREGROUND][CHARGER_OFF] = io_proto.wr_fg_chg_off(); + usage->bytes[WRITE][BACKGROUND][CHARGER_ON] = io_proto.wr_bg_chg_on(); + usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off(); +} + +} // namespace + +void uid_monitor::update_uid_io_proto(unordered_map* protos) +{ + for (const auto& item : io_history) { + const uint64_t& end_ts = item.first; + const struct uid_records& recs = item.second; + unordered_map user_items; + + for (const auto& entry : recs.entries) { + userid_t user_id = entry.ios.user_id; + UidIOItem* item_proto = user_items[user_id]; + if (item_proto == nullptr) { + item_proto = (*protos)[user_id].mutable_uid_io_usage() + ->add_uid_io_items(); + user_items[user_id] = item_proto; + } + item_proto->set_end_ts(end_ts); + + UidIORecords* recs_proto = item_proto->mutable_records(); + recs_proto->set_start_ts(recs.start_ts); + + UidRecord* rec_proto = recs_proto->add_entries(); + rec_proto->set_uid_name(entry.name); + rec_proto->set_user_id(user_id); + + IOUsage* uid_io_proto = rec_proto->mutable_uid_io(); + const io_usage& uio_ios = entry.ios.uid_ios; + set_io_usage_proto(uid_io_proto, uio_ios); + + for (const auto& task_io : entry.ios.task_ios) { + const std::string& task_name = task_io.first; + const io_usage& task_ios = task_io.second; + + TaskIOUsage* task_io_proto = rec_proto->add_task_io(); + task_io_proto->set_task_name(task_name); + set_io_usage_proto(task_io_proto->mutable_ios(), task_ios); + } + } + } +} + +void uid_monitor::clear_user_history(userid_t user_id) +{ + Mutex::Autolock _l(uidm_mutex); + + for (auto& item : io_history) { + vector* entries = &item.second.entries; + entries->erase( + remove_if(entries->begin(), entries->end(), + [user_id](const uid_record& rec) { + return rec.ios.user_id == user_id;}), + entries->end()); + } + + for (auto it = io_history.begin(); it != io_history.end(); ) { + if (it->second.entries.empty()) { + it = io_history.erase(it); + } else { + it++; + } + } +} + +void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto) +{ + if (!enabled()) return; + + Mutex::Autolock _l(uidm_mutex); + + for (const auto& item_proto : uid_io_proto.uid_io_items()) { + const UidIORecords& records_proto = item_proto.records(); + struct uid_records* recs = &io_history[item_proto.end_ts()]; + + recs->start_ts = records_proto.start_ts(); + for (const auto& rec_proto : records_proto.entries()) { + struct uid_record record; + record.name = rec_proto.uid_name(); + record.ios.user_id = rec_proto.user_id(); + get_io_usage_proto(&record.ios.uid_ios, rec_proto.uid_io()); + + for (const auto& task_io_proto : rec_proto.task_io()) { + get_io_usage_proto( + &record.ios.task_ios[task_io_proto.task_name()], + task_io_proto.ios()); + } + recs->entries.push_back(record); + } + } } void uid_monitor::set_charger_state(charger_stat_t stat) { - std::unique_ptr lock(new lock_t(&um_lock)); + Mutex::Autolock _l(uidm_mutex); if (charger_stat == stat) { return; @@ -289,16 +510,11 @@ void uid_monitor::set_charger_state(charger_stat_t stat) void uid_monitor::init(charger_stat_t stat) { charger_stat = stat; + start_ts = time(NULL); last_uid_io_stats = get_uid_io_stats(); } uid_monitor::uid_monitor() -{ - sem_init(&um_lock, 0, 1); -} - -uid_monitor::~uid_monitor() -{ - sem_destroy(&um_lock); + : enable(!access(UID_IO_STATS_PATH, R_OK)) { } diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp index 74b743656..4fd4bc9dc 100644 --- a/storaged/storaged_utils.cpp +++ b/storaged/storaged_utils.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -41,124 +42,7 @@ #include #include -bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) { - // Get time - struct timespec ts; - // Use monotonic to exclude suspend time so that we measure IO bytes/sec - // when system is running. - int ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (ret < 0) { - PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; - return false; - } - - std::string buffer; - if (!android::base::ReadFileToString(disk_stats_path, &buffer)) { - PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed."; - return false; - } - - // Regular diskstats entries - std::stringstream ss(buffer); - for (uint i = 0; i < DISK_STATS_SIZE; ++i) { - ss >> *((uint64_t*)stats + i); - } - // Other entries - stats->start_time = 0; - stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC + - ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC); - stats->counter = 1; - stats->io_avg = (double)stats->io_in_flight; - return true; -} - -struct disk_perf get_disk_perf(struct disk_stats* stats) { - struct disk_perf perf; - memset(&perf, 0, sizeof(struct disk_perf)); // initialize - - if (stats->io_ticks) { - if (stats->read_ticks) { - unsigned long long divisor = stats->read_ticks * stats->io_ticks; - perf.read_perf = ((unsigned long long)SECTOR_SIZE * - stats->read_sectors * - stats->io_in_queue + - (divisor >> 1)) / - divisor; - perf.read_ios = ((unsigned long long)SEC_TO_MSEC * - stats->read_ios * - stats->io_in_queue + - (divisor >> 1)) / - divisor; - } - if (stats->write_ticks) { - unsigned long long divisor = stats->write_ticks * stats->io_ticks; - perf.write_perf = ((unsigned long long)SECTOR_SIZE * - stats->write_sectors * - stats->io_in_queue + - (divisor >> 1)) / - divisor; - perf.write_ios = ((unsigned long long)SEC_TO_MSEC * - stats->write_ios * - stats->io_in_queue + - (divisor >> 1)) / - divisor; - } - perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) / - stats->io_ticks; - } - return perf; -} - -struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) { - struct disk_stats inc; - for (uint i = 0; i < DISK_STATS_SIZE; ++i) { - if (i == DISK_STATS_IO_IN_FLIGHT_IDX) { - continue; - } - - *((uint64_t*)&inc + i) = - *((uint64_t*)curr + i) - *((uint64_t*)prev + i); - } - // io_in_flight is exception - inc.io_in_flight = curr->io_in_flight; - - inc.start_time = prev->end_time; - inc.end_time = curr->end_time; - inc.io_avg = curr->io_avg; - inc.counter = 1; - - return inc; -} - -// Add src to dst -void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) { - if (dst->end_time != 0 && dst->end_time != src->start_time) { - LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats" - << " are added. dst end with " << dst->end_time - << ", src start with " << src->start_time; - } - - for (uint i = 0; i < DISK_STATS_SIZE; ++i) { - if (i == DISK_STATS_IO_IN_FLIGHT_IDX) { - continue; - } - - *((uint64_t*)dst + i) += *((uint64_t*)src + i); - } - - dst->io_in_flight = src->io_in_flight; - if (dst->counter + src->counter) { - dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) / - (dst->counter + src->counter); - } - dst->counter += src->counter; - dst->end_time = src->end_time; - if (dst->start_time == 0) { - dst->start_time = src->start_time; - } -} - -static bool cmp_uid_info(struct uid_info l, struct uid_info r) { +bool cmp_uid_info(const UidInfo& l, const UidInfo& r) { // Compare background I/O first. for (int i = UID_STATS - 1; i >= 0; i--) { uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes; @@ -177,56 +61,72 @@ static bool cmp_uid_info(struct uid_info l, struct uid_info r) { return l.name < r.name; } -void sort_running_uids_info(std::vector &uids) { +void sort_running_uids_info(std::vector &uids) { std::sort(uids.begin(), uids.end(), cmp_uid_info); } // Logging functions -void log_console_running_uids_info(std::vector uids) { +void log_console_running_uids_info(const std::vector& uids, bool flag_dump_task) { printf("name/uid fg_rchar fg_wchar fg_rbytes fg_wbytes " "bg_rchar bg_wchar bg_rbytes bg_wbytes fg_fsync bg_fsync\n"); for (const auto& uid : uids) { - printf("%s %ju %ju %ju %ju %ju %ju %ju %ju %ju %ju\n", uid.name.c_str(), + printf("%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + uid.name.c_str(), uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes, uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes, uid.io[0].fsync, uid.io[1].fsync); + if (flag_dump_task) { + for (const auto& task_it : uid.tasks) { + const task_info& task = task_it.second; + printf("-> %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 + " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + task.comm.c_str(), + task.io[0].rchar, task.io[0].wchar, task.io[0].read_bytes, task.io[0].write_bytes, + task.io[1].rchar, task.io[1].wchar, task.io[1].read_bytes, task.io[1].write_bytes, + task.io[0].fsync, task.io[1].fsync); + } + } } fflush(stdout); } -#if DEBUG -void log_debug_disk_perf(struct disk_perf* perf, const char* type) { - // skip if the input structure are all zeros - if (perf == NULL) return; - struct disk_perf zero_cmp; - memset(&zero_cmp, 0, sizeof(zero_cmp)); - if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return; +void log_console_perf_history(const vector& perf_history) { + if (perf_history.size() < 3 || + perf_history.size() != perf_history[0] + + perf_history[1] + + perf_history[2] + (size_t)3) { + return; + } - LOG_TO(SYSTEM, INFO) << "perf(ios) " << type - << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)" - << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)" - << " q:" << perf->queue; -} -#else -void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {} -#endif + printf("\nI/O perf history (KB/s) : most_recent <--------- least_recent \n"); -void log_event_disk_stats(struct disk_stats* stats, const char* type) { - // skip if the input structure are all zeros - if (stats == NULL) return; - struct disk_stats zero_cmp; - memset(&zero_cmp, 0, sizeof(zero_cmp)); - // skip event logging diskstats when it is zero increment (all first 11 entries are zero) - if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return; + std::stringstream line; + int start = 3; + int end = 3 + perf_history[0]; + std::copy(perf_history.begin() + start, perf_history.begin() + end, + std::ostream_iterator(line, " ")); + printf("last 24 hours : %s\n", line.str().c_str()); - android_log_event_list(EVENTLOGTAG_DISKSTATS) - << type << stats->start_time << stats->end_time - << stats->read_ios << stats->read_merges - << stats->read_sectors << stats->read_ticks - << stats->write_ios << stats->write_merges - << stats->write_sectors << stats->write_ticks - << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue - << LOG_ID_EVENTS; + line.str(""); + start = end; + end += perf_history[1]; + std::copy(perf_history.begin() + start, perf_history.begin() + end, + std::ostream_iterator(line, " ")); + printf("last 7 days : %s\n", line.str().c_str()); + + line.str(""); + start = end; + std::copy(perf_history.begin() + start, perf_history.end(), + std::ostream_iterator(line, " ")); + printf("last 52 weeks : %s\n", line.str().c_str()); } +map merge_io_usage(const vector& entries) { + map merged_entries; + for (const auto& record : entries) { + merged_entries[record.name] += record.ios.uid_ios; + } + return merged_entries; +} diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk deleted file mode 100644 index 26d04b162..000000000 --- a/storaged/tests/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH := $(call my-dir) - -test_module_prefix := storaged- -test_tags := tests - -# ----------------------------------------------------------------------------- -# Unit tests. -# ----------------------------------------------------------------------------- - -test_c_flags := \ - -fstack-protector-all \ - -g \ - -Wall -Wextra \ - -Werror \ - -fno-builtin \ - -test_src_files := \ - storaged_test.cpp \ - -# Build tests for the logger. Run with: -# adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests -include $(CLEAR_VARS) -LOCAL_MODULE := $(test_module_prefix)unit-tests -LOCAL_MODULE_TAGS := $(test_tags) -LOCAL_CFLAGS += $(test_c_flags) -LOCAL_STATIC_LIBRARIES := libstoraged -LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libpackagelistparser -LOCAL_SRC_FILES := $(test_src_files) -include $(BUILD_NATIVE_TEST) diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index b103ac1ec..ec47b65ee 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -24,13 +25,20 @@ #include +#include #include // data structures #include // functions to test #define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" #define SDA_DISK_STATS_PATH "/sys/block/sda/stat" -static void pause(uint32_t sec) { +using namespace std; +using namespace chrono; +using namespace storaged_proto; + +namespace { + +void write_and_pause(uint32_t sec) { const char* path = "/cache/test"; int fd = open(path, O_WRONLY | O_CREAT, 0600); ASSERT_LT(-1, fd); @@ -53,6 +61,8 @@ static void pause(uint32_t sec) { sleep(sec); } +} // namespace + // the return values of the tested functions should be the expected ones const char* DISK_STATS_PATH; TEST(storaged_test, retvals) { @@ -77,13 +87,11 @@ TEST(storaged_test, retvals) { EXPECT_FALSE(parse_disk_stats(wrong_path, &stats)); // reading a wrong path should not damage the output structure - EXPECT_EQ(0, memcmp(&stats, &old_stats, sizeof(disk_stats))); + EXPECT_EQ(stats, old_stats); } TEST(storaged_test, disk_stats) { - struct disk_stats stats; - memset(&stats, 0, sizeof(struct disk_stats)); - + struct disk_stats stats = {}; ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats)); // every entry of stats (except io_in_flight) should all be greater than 0 @@ -93,11 +101,7 @@ TEST(storaged_test, disk_stats) { } // accumulation of the increments should be the same with the overall increment - struct disk_stats base, tmp, curr, acc, inc[5]; - memset(&base, 0, sizeof(struct disk_stats)); - memset(&tmp, 0, sizeof(struct disk_stats)); - memset(&acc, 0, sizeof(struct disk_stats)); - + struct disk_stats base = {}, tmp = {}, curr, acc = {}, inc[5]; for (uint i = 0; i < 5; ++i) { ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr)); if (i == 0) { @@ -106,22 +110,18 @@ TEST(storaged_test, disk_stats) { sleep(5); continue; } - inc[i] = get_inc_disk_stats(&tmp, &curr); + get_inc_disk_stats(&tmp, &curr, &inc[i]); add_disk_stats(&inc[i], &acc); tmp = curr; - pause(5); + write_and_pause(5); } - struct disk_stats overall_inc; - memset(&overall_inc, 0, sizeof(disk_stats)); - overall_inc= get_inc_disk_stats(&base, &curr); + struct disk_stats overall_inc = {}; + get_inc_disk_stats(&base, &curr, &overall_inc); - for (uint i = 0; i < DISK_STATS_SIZE; ++i) { - if (i == 8) continue; // skip io_in_flight which can be 0 - EXPECT_EQ(*((uint64_t*)&overall_inc + i), *((uint64_t*)&acc + i)); - } + EXPECT_EQ(overall_inc, acc); } -static double mean(std::deque nums) { +double mean(std::deque nums) { double sum = 0.0; for (uint32_t i : nums) { sum += i; @@ -129,7 +129,7 @@ static double mean(std::deque nums) { return sum / nums.size(); } -static double standard_deviation(std::deque nums) { +double standard_deviation(std::deque nums) { double sum = 0.0; double avg = mean(nums); for (uint32_t i : nums) { @@ -181,7 +181,7 @@ TEST(storaged_test, stream_stats) { } } -static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) { +struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) { struct disk_perf retval; retval.read_perf = (double)perf.read_perf * mul; retval.read_ios = (double)perf.read_ios * mul; @@ -192,7 +192,7 @@ static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) { return retval; } -static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) { +struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) { struct disk_stats retval; retval.read_ios = stats1.read_ios + stats2.read_ios; retval.read_merges = stats1.read_merges + stats2.read_merges; @@ -210,11 +210,42 @@ static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_st return retval; } +void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) { + EXPECT_LE(stats1.read_ios, stats2.read_ios); + EXPECT_LE(stats1.read_merges, stats2.read_merges); + EXPECT_LE(stats1.read_sectors, stats2.read_sectors); + EXPECT_LE(stats1.read_ticks, stats2.read_ticks); + EXPECT_LE(stats1.write_ios, stats2.write_ios); + EXPECT_LE(stats1.write_merges, stats2.write_merges); + EXPECT_LE(stats1.write_sectors, stats2.write_sectors); + EXPECT_LE(stats1.write_ticks, stats2.write_ticks); + EXPECT_LE(stats1.io_ticks, stats2.io_ticks); + EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue); + + EXPECT_TRUE(stats1.read_ios < stats2.read_ios || + stats1.read_merges < stats2.read_merges || + stats1.read_sectors < stats2.read_sectors || + stats1.read_ticks < stats2.read_ticks || + stats1.write_ios < stats2.write_ios || + stats1.write_merges < stats2.write_merges || + stats1.write_sectors < stats2.write_sectors || + stats1.write_ticks < stats2.write_ticks || + stats1.io_ticks < stats2.io_ticks || + stats1.io_in_queue < stats2.io_in_queue); +} + TEST(storaged_test, disk_stats_monitor) { + using android::hardware::health::V2_0::get_health_service; + + auto healthService = get_health_service(); + // asserting that there is one file for diskstats - ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0); + ASSERT_TRUE(healthService != nullptr || access(MMC_DISK_STATS_PATH, R_OK) >= 0 || + access(SDA_DISK_STATS_PATH, R_OK) >= 0); + // testing if detect() will return the right value - disk_stats_monitor dsm_detect; + disk_stats_monitor dsm_detect{healthService}; + ASSERT_TRUE(dsm_detect.enabled()); // feed monitor with constant perf data for io perf baseline // using constant perf is reasonable since the functionality of stream_stats // has already been tested @@ -257,7 +288,7 @@ TEST(storaged_test, disk_stats_monitor) { } // testing if stalled disk_stats can be correctly accumulated in the monitor - disk_stats_monitor dsm_acc; + disk_stats_monitor dsm_acc{healthService}; struct disk_stats norm_inc = { .read_ios = 200, .read_merges = 0, @@ -294,14 +325,12 @@ TEST(storaged_test, disk_stats_monitor) { .io_avg = 0 }; - struct disk_stats stats_base; - memset(&stats_base, 0, sizeof(stats_base)); - + struct disk_stats stats_base = {}; int loop_size = 100; for (int i = 0; i < loop_size; ++i) { stats_base = disk_stats_add(stats_base, norm_inc); dsm_acc.update(&stats_base); - EXPECT_EQ(dsm_acc.mValid, (uint32_t)(i + 1) >= dsm_acc.mWindow); + EXPECT_EQ(dsm_acc.mValid, (uint32_t)i >= dsm_acc.mWindow); EXPECT_FALSE(dsm_acc.mStall); } @@ -316,36 +345,284 @@ TEST(storaged_test, disk_stats_monitor) { EXPECT_TRUE(dsm_acc.mValid); EXPECT_FALSE(dsm_acc.mStall); } -} -static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) { - EXPECT_LE(stats1.read_ios, stats2.read_ios); - EXPECT_LE(stats1.read_merges, stats2.read_merges); - EXPECT_LE(stats1.read_sectors, stats2.read_sectors); - EXPECT_LE(stats1.read_ticks, stats2.read_ticks); - - EXPECT_LE(stats1.write_ios, stats2.write_ios); - EXPECT_LE(stats1.write_merges, stats2.write_merges); - EXPECT_LE(stats1.write_sectors, stats2.write_sectors); - EXPECT_LE(stats1.write_ticks, stats2.write_ticks); - - EXPECT_LE(stats1.io_ticks, stats2.io_ticks); - EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue); -} - -#define TEST_LOOPS 20 -TEST(storaged_test, disk_stats_publisher) { - // asserting that there is one file for diskstats - ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0); - disk_stats_publisher dsp; - struct disk_stats prev; - memset(&prev, 0, sizeof(prev)); - - for (int i = 0; i < TEST_LOOPS; ++i) { - dsp.update(); - expect_increasing(prev, dsp.mPrevious); - prev = dsp.mPrevious; - pause(10); + struct disk_stats stats_prev = {}; + loop_size = 10; + write_and_pause(5); + for (int i = 0; i < loop_size; ++i) { + dsm_detect.update(); + expect_increasing(stats_prev, dsm_detect.mPrevious); + stats_prev = dsm_detect.mPrevious; + write_and_pause(5); } } +TEST(storaged_test, storage_info_t) { + storage_info_t si; + time_point tp; + time_point stp; + + // generate perf history [least_recent ------> most recent] + // day 1: 5, 10, 15, 20 | daily average 12 + // day 2: 25, 30, 35, 40, 45 | daily average 35 + // day 3: 50, 55, 60, 65, 70 | daily average 60 + // day 4: 75, 80, 85, 90, 95 | daily average 85 + // day 5: 100, 105, 110, 115, | daily average 107 + // day 6: 120, 125, 130, 135, 140 | daily average 130 + // day 7: 145, 150, 155, 160, 165 | daily average 155 + // end of week 1: | weekly average 83 + // day 1: 170, 175, 180, 185, 190 | daily average 180 + // day 2: 195, 200, 205, 210, 215 | daily average 205 + // day 3: 220, 225, 230, 235 | daily average 227 + // day 4: 240, 245, 250, 255, 260 | daily average 250 + // day 5: 265, 270, 275, 280, 285 | daily average 275 + // day 6: 290, 295, 300, 305, 310 | daily average 300 + // day 7: 315, 320, 325, 330, 335 | daily average 325 + // end of week 2: | weekly average 251 + // day 1: 340, 345, 350, 355 | daily average 347 + // day 2: 360, 365, 370, 375 + si.day_start_tp = {}; + for (int i = 0; i < 75; i++) { + tp += hours(5); + stp = {}; + stp += duration_cast(tp.time_since_epoch()); + si.update_perf_history((i + 1) * 5, stp); + } + + vector history = si.get_perf_history(); + EXPECT_EQ(history.size(), 66UL); + size_t i = 0; + EXPECT_EQ(history[i++], 4); + EXPECT_EQ(history[i++], 7); // 7 days + EXPECT_EQ(history[i++], 52); // 52 weeks + // last 24 hours + EXPECT_EQ(history[i++], 375); + EXPECT_EQ(history[i++], 370); + EXPECT_EQ(history[i++], 365); + EXPECT_EQ(history[i++], 360); + // daily average of last 7 days + EXPECT_EQ(history[i++], 347); + EXPECT_EQ(history[i++], 325); + EXPECT_EQ(history[i++], 300); + EXPECT_EQ(history[i++], 275); + EXPECT_EQ(history[i++], 250); + EXPECT_EQ(history[i++], 227); + EXPECT_EQ(history[i++], 205); + // weekly average of last 52 weeks + EXPECT_EQ(history[i++], 251); + EXPECT_EQ(history[i++], 83); + for (; i < history.size(); i++) { + EXPECT_EQ(history[i], 0); + } +} + +TEST(storaged_test, storage_info_t_proto) { + storage_info_t si; + si.day_start_tp = {}; + + IOPerfHistory proto; + proto.set_nr_samples(10); + proto.set_day_start_sec(0); + si.load_perf_history_proto(proto); + + // Skip ahead > 1 day, with no data points in the previous day. + time_point stp; + stp += hours(36); + si.update_perf_history(100, stp); + + vector history = si.get_perf_history(); + EXPECT_EQ(history.size(), 63UL); + EXPECT_EQ(history[0], 1); + EXPECT_EQ(history[1], 7); + EXPECT_EQ(history[2], 52); + EXPECT_EQ(history[3], 100); + for (size_t i = 4; i < history.size(); i++) { + EXPECT_EQ(history[i], 0); + } +} + +TEST(storaged_test, uid_monitor) { + uid_monitor uidm; + + uidm.io_history[200] = { + .start_ts = 100, + .entries = { + { "app1", { + .user_id = 0, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000, + } + }, + { "app2", { + .user_id = 0, + .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 1000, + } + }, + { "app1", { + .user_id = 1, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000, + .uid_ios.bytes[READ][FOREGROUND][CHARGER_ON] = 1000, + } + }, + }, + }; + + uidm.io_history[300] = { + .start_ts = 200, + .entries = { + { "app1", { + .user_id = 1, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] = 1000, + } + }, + { "app3", { + .user_id = 0, + .uid_ios.bytes[READ][BACKGROUND][CHARGER_OFF] = 1000, + } + }, + }, + }; + + unordered_map protos; + + uidm.update_uid_io_proto(&protos); + + EXPECT_EQ(protos.size(), 2U); + EXPECT_EQ(protos.count(0), 1UL); + EXPECT_EQ(protos.count(1), 1UL); + + EXPECT_EQ(protos[0].uid_io_usage().uid_io_items_size(), 2); + const UidIOItem& user_0_item_0 = protos[0].uid_io_usage().uid_io_items(0); + EXPECT_EQ(user_0_item_0.end_ts(), 200UL); + EXPECT_EQ(user_0_item_0.records().start_ts(), 100UL); + EXPECT_EQ(user_0_item_0.records().entries_size(), 2); + EXPECT_EQ(user_0_item_0.records().entries(0).uid_name(), "app1"); + EXPECT_EQ(user_0_item_0.records().entries(0).user_id(), 0UL); + EXPECT_EQ(user_0_item_0.records().entries(0).uid_io().wr_fg_chg_on(), 1000UL); + EXPECT_EQ(user_0_item_0.records().entries(1).uid_name(), "app2"); + EXPECT_EQ(user_0_item_0.records().entries(1).user_id(), 0UL); + EXPECT_EQ(user_0_item_0.records().entries(1).uid_io().rd_fg_chg_off(), 1000UL); + const UidIOItem& user_0_item_1 = protos[0].uid_io_usage().uid_io_items(1); + EXPECT_EQ(user_0_item_1.end_ts(), 300UL); + EXPECT_EQ(user_0_item_1.records().start_ts(), 200UL); + EXPECT_EQ(user_0_item_1.records().entries_size(), 1); + EXPECT_EQ(user_0_item_1.records().entries(0).uid_name(), "app3"); + EXPECT_EQ(user_0_item_1.records().entries(0).user_id(), 0UL); + EXPECT_EQ(user_0_item_1.records().entries(0).uid_io().rd_bg_chg_off(), 1000UL); + + EXPECT_EQ(protos[1].uid_io_usage().uid_io_items_size(), 2); + const UidIOItem& user_1_item_0 = protos[1].uid_io_usage().uid_io_items(0); + EXPECT_EQ(user_1_item_0.end_ts(), 200UL); + EXPECT_EQ(user_1_item_0.records().start_ts(), 100UL); + EXPECT_EQ(user_1_item_0.records().entries_size(), 1); + EXPECT_EQ(user_1_item_0.records().entries(0).uid_name(), "app1"); + EXPECT_EQ(user_1_item_0.records().entries(0).user_id(), 1UL); + EXPECT_EQ(user_1_item_0.records().entries(0).uid_io().rd_fg_chg_on(), 1000UL); + EXPECT_EQ(user_1_item_0.records().entries(0).uid_io().wr_fg_chg_on(), 1000UL); + const UidIOItem& user_1_item_1 = protos[1].uid_io_usage().uid_io_items(1); + EXPECT_EQ(user_1_item_1.end_ts(), 300UL); + EXPECT_EQ(user_1_item_1.records().start_ts(), 200UL); + EXPECT_EQ(user_1_item_1.records().entries_size(), 1); + EXPECT_EQ(user_1_item_1.records().entries(0).uid_name(), "app1"); + EXPECT_EQ(user_1_item_1.records().entries(0).user_id(), 1UL); + EXPECT_EQ(user_1_item_1.records().entries(0).uid_io().wr_fg_chg_off(), 1000UL); + + uidm.io_history.clear(); + + uidm.io_history[300] = { + .start_ts = 200, + .entries = { + { "app1", { + .user_id = 0, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000, + } + }, + }, + }; + + uidm.io_history[400] = { + .start_ts = 300, + .entries = { + { "app1", { + .user_id = 0, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000, + } + }, + }, + }; + + uidm.load_uid_io_proto(protos[0].uid_io_usage()); + uidm.load_uid_io_proto(protos[1].uid_io_usage()); + + EXPECT_EQ(uidm.io_history.size(), 3UL); + EXPECT_EQ(uidm.io_history.count(200), 1UL); + EXPECT_EQ(uidm.io_history.count(300), 1UL); + EXPECT_EQ(uidm.io_history.count(400), 1UL); + + EXPECT_EQ(uidm.io_history[200].start_ts, 100UL); + const vector& entries_0 = uidm.io_history[200].entries; + EXPECT_EQ(entries_0.size(), 3UL); + EXPECT_EQ(entries_0[0].name, "app1"); + EXPECT_EQ(entries_0[0].ios.user_id, 0UL); + EXPECT_EQ(entries_0[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + EXPECT_EQ(entries_0[1].name, "app2"); + EXPECT_EQ(entries_0[1].ios.user_id, 0UL); + EXPECT_EQ(entries_0[1].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF], 1000UL); + EXPECT_EQ(entries_0[2].name, "app1"); + EXPECT_EQ(entries_0[2].ios.user_id, 1UL); + EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_ON], 1000UL); + + EXPECT_EQ(uidm.io_history[300].start_ts, 200UL); + const vector& entries_1 = uidm.io_history[300].entries; + EXPECT_EQ(entries_1.size(), 3UL); + EXPECT_EQ(entries_1[0].name, "app1"); + EXPECT_EQ(entries_1[0].ios.user_id, 0UL); + EXPECT_EQ(entries_1[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + EXPECT_EQ(entries_1[1].name, "app3"); + EXPECT_EQ(entries_1[1].ios.user_id, 0UL); + EXPECT_EQ(entries_1[1].ios.uid_ios.bytes[READ][BACKGROUND][CHARGER_OFF], 1000UL); + EXPECT_EQ(entries_1[2].name, "app1"); + EXPECT_EQ(entries_1[2].ios.user_id, 1UL); + EXPECT_EQ(entries_1[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL); + + EXPECT_EQ(uidm.io_history[400].start_ts, 300UL); + const vector& entries_2 = uidm.io_history[400].entries; + EXPECT_EQ(entries_2.size(), 1UL); + EXPECT_EQ(entries_2[0].name, "app1"); + EXPECT_EQ(entries_2[0].ios.user_id, 0UL); + EXPECT_EQ(entries_2[0].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + + map merged_entries_0 = merge_io_usage(entries_0); + EXPECT_EQ(merged_entries_0.size(), 2UL); + EXPECT_EQ(merged_entries_0.count("app1"), 1UL); + EXPECT_EQ(merged_entries_0.count("app2"), 1UL); + EXPECT_EQ(merged_entries_0["app1"].bytes[READ][FOREGROUND][CHARGER_ON], 1000UL); + EXPECT_EQ(merged_entries_0["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 2000UL); + EXPECT_EQ(merged_entries_0["app2"].bytes[READ][FOREGROUND][CHARGER_OFF], 1000UL); + + map merged_entries_1 = merge_io_usage(entries_1); + EXPECT_EQ(merged_entries_1.size(), 2UL); + EXPECT_EQ(merged_entries_1.count("app1"), 1UL); + EXPECT_EQ(merged_entries_1.count("app3"), 1UL); + EXPECT_EQ(merged_entries_1["app1"].bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL); + EXPECT_EQ(merged_entries_1["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + EXPECT_EQ(merged_entries_1["app3"].bytes[READ][BACKGROUND][CHARGER_OFF], 1000UL); + + map merged_entries_2 = merge_io_usage(entries_2); + EXPECT_EQ(merged_entries_2.size(), 1UL); + EXPECT_EQ(merged_entries_2.count("app1"), 1UL); + EXPECT_EQ(merged_entries_2["app1"].bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); + + uidm.clear_user_history(0); + + EXPECT_EQ(uidm.io_history.size(), 2UL); + EXPECT_EQ(uidm.io_history.count(200), 1UL); + EXPECT_EQ(uidm.io_history.count(300), 1UL); + + EXPECT_EQ(uidm.io_history[200].entries.size(), 1UL); + EXPECT_EQ(uidm.io_history[300].entries.size(), 1UL); + + uidm.clear_user_history(1); + + EXPECT_EQ(uidm.io_history.size(), 0UL); +} diff --git a/storaged/tools/ranker.py b/storaged/tools/ranker.py new file mode 100644 index 000000000..d8096b705 --- /dev/null +++ b/storaged/tools/ranker.py @@ -0,0 +1,181 @@ +# Copyright 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Parser and ranker for dumpsys storaged output. + +This module parses output from dumpsys storaged by ranking uids based on +their io usage measured in 8 different stats. It must be provided the input +file through command line argument -i/--input. + +For more details, see: + $ python ranker.py -h + +Example: + $ python ranker.py -i io.txt -o output.txt -u 20 -cnt +""" + +import argparse +import sys + +IO_NAMES = ["[READ][FOREGROUND][CHARGER_OFF]", + "[WRITE][FOREGROUND][CHARGER_OFF]", + "[READ][BACKGROUND][CHARGER_OFF]", + "[WRITE][BACKGROUND][CHARGER_OFF]", + "[READ][FOREGROUND][CHARGER_ON]", + "[WRITE][FOREGROUND][CHARGER_ON]", + "[READ][BACKGROUND][CHARGER_ON]", + "[WRITE][BACKGROUND][CHARGER_ON]"] + + +def get_args(): + """Get arguments from command line. + + The only required argument is input file. + + Returns: + Args containing cmdline arguments + """ + + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--input", dest="input", required="true", + help="input io FILE, must provide", metavar="FILE") + parser.add_argument("-o", "--output", dest="output", default="stdout", + help="output FILE, default to stdout", metavar="FILE") + parser.add_argument("-u", "--uidcnt", dest="uidcnt", type=int, default=10, + help="set number of uids to display for each rank, " + "default 10") + parser.add_argument("-c", "--combine", dest="combine", default=False, + action="store_true", help="add io stats for same uids, " + "default to take io stats of last appearing uids") + parser.add_argument("-n", "--native", dest="native", default=False, + action="store_true", help="only include native apps in " + "ranking, default to include all apps") + parser.add_argument("-t", "--task", dest="task", default=False, + action="store_true", help="display task io under uids, " + "default to not display tasks") + return parser.parse_args() + + +def is_number(word): + try: + int(word) + return True + except ValueError: + return False + + +def combine_or_filter(args): + """Parser for io input. + + Either args.combine io stats for the same uids + or take the io stats for the last uid and ignore + the same uids before it. + + If task is required, store task ios along with uid + for later display. + + Returns: + The structure for the return value uids is as follows: + uids: {uid -> [UID_STATS, TASK_STATS(optional)]} + UID_STATS: [io1, io2, ..., io8] + TASK_STATS: {task_name -> [io1, io2, ..., io8]} + """ + fin = open(args.input, "r") + uids = {} + cur_uid = 0 + task_enabled = args.task + for line in fin: + words = line.split() + if words[0] == "->": + # task io + if not task_enabled: + continue + # get task command line + i = len(words) - 8 + task = " ".join(words[1:i]) + if task in uids[cur_uid][1]: + task_io = uids[cur_uid][1][task] + for j in range(8): + task_io[j] += long(words[i+j]) + else: + task_io = [] + for j in range(8): + task_io.append(long(words[i+j])) + uids[cur_uid][1][task] = task_io + + elif len(words) > 8: + if not is_number(words[0]) and args.native: + # uid not requested, ignore its tasks as well + task_enabled = False + continue + task_enabled = args.task + i = len(words) - 8 + uid = " ".join(words[:i]) + if uid in uids and args.combine: + uid_io = uids[uid][0] + for j in range(8): + uid_io[j] += long(words[i+j]) + uids[uid][0] = uid_io + else: + uid_io = [long(words[i+j]) for j in range(8)] + uids[uid] = [uid_io] + if task_enabled: + uids[uid].append({}) + cur_uid = uid + + return uids + + +def rank_uids(uids): + """Sort uids based on eight different io stats. + + Returns: + uid_rank is a 2d list of tuples: + The first dimension represent the 8 different io stats. + The second dimension is a sorted list of tuples by tup[0], + each tuple is a uid's perticular stat at the first dimension and the uid. + """ + uid_rank = [[(uids[uid][0][i], uid) for uid in uids] for i in range(8)] + for i in range(8): + uid_rank[i].sort(key=lambda tup: tup[0], reverse=True) + return uid_rank + + +def display_uids(uid_rank, uids, args): + """Display ranked uid io, along with task io if specified.""" + fout = sys.stdout + if args.output != "stdout": + fout = open(args.output, "w") + + for i in range(8): + fout.write("RANKING BY " + IO_NAMES[i] + "\n") + for j in range(min(args.uidcnt, len(uid_rank[0]))): + uid = uid_rank[i][j][1] + uid_stat = " ".join([str(uid_io) for uid_io in uids[uid][0]]) + fout.write(uid + " " + uid_stat + "\n") + if args.task: + for task in uids[uid][1]: + task_stat = " ".join([str(task_io) for task_io in uids[uid][1][task]]) + fout.write("-> " + task + " " + task_stat + "\n") + fout.write("\n") + + +def main(): + args = get_args() + uids = combine_or_filter(args) + uid_rank = rank_uids(uids) + display_uids(uid_rank, uids, args) + +if __name__ == "__main__": + main() diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp new file mode 100644 index 000000000..58e3fd282 --- /dev/null +++ b/storaged/uid_info.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "uid_info.h" + +using namespace android; +using namespace android::os::storaged; + +status_t UidInfo::writeToParcel(Parcel* parcel) const { + parcel->writeInt32(uid); + parcel->writeCString(name.c_str()); + parcel->write(&io, sizeof(io)); + + parcel->writeInt32(tasks.size()); + for (const auto& task_it : tasks) { + parcel->writeInt32(task_it.first); + parcel->writeCString(task_it.second.comm.c_str()); + parcel->write(&task_it.second.io, sizeof(task_it.second.io)); + } + return NO_ERROR; +} + +status_t UidInfo::readFromParcel(const Parcel* parcel) { + uid = parcel->readInt32(); + name = parcel->readCString(); + parcel->read(&io, sizeof(io)); + + uint32_t tasks_size = parcel->readInt32(); + for (uint32_t i = 0; i < tasks_size; i++) { + task_info task; + task.pid = parcel->readInt32(); + task.comm = parcel->readCString(); + parcel->read(&task.io, sizeof(task.io)); + tasks[task.pid] = task; + } + return NO_ERROR; +} diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index 5428e733e..899f8a309 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -39,7 +39,6 @@ cc_binary { "libcrypto", "libcutils", "libkeymaster_portable", - "libkeymaster_staging", "libtrusty", "libkeymaster_messages", "libsoftkeymasterdevice",