Merge "[TeX] Introduced Telemetry Express Histogram metric Native API"
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 9512e7e..6d50fa4 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -283,15 +283,17 @@
 
     srcs: [
         "bootimg_utils.cpp",
+        "fastboot_driver.cpp",
         "fastboot.cpp",
+        "filesystem.cpp",
         "fs.cpp",
         "socket.cpp",
+        "storage.cpp",
         "super_flash_helper.cpp",
         "tcp.cpp",
         "udp.cpp",
         "util.cpp",
         "vendor_boot_img_utils.cpp",
-        "fastboot_driver.cpp",
     ],
 
     // Only version the final binaries
@@ -391,6 +393,8 @@
             enabled: false,
         },
     },
+
+    test_suites: ["general-tests"],
 }
 
 cc_test_host {
diff --git a/fastboot/TEST_MAPPING b/fastboot/TEST_MAPPING
new file mode 100644
index 0000000..10f3d82
--- /dev/null
+++ b/fastboot/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "fastboot_test"
+    }
+  ]
+}
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 5afeb4f..6b6a982 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -70,11 +70,14 @@
     using HidlFastboot = android::hardware::fastboot::V1_1::IFastboot;
     using aidl::android::hardware::fastboot::FastbootShim;
     auto service_name = IFastboot::descriptor + "/default"s;
-    ndk::SpAIBinder binder(AServiceManager_getService(service_name.c_str()));
-    std::shared_ptr<IFastboot> fastboot = IFastboot::fromBinder(binder);
-    if (fastboot != nullptr) {
-        LOG(INFO) << "Using AIDL fastboot service";
-        return fastboot;
+    if (AServiceManager_isDeclared(service_name.c_str())) {
+        ndk::SpAIBinder binder(AServiceManager_waitForService(service_name.c_str()));
+        std::shared_ptr<IFastboot> fastboot = IFastboot::fromBinder(binder);
+        if (fastboot != nullptr) {
+            LOG(INFO) << "Found and using AIDL fastboot service";
+            return fastboot;
+        }
+        LOG(WARNING) << "AIDL fastboot service is declared, but it cannot be retrieved.";
     }
     LOG(INFO) << "Unable to get AIDL fastboot service, trying HIDL...";
     android::sp<HidlFastboot> hidl_fastboot = HidlFastboot::getService();
diff --git a/fastboot/filesystem.cpp b/fastboot/filesystem.cpp
new file mode 100644
index 0000000..a58ba00
--- /dev/null
+++ b/fastboot/filesystem.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#ifdef _WIN32
+#include <android-base/utf8.h>
+#include <direct.h>
+#include <shlobj.h>
+#else
+#include <pwd.h>
+#endif
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "filesystem.h"
+
+namespace {
+
+int LockFile(int fd) {
+#ifdef _WIN32
+    HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+    OVERLAPPED overlapped = {};
+    const BOOL locked = LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0,
+                                   MAXDWORD, MAXDWORD, &overlapped);
+    return locked ? 0 : -1;
+#else
+    return flock(fd, LOCK_EX);
+#endif
+}
+
+}
+
+// inspired by adb implementation:
+// cs.android.com/android/platform/superproject/+/master:packages/modules/adb/adb_utils.cpp;l=275
+std::string GetHomeDirPath() {
+#ifdef _WIN32
+    WCHAR path[MAX_PATH];
+    const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
+    if (FAILED(hr)) {
+        return {};
+    }
+    std::string home_str;
+    if (!android::base::WideToUTF8(path, &home_str)) {
+        return {};
+    }
+    return home_str;
+#else
+    if (const char* const home = getenv("HOME")) {
+        return home;
+    }
+
+    struct passwd pwent;
+    struct passwd* result;
+    int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (pwent_max == -1) {
+        pwent_max = 16384;
+    }
+    std::vector<char> buf(pwent_max);
+    int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result);
+    if (rc == 0 && result) {
+        return result->pw_dir;
+    }
+#endif
+
+    return {};
+}
+
+bool FileExists(const std::string& path) {
+    return access(path.c_str(), F_OK) == 0;
+}
+
+bool EnsureDirectoryExists(const std::string& directory_path) {
+    const int result =
+#ifdef _WIN32
+                       _mkdir(directory_path.c_str());
+#else
+                       mkdir(directory_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+#endif
+
+    return result == 0 || errno == EEXIST;
+}
+
+FileLock::FileLock(const std::string& path) : fd_(open(path.c_str(), O_CREAT | O_WRONLY, 0644)) {
+    if (LockFile(fd_.get()) != 0) {
+        LOG(FATAL) << "Failed to acquire a lock on " << path;
+    }
+}
\ No newline at end of file
diff --git a/fastboot/filesystem.h b/fastboot/filesystem.h
new file mode 100644
index 0000000..3261496
--- /dev/null
+++ b/fastboot/filesystem.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <string>
+
+using android::base::unique_fd;
+
+// TODO(b/175635923): remove after enabling libc++fs for windows
+const char kPathSeparator =
+#ifdef _WIN32
+                            '\\';
+#else
+                            '/';
+#endif
+
+std::string GetHomeDirPath();
+bool EnsureDirectoryExists(const std::string& directory_path);
+
+class FileLock {
+  public:
+    FileLock() = delete;
+    FileLock(const std::string& path);
+
+  private:
+    unique_fd fd_;
+};
\ No newline at end of file
diff --git a/fastboot/storage.cpp b/fastboot/storage.cpp
new file mode 100644
index 0000000..db13dd6
--- /dev/null
+++ b/fastboot/storage.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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 <android-base/file.h>
+#include <android-base/logging.h>
+
+#include <fstream>
+
+#include "storage.h"
+#include "util.h"
+
+ConnectedDevicesStorage::ConnectedDevicesStorage() {
+    const std::string home_path = GetHomeDirPath();
+    if (home_path.empty()) {
+        return;
+    }
+
+    const std::string home_fastboot_path = home_path + kPathSeparator + ".fastboot";
+
+    if (!EnsureDirectoryExists(home_fastboot_path)) {
+        LOG(FATAL) << "Cannot create directory: " << home_fastboot_path;
+    }
+
+    // We're using a separate file for locking because the Windows LockFileEx does not
+    // permit opening a file stream for the locked file, even within the same process. So,
+    // we have to use fd or handle API to manipulate the storage files, which makes it
+    // nearly impossible to fully rewrite a file content without having to recreate it.
+    // Unfortunately, this is not an option during holding a lock.
+    devices_path_ = home_fastboot_path + kPathSeparator + "devices";
+    devices_lock_path_ = home_fastboot_path + kPathSeparator + "devices.lock";
+}
+
+void ConnectedDevicesStorage::WriteDevices(const std::set<std::string>& devices) {
+    std::ofstream devices_stream(devices_path_);
+    std::copy(devices.begin(), devices.end(),
+              std::ostream_iterator<std::string>(devices_stream, "\n"));
+}
+
+std::set<std::string> ConnectedDevicesStorage::ReadDevices() {
+    std::ifstream devices_stream(devices_path_);
+    std::istream_iterator<std::string> start(devices_stream), end;
+    std::set<std::string> devices(start, end);
+    return devices;
+}
+
+void ConnectedDevicesStorage::Clear() {
+    if (!android::base::RemoveFileIfExists(devices_path_)) {
+        LOG(FATAL) << "Failed to clear connected device list: " << devices_path_;
+    }
+}
+
+FileLock ConnectedDevicesStorage::Lock() const {
+    return FileLock(devices_lock_path_);
+}
\ No newline at end of file
diff --git a/fastboot/storage.h b/fastboot/storage.h
new file mode 100644
index 0000000..1cce950
--- /dev/null
+++ b/fastboot/storage.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "filesystem.h"
+
+class ConnectedDevicesStorage {
+  public:
+    ConnectedDevicesStorage();
+    void WriteDevices(const std::set<std::string>& devices);
+    std::set<std::string> ReadDevices();
+    void Clear();
+
+    FileLock Lock() const;
+  private:
+    std::string devices_path_;
+    std::string devices_lock_path_;
+};
\ No newline at end of file
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 4ea452a..b180a58 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -138,6 +138,7 @@
       mBatteryDevicePresent(false),
       mBatteryFixedCapacity(0),
       mBatteryFixedTemperature(0),
+      mBatteryHealthStatus(BatteryMonitor::BH_UNKNOWN),
       mHealthInfo(std::make_unique<HealthInfo>()) {
     initHealthInfo(mHealthInfo.get());
 }
@@ -230,6 +231,23 @@
     return *ret;
 }
 
+BatteryHealth getBatteryHealthStatus(int status) {
+    BatteryHealth value;
+
+    if (status == BatteryMonitor::BH_NOMINAL)
+        value = BatteryHealth::GOOD;
+    else if (status == BatteryMonitor::BH_MARGINAL)
+        value = BatteryHealth::FAIR;
+    else if (status == BatteryMonitor::BH_NEEDS_REPLACEMENT)
+        value = BatteryHealth::DEAD;
+    else if (status == BatteryMonitor::BH_FAILED)
+        value = BatteryHealth::UNSPECIFIED_FAILURE;
+    else
+        value = BatteryHealth::UNKNOWN;
+
+    return value;
+}
+
 BatteryChargingPolicy getBatteryChargingPolicy(const char* chargingPolicy) {
     static SysfsStringEnumMap<BatteryChargingPolicy> batteryChargingPolicyMap[] = {
             {"0", BatteryChargingPolicy::INVALID},   {"1", BatteryChargingPolicy::DEFAULT},
@@ -377,6 +395,9 @@
     if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
         mHealthInfo->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath);
 
+    if (!mHealthdConfig->batteryHealthStatusPath.isEmpty())
+        mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath);
+
     if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
         mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds =
                 getIntField(mHealthdConfig->batteryManufacturingDatePath);
@@ -397,8 +418,13 @@
     if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
         mHealthInfo->batteryStatus = getBatteryStatus(buf.c_str());
 
-    if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
-        mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
+    // Backward compatible with android.hardware.health V1
+    if (mBatteryHealthStatus < BatteryMonitor::BH_MARGINAL) {
+        if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
+            mHealthInfo->batteryHealth = getBatteryHealth(buf.c_str());
+    } else {
+        mHealthInfo->batteryHealth = getBatteryHealthStatus(mBatteryHealthStatus);
+    }
 
     if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
         mHealthInfo->batteryTechnology = String8(buf.c_str());
@@ -878,6 +904,12 @@
                     }
                 }
 
+                if (mHealthdConfig->batteryHealthStatusPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthStatusPath = path;
+                }
+
                 if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name);
@@ -957,6 +989,8 @@
             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
         if (mHealthdConfig->batteryStateOfHealthPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n");
+        if (mHealthdConfig->batteryHealthStatusPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "batteryHealthStatusPath not found\n");
         if (mHealthdConfig->batteryManufacturingDatePath.isEmpty())
             KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n");
         if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 4af2a87..7b4f46c 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -56,6 +56,14 @@
         ANDROID_POWER_SUPPLY_TYPE_DOCK
     };
 
+    enum BatteryHealthStatus {
+        BH_UNKNOWN = -1,
+        BH_NOMINAL,
+        BH_MARGINAL,
+        BH_NEEDS_REPLACEMENT,
+        BH_FAILED,
+    };
+
     BatteryMonitor();
     ~BatteryMonitor();
     void init(struct healthd_config *hc);
@@ -85,6 +93,7 @@
     bool mBatteryDevicePresent;
     int mBatteryFixedCapacity;
     int mBatteryFixedTemperature;
+    int mBatteryHealthStatus;
     std::unique_ptr<aidl::android::hardware::health::HealthInfo> mHealthInfo;
 };
 
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index e1c357c..688e458 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -73,6 +73,7 @@
     android::String8 batteryChargeTimeToFullNowPath;
     android::String8 batteryFullChargeDesignCapacityUahPath;
     android::String8 batteryStateOfHealthPath;
+    android::String8 batteryHealthStatusPath;
     android::String8 batteryManufacturingDatePath;
     android::String8 batteryFirstUsageDatePath;
     android::String8 chargingStatePath;
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 1e69ede..7bb5c90 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -679,6 +679,10 @@
 }
 
 TEST(init, GentleKill) {
+    if (getuid() != 0) {
+        GTEST_SKIP() << "Must be run as root.";
+        return;
+    }
     std::string init_script = R"init(
 service test_gentle_kill /system/bin/sleep 1000
     disabled
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 468d796..ac369d2 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -229,8 +229,8 @@
         auto controller_count = ACgroupFile_getControllerCount();
         for (uint32_t i = 0; i < controller_count; ++i) {
             const ACgroupController* controller = ACgroupFile_getController(i);
-            if (ACgroupController_getFlags(controller) &
-                CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+            const uint32_t flags = ACgroupController_getFlags(controller);
+            if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
                 std::string str("+");
                 str.append(ACgroupController_getName(controller));
                 if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3dd269a..3362872 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -222,6 +222,8 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 LOCAL_MODULE_PATH := $(PRODUCT_OUT)
 
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
 include $(BUILD_PREBUILT)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))