Merge RQ2A.210305.007

Bug: 180401296
Merged-In: I0ea517cc72be1bd492f8a70f14dbb0d3295f6304
Change-Id: I03928f17ba4bf3a87c1ffd6927cf57e40db4fa64
diff --git a/health/Android.bp b/health/Android.bp
index b563b43..e954ca3 100644
--- a/health/Android.bp
+++ b/health/Android.bp
@@ -58,6 +58,7 @@
     static_libs: [
         "libgmock",
         "libpixelhealth",
+        "libbatterymonitor",
     ],
 
     shared_libs: [
diff --git a/health/BatteryDefender.cpp b/health/BatteryDefender.cpp
index 37283da..4d93741 100644
--- a/health/BatteryDefender.cpp
+++ b/health/BatteryDefender.cpp
@@ -34,10 +34,12 @@
 namespace pixel {
 namespace health {
 
-BatteryDefender::BatteryDefender(const char *pathChargeLevelStart, const char *pathChargeLevelStop,
-                                 const int32_t timeToActivateSecs,
+BatteryDefender::BatteryDefender(const char *pathWirelessPresent, const char *pathChargeLevelStart,
+                                 const char *pathChargeLevelStop, const int32_t timeToActivateSecs,
                                  const int32_t timeToClearTimerSecs)
-    : kPathChargeLevelStart(pathChargeLevelStart),
+
+    : kPathWirelessPresent(pathWirelessPresent),
+      kPathChargeLevelStart(pathChargeLevelStart),
       kPathChargeLevelStop(pathChargeLevelStop),
       kTimeToActivateSecs(timeToActivateSecs),
       kTimeToClearTimerSecs(timeToClearTimerSecs) {
@@ -75,11 +77,13 @@
     str->erase(std::remove(str->begin(), str->end(), '\r'), str->end());
 }
 
-int BatteryDefender::readFileToInt(const char *path) {
+int BatteryDefender::readFileToInt(const char *path, const bool optionalFile) {
     std::string buffer;
     int value = 0;  // default
     if (!android::base::ReadFileToString(path, &buffer)) {
-        LOG(ERROR) << "Failed to read " << path;
+        if (optionalFile == false) {
+            LOG(ERROR) << "Failed to read " << path;
+        }
     } else {
         removeLineEndings(&buffer);
         if (!android::base::ParseInt(buffer.c_str(), &value)) {
@@ -113,8 +117,20 @@
     int chargeLevelStart = vendorStart;
     int chargeLevelStop = vendorStop;
     if (mCurrentState == STATE_ACTIVE) {
-        chargeLevelStart = kChargeLevelDefenderStart;
-        chargeLevelStop = kChargeLevelDefenderStop;
+        const int newDefenderLevelStart = android::base::GetIntProperty(
+                kPropBatteryDefenderCtrlStartSOC, kChargeLevelDefenderStart, 0, 100);
+        const int newDefenderLevelStop = android::base::GetIntProperty(
+                kPropBatteryDefenderCtrlStopSOC, kChargeLevelDefenderStop, 0, 100);
+        const bool overrideLevelsValid =
+                (newDefenderLevelStart <= newDefenderLevelStop) && (newDefenderLevelStop != 0);
+
+        if (overrideLevelsValid) {
+            chargeLevelStart = newDefenderLevelStart;
+            chargeLevelStop = newDefenderLevelStop;
+        } else {
+            chargeLevelStart = kChargeLevelDefenderStart;
+            chargeLevelStop = kChargeLevelDefenderStop;
+        }
     }
 
     // Disable battery defender effects in charger mode until
@@ -134,13 +150,17 @@
 }
 
 bool BatteryDefender::isChargePowerAvailable(void) {
-    // USB presence is an indicator of connectivity
-    const bool chargerPresentWired = readFileToInt(kPathWiredChargerPresent) != 0;
+    // USB presence is an indicator of power availability
+    const bool chargerPresentWired = readFileToInt(kPathUSBChargerPresent) != 0;
+    const bool chargerPresentWireless =
+            readFileToInt(kPathWirelessPresent, mIgnoreWirelessFileError) != 0;
+    mIsUsbPresent = chargerPresentWired;
+    mIsWirelessPresent = chargerPresentWireless;
 
-    // Wireless online is an indicator of a device having charge power
-    const bool chargerOnlineWireless = readFileToInt(kPathWirelessChargerOnline) != 0;
+    // Report wireless read error only once; some devices may not have a wireless adapter
+    mIgnoreWirelessFileError = true;
 
-    return chargerPresentWired || chargerOnlineWireless;
+    return chargerPresentWired || chargerPresentWireless;
 }
 
 bool BatteryDefender::isDefaultChargeLevel(const int start, const int stop) {
@@ -149,11 +169,12 @@
 
 bool BatteryDefender::isBatteryDefenderDisabled(const int vendorStart, const int vendorStop) {
     const bool isDefaultVendorChargeLevel = isDefaultChargeLevel(vendorStart, vendorStop);
-    const bool isExplicitlyDisabled =
+    const bool isOverrideDisabled =
             android::base::GetBoolProperty(kPropBatteryDefenderDisable, false);
-    const bool isDebuggable = android::base::GetBoolProperty(kPropDebuggable, false);
+    const bool isCtrlEnabled =
+            android::base::GetBoolProperty(kPropBatteryDefenderCtrlEnable, kDefaultEnable);
 
-    return isExplicitlyDisabled || (isDefaultVendorChargeLevel == false) || (isDebuggable == false);
+    return isOverrideDisabled || (isDefaultVendorChargeLevel == false) || (isCtrlEnabled == false);
 }
 
 void BatteryDefender::addTimeToChargeTimers(void) {
@@ -170,14 +191,31 @@
 int32_t BatteryDefender::getTimeToActivate(void) {
     // Use the default constructor value if the modified property is not between 60 and INT_MAX
     // (seconds)
-    return android::base::GetIntProperty(kPropBatteryDefenderThreshold, kTimeToActivateSecs,
-                                         (int32_t)ONE_MIN_IN_SECONDS, INT32_MAX);
+    const int32_t timeToActivateOverride =
+            android::base::GetIntProperty(kPropBatteryDefenderThreshold, kTimeToActivateSecs,
+                                          (int32_t)ONE_MIN_IN_SECONDS, INT32_MAX);
+
+    const bool overrideActive = timeToActivateOverride != kTimeToActivateSecs;
+    if (overrideActive) {
+        return timeToActivateOverride;
+    } else {
+        // No overrides taken; apply ctrl time to activate...
+        // Note; do not allow less than 1 day trigger time
+        return android::base::GetIntProperty(kPropBatteryDefenderCtrlActivateTime,
+                                             kTimeToActivateSecs, (int32_t)ONE_DAY_IN_SECONDS,
+                                             INT32_MAX);
+    }
 }
 
-void BatteryDefender::stateMachine_runAction(const state_E state) {
+void BatteryDefender::stateMachine_runAction(const state_E state,
+                                             const struct android::BatteryProperties *props) {
     switch (state) {
         case STATE_INIT:
             loadPersistentStorage();
+            if (props->chargerUsbOnline || props->chargerAcOnline) {
+                mWasAcOnline = props->chargerAcOnline;
+                mWasUsbOnline = props->chargerUsbOnline;
+            }
             break;
 
         case STATE_DISABLED:
@@ -185,12 +223,15 @@
             clearStateData();
             break;
 
-        case STATE_CONNECTED:
+        case STATE_CONNECTED: {
             addTimeToChargeTimers();
-            if (readFileToInt(kPathBatteryCapacity) == kChargeHighCapacityLevel) {
+
+            const int triggerLevel = android::base::GetIntProperty(
+                    kPropBatteryDefenderCtrlTriggerSOC, kChargeHighCapacityLevel, 0, 100);
+            if (props->batteryLevel >= triggerLevel) {
                 mHasReachedHighCapacityLevel = true;
             }
-            break;
+        } break;
 
         case STATE_ACTIVE:
             addTimeToChargeTimers();
@@ -237,13 +278,19 @@
             case STATE_CONNECTED:
                 if (mTimeChargerPresentSecs > mTimeToActivateSecsModified) {
                     nextState = STATE_ACTIVE;
-                } else if (mTimeChargerNotPresentSecs > kTimeToClearTimerSecs) {
+                }
+                FALLTHROUGH_INTENDED;
+
+            case STATE_ACTIVE: {
+                const int timeToClear = android::base::GetIntProperty(
+                        kPropBatteryDefenderCtrlResumeTime, kTimeToClearTimerSecs, 0, INT32_MAX);
+
+                /* Check for mIsPowerAvailable in case timeToClear is 0 */
+                if ((mTimeChargerNotPresentSecs >= timeToClear) && (mIsPowerAvailable == false)) {
                     nextState = STATE_DISCONNECTED;
                 }
-                break;
+            } break;
 
-            case STATE_ACTIVE:
-                // Latch unless disabled or unless the health module has restarted (ie. reboot)
             default:
                 break;
         }
@@ -257,9 +304,8 @@
 void BatteryDefender::stateMachine_firstAction(const state_E state) {
     switch (state) {
         case STATE_DISABLED:
-            clearStateData();
             LOG(INFO) << "Disabled!";
-            break;
+            FALLTHROUGH_INTENDED;
 
         case STATE_DISCONNECTED:
             clearStateData();
@@ -286,7 +332,50 @@
     }
 }
 
-void BatteryDefender::update(void) {
+void BatteryDefender::updateDefenderProperties(struct android::BatteryProperties *props) {
+    /**
+     * Override the OVERHEAT flag for UI updates to settings.
+     * Also, force AC/USB online if active and still connected to power.
+     */
+    if (mCurrentState == STATE_ACTIVE) {
+        props->batteryHealth = android::BATTERY_HEALTH_OVERHEAT;
+    }
+
+    /**
+     * If the kernel is forcing the input current limit to 0, then the online status may
+     * need to be overwritten. Also, setting a charge limit below the current charge level
+     * may disable the adapter.
+     * Note; only override "online" if necessary (all "online"s are false).
+     */
+    if (props->chargerUsbOnline == false && props->chargerAcOnline == false) {
+        /* Override if the USB is connected and a battery defender is active */
+        if (mIsUsbPresent && props->batteryHealth == android::BATTERY_HEALTH_OVERHEAT) {
+            if (mWasAcOnline) {
+                props->chargerAcOnline = true;
+            }
+            if (mWasUsbOnline) {
+                props->chargerUsbOnline = true;
+            }
+        }
+    } else {
+        /* One of these booleans will always be true if updated here */
+        mWasAcOnline = props->chargerAcOnline;
+        mWasUsbOnline = props->chargerUsbOnline;
+    }
+
+    /* Do the same as above for wireless adapters */
+    if (props->chargerWirelessOnline == false) {
+        if (mIsWirelessPresent && props->batteryHealth == android::BATTERY_HEALTH_OVERHEAT) {
+            props->chargerWirelessOnline = true;
+        }
+    }
+}
+
+void BatteryDefender::update(struct android::BatteryProperties *props) {
+    if (!props) {
+        return;
+    }
+
     // Update module inputs
     const int chargeLevelVendorStart =
             android::base::GetIntProperty(kPropChargeLevelVendorStart, kChargeLevelDefaultStart);
@@ -297,13 +386,16 @@
     mTimeBetweenUpdateCalls = getDeltaTimeSeconds(&mTimePreviousSecs);
 
     // Run state machine
-    stateMachine_runAction(mCurrentState);
+    stateMachine_runAction(mCurrentState, props);
     const state_E nextState = stateMachine_getNextState(mCurrentState);
     if (nextState != mCurrentState) {
         stateMachine_firstAction(nextState);
     }
     mCurrentState = nextState;
 
+    // Verify/update battery defender battery properties
+    updateDefenderProperties(props); /* May override battery properties */
+
     // Store outputs
     writeTimeToFile(kPathPersistChargerPresentTime, mTimeChargerPresentSecs,
                     &mTimeChargerPresentSecsPrevious);
diff --git a/health/include/pixelhealth/BatteryDefender.h b/health/include/pixelhealth/BatteryDefender.h
index 30512c2..4a16bcc 100644
--- a/health/include/pixelhealth/BatteryDefender.h
+++ b/health/include/pixelhealth/BatteryDefender.h
@@ -17,6 +17,8 @@
 #ifndef HARDWARE_GOOGLE_PIXEL_HEALTH_BATTERYDEFENDER_H
 #define HARDWARE_GOOGLE_PIXEL_HEALTH_BATTERYDEFENDER_H
 
+#include <batteryservice/BatteryService.h>
+
 #include <stdbool.h>
 #include <time.h>
 #include <string>
@@ -31,18 +33,19 @@
 const uint32_t ONE_DAY_IN_HOURS = 24;
 const uint32_t ONE_DAY_IN_SECONDS = ONE_DAY_IN_HOURS * ONE_HOUR_IN_MINUTES * ONE_MIN_IN_SECONDS;
 
-const uint32_t DEFAULT_TIME_TO_ACTIVATE_SECONDS = (14 * ONE_DAY_IN_SECONDS);
+const uint32_t DEFAULT_TIME_TO_ACTIVATE_SECONDS = (4 * ONE_DAY_IN_SECONDS);
 const uint32_t DEFAULT_TIME_TO_CLEAR_SECONDS = (5 * ONE_MIN_IN_SECONDS);
 const int DEFAULT_CHARGE_LEVEL_START = 0;
 const int DEFAULT_CHARGE_LEVEL_STOP = 100;
-const int DEFAULT_CHARGE_LEVEL_DEFENDER_START = 60;
-const int DEFAULT_CHARGE_LEVEL_DEFENDER_STOP = 70;
+const int DEFAULT_CHARGE_LEVEL_DEFENDER_START = 70;
+const int DEFAULT_CHARGE_LEVEL_DEFENDER_STOP = 80;
 const int DEFAULT_CAPACITY_LEVEL = 100;
 
 class BatteryDefender {
   public:
     // Set default google charger paths - can be overridden for other devices
-    BatteryDefender(const char *pathChargeLevelStart =
+    BatteryDefender(const char *pathWirelessPresent = "/sys/class/power_supply/wireless/present",
+                    const char *pathChargeLevelStart =
                             "/sys/devices/platform/soc/soc:google,charger/charge_start_level",
                     const char *pathChargeLevelStop =
                             "/sys/devices/platform/soc/soc:google,charger/charge_stop_level",
@@ -50,7 +53,7 @@
                     const int32_t timeToClearTimerSecs = DEFAULT_TIME_TO_CLEAR_SECONDS);
 
     // This function shall be called periodically in HealthService
-    void update(void);
+    void update(struct android::BatteryProperties *props);
 
   private:
     enum state_E {
@@ -69,15 +72,14 @@
             [STATE_ACTIVE] = "ACTIVE",
     };
 
+    const char *const kPathWirelessPresent;
     const char *const kPathChargeLevelStart;
     const char *const kPathChargeLevelStop;
     const int32_t kTimeToActivateSecs;
     const int32_t kTimeToClearTimerSecs;
 
     // Sysfs
-    const char *const kPathWirelessChargerOnline = "/sys/class/power_supply/wireless/online";
-    const char *const kPathWiredChargerPresent = "/sys/class/power_supply/usb/present";
-    const char *const kPathBatteryCapacity = "/sys/class/power_supply/battery/capacity";
+    const char *const kPathUSBChargerPresent = "/sys/class/power_supply/usb/present";
     const char *const kPathPersistChargerPresentTime =
             "/mnt/vendor/persist/battery/defender_charger_time";
     const char *const kPathPersistDefenderActiveTime =
@@ -89,10 +91,21 @@
     const char *const kPropBatteryDefenderState = "vendor.battery.defender.state";
     const char *const kPropBatteryDefenderDisable = "vendor.battery.defender.disable";
     const char *const kPropBatteryDefenderThreshold = "vendor.battery.defender.threshold";
-    const char *const kPropDebuggable = "ro.debuggable";
     const char *const kPropBootmode = "ro.bootmode";
+    const char *const kPropBatteryDefenderCtrlEnable = "vendor.battery.defender.ctrl.enable";
+    const char *const kPropBatteryDefenderCtrlActivateTime =
+            "vendor.battery.defender.ctrl.trigger_time";
+    const char *const kPropBatteryDefenderCtrlResumeTime =
+            "vendor.battery.defender.ctrl.resume_time";
+    const char *const kPropBatteryDefenderCtrlStartSOC =
+            "vendor.battery.defender.ctrl.recharge_soc_start";
+    const char *const kPropBatteryDefenderCtrlStopSOC =
+            "vendor.battery.defender.ctrl.recharge_soc_stop";
+    const char *const kPropBatteryDefenderCtrlTriggerSOC =
+            "vendor.battery.defender.ctrl.trigger_soc";
 
     // Default thresholds
+    const bool kDefaultEnable = true;
     const int kChargeLevelDefaultStart = DEFAULT_CHARGE_LEVEL_START;
     const int kChargeLevelDefaultStop = DEFAULT_CHARGE_LEVEL_STOP;
     const int kChargeLevelDefenderStart = DEFAULT_CHARGE_LEVEL_DEFENDER_START;
@@ -102,6 +115,8 @@
     // Inputs
     int64_t mTimeBetweenUpdateCalls = 0;
     int64_t mTimePreviousSecs;
+    bool mIsUsbPresent = false;
+    bool mIsWirelessPresent = false;
     bool mIsPowerAvailable = false;
     bool mIsDefenderDisabled = false;
     int32_t mTimeToActivateSecsModified;
@@ -116,18 +131,28 @@
     int mChargeLevelStartPrevious = DEFAULT_CHARGE_LEVEL_START;
     int mChargeLevelStopPrevious = DEFAULT_CHARGE_LEVEL_STOP;
     bool mHasReachedHighCapacityLevel = false;
+    bool mWasAcOnline = false;
+    bool mWasUsbOnline = true; /* Default; in case neither AC/USB online becomes 1 */
+    bool mIgnoreWirelessFileError = false;
 
-    void stateMachine_runAction(const state_E state);        // Process state actions
-    state_E stateMachine_getNextState(const state_E state);  // Check transitions
-    void stateMachine_firstAction(const state_E state);      // Process entry actions
+    // Process state actions
+    void stateMachine_runAction(const state_E state,
+                                const struct android::BatteryProperties *props);
 
+    // Check state transitions
+    state_E stateMachine_getNextState(const state_E state);
+
+    // Process state entry actions
+    void stateMachine_firstAction(const state_E state);
+
+    void updateDefenderProperties(struct android::BatteryProperties *props);
     void clearStateData(void);
     void loadPersistentStorage(void);
     int64_t getTime(void);
     int64_t getDeltaTimeSeconds(int64_t *timeStartSecs);
     int32_t getTimeToActivate(void);
     void removeLineEndings(std::string *str);
-    int readFileToInt(const char *path);
+    int readFileToInt(const char *path, const bool optionalFile = false);
     bool writeIntToFile(const char *path, const int value);
     void writeTimeToFile(const char *path, const int value, int64_t *previous);
     void writeChargeLevelsToFile(const int vendorStart, const int vendorStop);
diff --git a/health/test/TestBatteryDefender.cpp b/health/test/TestBatteryDefender.cpp
index 50656c6..7366aab 100644
--- a/health/test/TestBatteryDefender.cpp
+++ b/health/test/TestBatteryDefender.cpp
@@ -24,6 +24,8 @@
 #include <android-base/file.h>
 #include <android-base/properties.h>
 
+#define MIN_TIME_BETWEEN_FILE_UPDATES (30 + 1)
+
 class HealthInterface {
   public:
     virtual ~HealthInterface() {}
@@ -102,6 +104,8 @@
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
+struct android::BatteryProperties props;
+
 class BatteryDefenderTest : public ::testing::Test {
   public:
     BatteryDefenderTest() {}
@@ -109,6 +113,8 @@
     void SetUp() {
         mock = &mockFixture;
 
+        props = {};
+
         EXPECT_CALL(*mock, SetProperty(_, _)).Times(AnyNumber());
         EXPECT_CALL(*mock, ReadFileToString(_, _, _)).Times(AnyNumber());
         EXPECT_CALL(*mock, GetIntProperty(_, _, _, _)).Times(AnyNumber());
@@ -127,9 +133,8 @@
     HealthInterfaceMock mockFixture;
 };
 
-const char *kPathWirelessChargerOnline = "/sys/class/power_supply/wireless/online";
 const char *kPathWiredChargerPresent = "/sys/class/power_supply/usb/present";
-const char *kPathBatteryCapacity = "/sys/class/power_supply/battery/capacity";
+const char *kPathWirelessChargerPresent = "/sys/class/power_supply/wireless/present";
 const char *kPathPersistChargerPresentTime = "/mnt/vendor/persist/battery/defender_charger_time";
 const char *kPathPersistDefenderActiveTime = "/mnt/vendor/persist/battery/defender_active_time";
 const char *kPathStartLevel = "/sys/devices/platform/soc/soc:google,charger/charge_start_level";
@@ -140,30 +145,62 @@
 const char *kPropBatteryDefenderState = "vendor.battery.defender.state";
 const char *kPropBatteryDefenderDisable = "vendor.battery.defender.disable";
 const char *kPropBatteryDefenderThreshold = "vendor.battery.defender.threshold";
-const char *kPropDebuggable = "ro.debuggable";
+
+const char *kPropBatteryDefenderCtrlEnable = "vendor.battery.defender.ctrl.enable";
+const char *kPropBatteryDefenderCtrlActivateTime = "vendor.battery.defender.ctrl.trigger_time";
+const char *kPropBatteryDefenderCtrlResumeTime = "vendor.battery.defender.ctrl.resume_time";
+const char *kPropBatteryDefenderCtrlStartSOC = "vendor.battery.defender.ctrl.recharge_soc_start";
+const char *kPropBatteryDefenderCtrlStopSOC = "vendor.battery.defender.ctrl.recharge_soc_stop";
+const char *kPropBatteryDefenderCtrlTriggerSOC = "vendor.battery.defender.ctrl.trigger_soc";
 
 static void enableDefender(void) {
     ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStart, _, _, _)).WillByDefault(Return(0));
     ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillByDefault(Return(100));
     ON_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillByDefault(Return(false));
-    ON_CALL(*mock, GetBoolProperty(kPropDebuggable, _)).WillByDefault(Return(true));
+
+    ON_CALL(*mock, GetBoolProperty(kPropBatteryDefenderCtrlEnable, _)).WillByDefault(Return(true));
 }
 
-static void powerAvailable(void) {
-    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _))
-            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
+static void usbPresent(void) {
     ON_CALL(*mock, ReadFileToString(kPathWiredChargerPresent, _, _))
             .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
 }
 
-static void defaultThreshold(void) {
+static void wirelessPresent(void) {
+    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerPresent, _, _))
+            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
+}
+
+static void wirelessNotPresent(void) {
+    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerPresent, _, _))
+            .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true)));
+}
+
+static void powerAvailable(void) {
+    wirelessPresent();
+    usbPresent();
+}
+
+static void defaultThresholds(void) {
     ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
             .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));
+
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
+            .WillByDefault(Return(70));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
+            .WillByDefault(Return(80));
+
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlTriggerSOC, _, _, _))
+            .WillByDefault(Return(100));
 }
 
 static void capacityReached(void) {
-    ON_CALL(*mock, ReadFileToString(kPathBatteryCapacity, _, _))
-            .WillByDefault(DoAll(SetArgPointee<1>(std::to_string(100)), Return(true)));
+    props.batteryLevel = 100;
 }
 
 static void initToConnectedCapacityReached(void) {
@@ -186,7 +223,7 @@
 
     // Enable Battery Defender
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
-    battDefender.update();
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, DisableNonDefaultLevels) {
@@ -197,17 +234,7 @@
     EXPECT_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillOnce(Return(35));
 
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED"));
-    battDefender.update();
-}
-
-TEST_F(BatteryDefenderTest, DisableDebuggable) {
-    BatteryDefender battDefender;
-
-    // Enable Battery Defender
-    EXPECT_CALL(*mock, GetBoolProperty(kPropDebuggable, _)).WillOnce(Return(false));
-
-    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED"));
-    battDefender.update();
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, DisableExplicit) {
@@ -217,7 +244,7 @@
     EXPECT_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillOnce(Return(true));
 
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED"));
-    battDefender.update();
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, InitActive) {
@@ -225,13 +252,13 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
 
     EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
             .WillOnce(DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1)),
                             Return(true)));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
-    battDefender.update();
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, InitConnectedCapacityReached) {
@@ -239,21 +266,22 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
 
     InSequence s;
 
+    int time_expected = DEFAULT_TIME_TO_ACTIVATE_SECONDS - 1;
     EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS - 1)),
-                            Return(true)));
+            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(time_expected)), Return(true)));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    battDefender.update();
+    battDefender.update(&props);
 
-    testvar_systemTimeSecs++;
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS),
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    time_expected += MIN_TIME_BETWEEN_FILE_UPDATES;
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(time_expected),
                                          kPathPersistChargerPresentTime, _));
-    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    battDefender.update();
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, InitConnected) {
@@ -261,19 +289,24 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
 
     InSequence s;
 
     EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
             .WillOnce(DoAll(SetArgPointee<1>(std::to_string(0)), Return(true)));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    battDefender.update();
+    battDefender.update(&props);
 
     // mHasReachedHighCapacityLevel shall be false
     testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    battDefender.update();
+    battDefender.update(&props);
+
+    // Would be active if mHasReachedHighCapacityLevel was true
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, TriggerTime) {
@@ -281,32 +314,32 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
 
     InSequence s;
 
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    testvar_systemTimeSecs += 1;
-    battDefender.update();
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    battDefender.update(&props);
 
     // Reached 100% capacity at least once
-    EXPECT_CALL(*mock, ReadFileToString(kPathBatteryCapacity, _, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(100)), Return(true)));
+    capacityReached();
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    testvar_systemTimeSecs += 1;
-    battDefender.update();
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    battDefender.update(&props);
 
     EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS),
                                          kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS;
-    battDefender.update();
+    battDefender.update(&props);
 
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1),
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS +
+                                                        MIN_TIME_BETWEEN_FILE_UPDATES),
                                          kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
-    testvar_systemTimeSecs += 1;
-    battDefender.update();
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, ChargeLevels) {
@@ -314,7 +347,7 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
     initToConnectedCapacityReached();
 
     InSequence s;
@@ -322,13 +355,13 @@
     // No expectations needed; default values already set
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 0;
-    battDefender.update();
+    battDefender.update(&props);
 
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStartLevel, _));
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStopLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
     testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
-    battDefender.update();
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, ActiveTime) {
@@ -336,78 +369,425 @@
 
     enableDefender();
     powerAvailable();
-    defaultThreshold();
+    defaultThresholds();
     initToActive();
 
     InSequence s;
 
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStartLevel, _));
-    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStopLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
-    battDefender.update();
+    battDefender.update(&props);
+}
+
+TEST_F(BatteryDefenderTest, ActiveTime_NonDefaultLevels) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    powerAvailable();
+    initToActive();
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));
+
+    // Non-default
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
+            .WillByDefault(Return(50));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
+            .WillByDefault(Return(60));
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(50), kPathStartLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStopLevel, _));
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
+    battDefender.update(&props);
+}
+
+TEST_F(BatteryDefenderTest, ActiveTime_NonDefaultLevels_invalid) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    powerAvailable();
+    initToActive();
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));
+
+    // Non-default
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
+            .WillByDefault(Return(30));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
+            .WillByDefault(Return(10));
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
+    battDefender.update(&props);
 }
 
 TEST_F(BatteryDefenderTest, ConnectDisconnectCycle) {
     BatteryDefender battDefender;
 
     enableDefender();
-    defaultThreshold();
+    defaultThresholds();
     initToConnectedCapacityReached();
 
     InSequence s;
 
     // Power ON
-    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _))
-            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
+    wirelessPresent();
 
     EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000), kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
 
     EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1060), kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
 
     // Power OFF
-    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _))
-            .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true)));
+    wirelessNotPresent();
 
     // Maintain kPathPersistChargerPresentTime = 1060
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
 
     // Maintain kPathPersistChargerPresentTime = 1060
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
-    testvar_systemTimeSecs += 60 * 4;
-    battDefender.update();
+    testvar_systemTimeSecs += 60 * 4 - 1;
+    battDefender.update(&props);
 
+    testvar_systemTimeSecs += 1;
     EXPECT_CALL(*mock, WriteStringToFile(std::to_string(0), kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
-    testvar_systemTimeSecs += 1;
-    battDefender.update();
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    battDefender.update(&props);
 
     // Power ON
-    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _))
-            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
+    wirelessPresent();
 
     // Maintain kPathPersistChargerPresentTime = 0
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
 
     capacityReached();
     // Maintain kPathPersistChargerPresentTime = 0
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
 
     EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathPersistChargerPresentTime, _));
     EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
     testvar_systemTimeSecs += 60;
-    battDefender.update();
+    battDefender.update(&props);
+}
+
+TEST_F(BatteryDefenderTest, ConnectDisconnectResumeTimeThreshold0) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    initToConnectedCapacityReached();
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
+            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
+
+    // Non-default thresholds
+    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
+            .WillByDefault(Return(0));
+
+    InSequence s;
+
+    // Power ON
+    wirelessPresent();
+
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000), kPathPersistChargerPresentTime, _));
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    testvar_systemTimeSecs += 60;
+    battDefender.update(&props);
+
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1060), kPathPersistChargerPresentTime, _));
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    testvar_systemTimeSecs += 60;
+    battDefender.update(&props);
+
+    // Power OFF
+    wirelessNotPresent();
+
+    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(0), kPathPersistChargerPresentTime, _));
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
+    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
+    battDefender.update(&props);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitActive_allOnlineFalse) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToActive();
+
+    InSequence s;
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitActive_usbOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToActive();
+
+    InSequence s;
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = true;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitActive_acOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToActive();
+
+    InSequence s;
+
+    props.chargerAcOnline = true;
+    props.chargerUsbOnline = false;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, false);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, false);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitActive_allOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToActive();
+
+    InSequence s;
+
+    props.chargerAcOnline = true;
+    props.chargerUsbOnline = true;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_allOnlineFalse) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_usbOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = true;
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, false);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_acOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
+
+    props.chargerAcOnline = true;
+    props.chargerUsbOnline = false;
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, false);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, false);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_allOnline) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
+
+    props.chargerAcOnline = true;
+    props.chargerUsbOnline = true;
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_overrideHealth) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    props.batteryHealth = android::BATTERY_HEALTH_UNKNOWN;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
+    battDefender.update(&props);
+    ASSERT_EQ(props.batteryHealth, android::BATTERY_HEALTH_UNKNOWN);
+
+    props.batteryHealth = android::BATTERY_HEALTH_UNKNOWN;
+    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
+    battDefender.update(&props);
+    ASSERT_EQ(props.batteryHealth, android::BATTERY_HEALTH_OVERHEAT);
+}
+
+TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_kernelDefend) {
+    BatteryDefender battDefender;
+
+    enableDefender();
+    usbPresent();
+    defaultThresholds();
+    initToConnectedCapacityReached();
+
+    InSequence s;
+
+    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")).Times(3);
+    battDefender.update(&props);
+
+    props.chargerAcOnline = true;
+    props.chargerUsbOnline = true;
+    props.batteryHealth = android::BATTERY_HEALTH_OVERHEAT;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    battDefender.update(&props);
+    ASSERT_EQ(props.chargerAcOnline, true);
+    ASSERT_EQ(props.chargerUsbOnline, true);
 }
 
 }  // namespace health
diff --git a/pixelstats/Android.bp b/pixelstats/Android.bp
index 7f2ee61..94fa064 100644
--- a/pixelstats/Android.bp
+++ b/pixelstats/Android.bp
@@ -49,6 +49,7 @@
     "UeventListener.cpp",
     "WlcReporter.cpp",
     "BatteryCapacityReporter.cpp",
+    "BatteryEEPROMReporter.cpp",
   ],
   cflags: [
     "-Wall",
diff --git a/pixelstats/BatteryEEPROMReporter.cpp b/pixelstats/BatteryEEPROMReporter.cpp
new file mode 100644
index 0000000..ab0280d
--- /dev/null
+++ b/pixelstats/BatteryEEPROMReporter.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "pixelstats: BatteryEEPROM"
+
+#include <log/log.h>
+#include <time.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <inttypes.h>
+
+#include <android-base/file.h>
+
+#include <android/frameworks/stats/1.0/IStats.h>
+#include <pixelstats/BatteryEEPROMReporter.h>
+
+#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+using android::base::ReadFileToString;
+using android::frameworks::stats::V1_0::IStats;
+using android::frameworks::stats::V1_0::VendorAtom;
+using android::hardware::google::pixel::PixelAtoms::BatteryEEPROM;
+
+#define LINESIZE 71
+
+BatteryEEPROMReporter::BatteryEEPROMReporter() {}
+
+void BatteryEEPROMReporter::checkAndReport(const std::string &path) {
+    std::string file_contents;
+    std::string history_each;
+
+    const int kSecondsPerMonth = 60 * 60 * 24 * 30;
+    int64_t now = getTimeSecs();
+
+    if ((report_time_ != 0) && (now - report_time_ < kSecondsPerMonth)) {
+        ALOGD("Not upload time. now:%ld, pre:%ld", now, report_time_);
+        return;
+    }
+
+    if (!ReadFileToString(path.c_str(), &file_contents)) {
+        ALOGE("Unable to read %s - %s", path.c_str(), strerror(errno));
+        return;
+    }
+    ALOGD("checkAndReport: %s", file_contents.c_str());
+
+    int16_t i, num;
+    struct BatteryHistory hist;
+    const int kHistTotalLen = strlen(file_contents.c_str());
+
+    for (i = 0; i < (LINESIZE * BATT_HIST_NUM_MAX); i = i + LINESIZE) {
+        if (i + LINESIZE > kHistTotalLen)
+            break;
+        history_each = file_contents.substr(i, LINESIZE);
+        num = sscanf(history_each.c_str(),
+                   "%4" SCNx16 "%4" SCNx16 "%4" SCNx16 "%4" SCNx16
+                   "%2" SCNx8 "%2" SCNx8 " %2" SCNx8 "%2" SCNx8
+                   "%2" SCNx8 "%2" SCNx8 " %2" SCNx8 "%2" SCNx8
+                   "%2" SCNx8 "%2" SCNx8 " %4" SCNx16 "%4" SCNx16
+                   "%4" SCNx16 "%4" SCNx16 "%4" SCNx16,
+                   &hist.cycle_cnt, &hist.full_cap, &hist.esr,
+                   &hist.rslow, &hist.batt_temp, &hist.soh,
+                   &hist.cc_soc, &hist.cutoff_soc, &hist.msoc,
+                   &hist.sys_soc, &hist.reserve, &hist.batt_soc,
+                   &hist.min_temp, &hist.max_temp,  &hist.max_vbatt,
+                   &hist.min_vbatt, &hist.max_ibatt, &hist.min_ibatt,
+                   &hist.checksum);
+
+        if (num != kNumBatteryHistoryFields) {
+            ALOGE("Couldn't process %s", history_each.c_str());
+            continue;
+        }
+
+        if (checkLogEvent(hist)) {
+            reportEvent(hist);
+            report_time_ = getTimeSecs();
+        }
+    }
+}
+
+int64_t BatteryEEPROMReporter::getTimeSecs(void) {
+    return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
+}
+
+/**
+ * @return true if a log should be reported, else false.
+ * Here we use checksum to confirm the data is usable or not.
+ * The checksum mismatch when storage data overflow or corrupt.
+ * We don't need data in such cases.
+ */
+bool BatteryEEPROMReporter::checkLogEvent(struct BatteryHistory hist) {
+    int checksum = 0;
+
+    checksum = hist.cycle_cnt + hist.full_cap + hist.esr + hist.rslow
+                + hist.soh + hist.batt_temp + hist.cutoff_soc + hist.cc_soc
+                + hist.sys_soc + hist.msoc + hist.batt_soc + hist.reserve
+                + hist.max_temp + hist.min_temp + hist.max_vbatt
+                + hist.min_vbatt + hist.max_ibatt + hist.min_ibatt;
+    /* Compare with checksum data */
+    if (checksum == hist.checksum) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void BatteryEEPROMReporter::reportEvent(struct BatteryHistory hist) {
+       sp<IStats> stats_client = IStats::tryGetService();
+       // upload atom
+       std::vector<int> eeprom_history_fields = {BatteryEEPROM::kCycleCntFieldNumber,
+                                                 BatteryEEPROM::kFullCapFieldNumber,
+                                                 BatteryEEPROM::kEsrFieldNumber,
+                                                 BatteryEEPROM::kRslowFieldNumber,
+                                                 BatteryEEPROM::kSohFieldNumber,
+                                                 BatteryEEPROM::kBattTempFieldNumber,
+                                                 BatteryEEPROM::kCutoffSocFieldNumber,
+                                                 BatteryEEPROM::kCcSocFieldNumber,
+                                                 BatteryEEPROM::kSysSocFieldNumber,
+                                                 BatteryEEPROM::kMsocFieldNumber,
+                                                 BatteryEEPROM::kBattSocFieldNumber,
+                                                 BatteryEEPROM::kReserveFieldNumber,
+                                                 BatteryEEPROM::kMaxTempFieldNumber,
+                                                 BatteryEEPROM::kMinTempFieldNumber,
+                                                 BatteryEEPROM::kMaxVbattFieldNumber,
+                                                 BatteryEEPROM::kMinVbattFieldNumber,
+                                                 BatteryEEPROM::kMaxIbattFieldNumber,
+                                                 BatteryEEPROM::kMinIbattFieldNumber,
+                                                 BatteryEEPROM::kChecksumFieldNumber};
+       std::vector<VendorAtom::Value> values(eeprom_history_fields.size());
+       VendorAtom::Value val;
+
+       ALOGD("reportEvent: cycle_cnt:%d, full_cap:%d, esr:%d, rslow:%d, soh:%d, "
+             "batt_temp:%d, cutoff_soc:%d, cc_soc:%d, sys_soc:%d, msoc:%d, "
+             "batt_soc:%d, reserve:%d, max_temp:%d, min_temp:%d, max_vbatt:%d, "
+             "min_vbatt:%d, max_ibatt:%d, min_ibatt:%d, checksum:%d",
+             hist.cycle_cnt, hist.full_cap, hist.esr, hist.rslow, hist.soh,
+             hist.batt_temp, hist.cutoff_soc, hist.cc_soc, hist.sys_soc,
+             hist.msoc, hist.batt_soc, hist.reserve, hist.max_temp,
+             hist.min_temp, hist.max_vbatt, hist.min_vbatt, hist.max_ibatt,
+             hist.min_ibatt, hist.checksum);
+
+       val.intValue(hist.cycle_cnt);
+       values[BatteryEEPROM::kCycleCntFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.full_cap);
+       values[BatteryEEPROM::kFullCapFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.esr);
+       values[BatteryEEPROM::kEsrFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.rslow);
+       values[BatteryEEPROM::kRslowFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.soh);
+       values[BatteryEEPROM::kSohFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.batt_temp);
+       values[BatteryEEPROM::kBattTempFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.cutoff_soc);
+       values[BatteryEEPROM::kCutoffSocFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.cc_soc);
+       values[BatteryEEPROM::kCcSocFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.sys_soc);
+       values[BatteryEEPROM::kSysSocFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.msoc);
+       values[BatteryEEPROM::kMsocFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.batt_soc);
+       values[BatteryEEPROM::kBattSocFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.reserve);
+       values[BatteryEEPROM::kReserveFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.max_temp);
+       values[BatteryEEPROM::kMaxTempFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.min_temp);
+       values[BatteryEEPROM::kMinTempFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.max_vbatt);
+       values[BatteryEEPROM::kMaxVbattFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.min_vbatt);
+       values[BatteryEEPROM::kMinVbattFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.max_ibatt);
+       values[BatteryEEPROM::kMaxIbattFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.min_ibatt);
+       values[BatteryEEPROM::kMinIbattFieldNumber - kVendorAtomOffset] = val;
+       val.intValue(hist.checksum);
+       values[BatteryEEPROM::kChecksumFieldNumber - kVendorAtomOffset] = val;
+
+       VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
+                        .atomId = PixelAtoms::Ids::BATTERY_EEPROM,
+                        .values = values};
+       Return<void> ret = stats_client->reportVendorAtom(event);
+       if (!ret.isOk())
+           ALOGE("Unable to report BatteryEEPROM to Stats service");
+}
+
+
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
diff --git a/pixelstats/SysfsCollector.cpp b/pixelstats/SysfsCollector.cpp
index bf1e3d5..29b3509 100644
--- a/pixelstats/SysfsCollector.cpp
+++ b/pixelstats/SysfsCollector.cpp
@@ -72,7 +72,8 @@
       kF2fsStatsPath(sysfs_paths.F2fsStatsPath),
       kUserdataBlockProp(sysfs_paths.UserdataBlockProp),
       kZramMmStatPath("/sys/block/zram0/mm_stat"),
-      kZramBdStatPath("/sys/block/zram0/bd_stat") {}
+      kZramBdStatPath("/sys/block/zram0/bd_stat"),
+      kEEPROMPath(sysfs_paths.EEPROMPath) {}
 
 bool SysfsCollector::ReadFileToInt(const std::string &path, int *val) {
     return ReadFileToInt(path.c_str(), val);
@@ -126,6 +127,18 @@
 }
 
 /**
+ * Read the contents of kEEPROMPath and report them.
+ */
+void SysfsCollector::logBatteryEEPROM() {
+    if (kEEPROMPath == nullptr || strlen(kEEPROMPath) == 0) {
+        ALOGV("Battery EEPROM path not specified");
+        return;
+    }
+
+    battery_EEPROM_reporter_.checkAndReport(kEEPROMPath);
+}
+
+/**
  * Check the codec for failures over the past 24hr.
  */
 void SysfsCollector::logCodecFailed() {
@@ -599,6 +612,7 @@
     logUFSLifetime();
     logF2fsStats();
     logZramStats();
+    logBatteryEEPROM();
 
     stats_.clear();
 }
diff --git a/pixelstats/include/pixelstats/BatteryEEPROMReporter.h b/pixelstats/include/pixelstats/BatteryEEPROMReporter.h
new file mode 100644
index 0000000..e3ff997
--- /dev/null
+++ b/pixelstats/include/pixelstats/BatteryEEPROMReporter.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_GOOGLE_PIXEL_PIXELSTATS_BATTERYEEPROMREPORTER_H
+#define HARDWARE_GOOGLE_PIXEL_PIXELSTATS_BATTERYEEPROMREPORTER_H
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+// The storage for save whole history is 928 byte
+// each history contains 19 items with total size 28 byte
+// hence the history number is 928/28~33
+#define BATT_HIST_NUM_MAX	33
+
+/**
+ * A class to upload battery EEPROM metrics
+ */
+class BatteryEEPROMReporter {
+  public:
+    BatteryEEPROMReporter();
+    void checkAndReport(const std::string &path);
+
+  private:
+    // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so
+    // store everything in the values array at the index of the field number
+    // -2.
+    const int kVendorAtomOffset = 2;
+
+    struct BatteryHistory {
+        /* The cycle count number; record of charge/discharge times */
+        uint16_t cycle_cnt;
+        /* The current full capacity of the battery under nominal conditions */
+        uint16_t full_cap;
+        /* The battery equivalent series resistance */
+        uint16_t esr;
+        /* Battery resistance related to temperature change */
+        uint16_t rslow;
+        /* Battery health indicator reflecting the battery age state */
+        uint8_t soh;
+        /* The battery temperature */
+        int8_t batt_temp;
+
+        /* Battery state of charge (SOC) shutdown point */
+        uint8_t cutoff_soc;
+        /* Raw battery state of charge (SOC), based on battery current (CC = Coulomb Counter) */
+        uint8_t cc_soc;
+        /* Estimated battery state of charge (SOC) from batt_soc with endpoint limiting (0% and 100%) */
+        uint8_t sys_soc;
+        /* Filtered monotonic SOC, handles situations where the cutoff_soc is increased and
+         * then decreased from the battery physical properties
+         */
+        uint8_t msoc;
+        /* Estimated SOC derived from cc_soc that provides voltage loop feedback correction using
+         * battery voltage, current, and status values
+         */
+        uint8_t batt_soc;
+
+        /* Field used for data padding in the EEPROM data */
+        uint8_t reserve;
+
+        /* The maximum battery temperature ever seen */
+        int8_t max_temp;
+        /* The minimum battery temperature ever seen */
+        int8_t min_temp;
+        /* The maximum battery voltage ever seen */
+        uint16_t max_vbatt;
+        /* The minimum battery voltage ever seen */
+        uint16_t min_vbatt;
+        /* The maximum battery current ever seen */
+        int16_t max_ibatt;
+        /* The minimum battery current ever seen */
+        int16_t min_ibatt;
+        /* Field used to verify the integrity of the EEPROM data */
+        uint16_t checksum;
+    };
+    /* The number of elements in struct BatteryHistory */
+    const int kNumBatteryHistoryFields = 19;
+
+    int64_t report_time_ = 0;
+    int64_t getTimeSecs();
+
+    bool checkLogEvent(struct BatteryHistory hist);
+    void reportEvent(struct BatteryHistory hist);
+};
+
+}  // namespace pixel
+}  // namespace google
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_BATTERYEEPROMREPORTER_H
diff --git a/pixelstats/include/pixelstats/SysfsCollector.h b/pixelstats/include/pixelstats/SysfsCollector.h
index c6cc608..bbe116f 100644
--- a/pixelstats/include/pixelstats/SysfsCollector.h
+++ b/pixelstats/include/pixelstats/SysfsCollector.h
@@ -20,6 +20,8 @@
 #include <android/frameworks/stats/1.0/IStats.h>
 #include <utils/StrongPointer.h>
 
+#include "BatteryEEPROMReporter.h"
+
 using android::sp;
 using android::frameworks::stats::V1_0::IStats;
 using android::frameworks::stats::V1_0::SlowIo;
@@ -50,6 +52,7 @@
         const char *const UserdataBlockProp;
         const char *const ZramMmStatPath;
         const char *const ZramBdStatPath;
+        const char *const EEPROMPath;
     };
 
     SysfsCollector(const struct SysfsPaths &paths);
@@ -71,6 +74,7 @@
     void logF2fsStats();
     void logZramStats();
     void logBootStats();
+    void logBatteryEEPROM();
 
     void reportSlowIoFromFile(const char *path, const SlowIo::IoOperation &operation_s);
     void reportZramMmStat();
@@ -96,8 +100,11 @@
     const char *const kUserdataBlockProp;
     const char *const kZramMmStatPath;
     const char *const kZramBdStatPath;
+    const char *const kEEPROMPath;
     sp<IStats> stats_;
 
+    BatteryEEPROMReporter battery_EEPROM_reporter_;
+
     // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so
     // store everything in the values array at the index of the field number
     // -2.
diff --git a/pixelstats/pixelatoms.proto b/pixelstats/pixelatoms.proto
index 857e66f..a920783 100644
--- a/pixelstats/pixelatoms.proto
+++ b/pixelstats/pixelatoms.proto
@@ -46,6 +46,8 @@
     DEVICE_ORIENTATION = 105009;
     FG_CAPACITY = 105010;
     PD_VID_PID = 105011;
+    BATTERY_EEPROM = 105012;
+
     // AOSP atom ID range ends at 109999
 }
 
@@ -257,3 +259,51 @@
     /* Product ID of wired charger */
     optional int32 pid = 3;
 }
+
+message BatteryEEPROM {
+    /* The cycle count number; record of charge/discharge times */
+    optional int32 cycle_cnt = 2;
+    /* The current full capacity of the battery under nominal conditions */
+    optional int32 full_cap = 3;
+    /* The battery equivalent series resistance */
+    optional int32 esr = 4;
+    /* Battery resistance related to temperature change */
+    optional int32 rslow = 5;
+    /* Battery health indicator reflecting the battery age state */
+    optional int32 soh = 6;
+    /* The battery temperature */
+    optional int32 batt_temp = 7;
+
+    /* Battery state of charge (SOC) shutdown point */
+    optional int32 cutoff_soc = 8;
+    /* Raw battery state of charge (SOC), based on battery current (CC = Coulomb Counter) */
+    optional int32 cc_soc = 9;
+    /* Estimated battery state of charge (SOC) from batt_soc with endpoint limiting (0% and 100%) */
+    optional int32 sys_soc = 10;
+    /* Filtered monotonic SOC, handles situations where the cutoff_soc is increased and
+     * then decreased from the battery physical properties
+     */
+    optional int32 msoc = 11;
+    /* Estimated SOC derived from cc_soc that provides voltage loop feedback correction using
+     * battery voltage, current, and status values
+     */
+    optional int32 batt_soc = 12;
+
+    /* Field used for data padding in the EEPROM data */
+    optional int32 reserve = 13;
+
+    /* The maximum battery temperature ever seen */
+    optional int32 max_temp = 14;
+    /* The minimum battery temperature ever seen */
+    optional int32 min_temp = 15;
+    /* The maximum battery voltage ever seen */
+    optional int32 max_vbatt = 16;
+    /* The minimum battery voltage ever seen */
+    optional int32 min_vbatt = 17;
+    /* The maximum battery current ever seen */
+    optional int32 max_ibatt = 18;
+    /* The minimum battery current ever seen */
+    optional int32 min_ibatt = 19;
+    /* Field used to verify the integrity of the EEPROM data */
+    optional int32 checksum = 20;
+}