On low power turn off rather than rebooting to allow device to charge

The code was using encrypted_upto == 0 as an indicator that encryption
has succeeded. This meant that if no encryption happened, we would reboot
continually.

We now set encrypted_upto to fs_size when encryption is complete.

Also don't start to encrypt unless we are at 10% power. Stop when we
get to 5% power. This should lead to partial encryptions only very
rarely.

Bug: 15513202
Change-Id: I6214d78579d1fbbe2f63ee8862473d86a89d29b3
diff --git a/CheckBattery.cpp b/CheckBattery.cpp
index 8a674d0..f689bb4 100644
--- a/CheckBattery.cpp
+++ b/CheckBattery.cpp
@@ -26,6 +26,13 @@
 {
     // How often to check battery in seconds
     const int CHECK_PERIOD = 30;
+
+    // How charged should the battery be (percent) to start encrypting
+    const int START_THRESHOLD = 10;
+
+    // How charged should the battery be (percent) to continue encrypting
+    const int CONTINUE_THRESHOLD = 5;
+
     const String16 serviceName("batteryproperties");
 
     sp<IBinder> bs;
@@ -33,43 +40,59 @@
 
     bool singletonInitialized = false;
     time_t last_checked = {0};
-    int battery_ok = 1;
+    int last_result = 100;
+
+    int is_battery_ok(int threshold)
+    {
+        time_t now = time(NULL);
+        if (now == -1 || difftime(now, last_checked) < 5) {
+            goto finish;
+        }
+        last_checked = now;
+
+        if (!singletonInitialized) {
+            bs = defaultServiceManager()->checkService(serviceName);
+            if (bs == NULL) {
+                SLOGE("No batteryproperties service!");
+                goto finish;
+            }
+
+            interface = interface_cast<IBatteryPropertiesRegistrar>(bs);
+            if (interface == NULL) {
+                SLOGE("No IBatteryPropertiesRegistrar interface");
+                goto finish;
+            }
+
+            singletonInitialized = true;
+        }
+
+        {
+            BatteryProperty val;
+            status_t status = interface
+                ->getProperty(android::BATTERY_PROP_CAPACITY, &val);
+            if (status == NO_ERROR) {
+                SLOGD("Capacity is %d", (int)val.valueInt64);
+                last_result = val.valueInt64;
+            } else {
+                SLOGE("Failed to get battery charge");
+                last_result = 100;
+            }
+        }
+
+    finish:
+        return last_result >= threshold;
+    }
 }
 
-extern "C" int is_battery_ok()
+extern "C"
 {
-    time_t now = time(NULL);
-    if (now == -1 || difftime(now, last_checked) < 5) {
-        return battery_ok;
-    }
-    last_checked = now;
-
-    if (!singletonInitialized) {
-        bs = defaultServiceManager()->checkService(serviceName);
-        if (bs == NULL) {
-            SLOGE("No batteryproperties service!");
-            return 1;
-        }
-
-        interface = interface_cast<IBatteryPropertiesRegistrar>(bs);
-        if (interface == NULL) {
-            SLOGE("No IBatteryPropertiesRegistrar interface");
-            return 1;
-        }
-
-        singletonInitialized = true;
+    int is_battery_ok_to_start()
+    {
+        return is_battery_ok(START_THRESHOLD);
     }
 
-    BatteryProperty val;
-    status_t status = interface->getProperty(android::BATTERY_PROP_CAPACITY,
-                                             &val);
-    if (status == NO_ERROR) {
-        SLOGD("Capacity is %d", (int)val.valueInt64);
-        battery_ok = val.valueInt64 > 5 ? 1 : 0;
-    } else {
-        SLOGE("Failed to get battery charge");
-        battery_ok = 1;
+    int is_battery_ok_to_continue()
+    {
+        return is_battery_ok(CONTINUE_THRESHOLD);
     }
-
-    return battery_ok;
 }
diff --git a/CheckBattery.h b/CheckBattery.h
index a7bff34..dd11ba9 100644
--- a/CheckBattery.h
+++ b/CheckBattery.h
@@ -21,7 +21,8 @@
 extern "C" {
 #endif
 
-int is_battery_ok();
+int is_battery_ok_to_start();
+int is_battery_ok_to_continue();
 
 #ifdef __cplusplus
 }
diff --git a/cryptfs.c b/cryptfs.c
index 8680698..fc4259c 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -2049,7 +2049,7 @@
                 }
             }
 
-            if (!is_battery_ok()) {
+            if (!is_battery_ok_to_continue()) {
                 SLOGE("Stopping encryption due to low battery");
                 rc = 0;
                 goto errout;
@@ -2231,7 +2231,7 @@
                   i * CRYPT_SECTORS_PER_BUFSIZE);
         }
 
-       if (!is_battery_ok()) {
+       if (!is_battery_ok_to_continue()) {
             SLOGE("Stopping encryption due to low battery");
             *size_already_done += (i + 1) * CRYPT_SECTORS_PER_BUFSIZE - 1;
             rc = 0;
@@ -2332,8 +2332,8 @@
     off64_t cur_encryption_done=0, tot_encryption_size=0;
     int i, rc = -1;
 
-    if (!is_battery_ok()) {
-        SLOGE("Stopping encryption due to low battery");
+    if (!is_battery_ok_to_start()) {
+        SLOGW("Not starting encryption due to low battery");
         return 0;
     }
 
@@ -2348,11 +2348,11 @@
                                     tot_encryption_size,
                                     previously_encrypted_upto);
 
-        if (!rc && cur_encryption_done != (off64_t)crypt_ftr->fs_size) {
+        if (!rc) {
             crypt_ftr->encrypted_upto = cur_encryption_done;
         }
 
-        if (!rc && !crypt_ftr->encrypted_upto) {
+        if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) {
             /* The inplace routine never actually sets the progress to 100% due
              * to the round down nature of integer division, so set it here */
             property_set("vold.encrypt_progress", "100");
@@ -2601,10 +2601,10 @@
     }
 
     /* Calculate checksum if we are not finished */
-    if (!rc && crypt_ftr.encrypted_upto) {
+    if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
         rc = cryptfs_SHA256_fileblock(crypto_blkdev,
                                       crypt_ftr.hash_first_block);
-        if (!rc) {
+        if (rc) {
             SLOGE("Error calculating checksum for continuing encryption");
             rc = -1;
         }
@@ -2618,19 +2618,22 @@
     if (! rc) {
         /* Success */
 
-        /* Clear the encryption in progres flag in the footer */
-        if (!crypt_ftr.encrypted_upto) {
+        /* Clear the encryption in progress flag in the footer */
+        if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
             crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
         } else {
             SLOGD("Encrypted up to sector %lld - will continue after reboot",
                   crypt_ftr.encrypted_upto);
         }
-        put_crypt_ftr_and_key(&crypt_ftr);
+
+        if (crypt_ftr.encrypted_upto) {
+            put_crypt_ftr_and_key(&crypt_ftr);
+        }
 
         sleep(2); /* Give the UI a chance to show 100% progress */
                   /* Partially encrypted - ensure writes are flushed to ssd */
 
-        if (!crypt_ftr.encrypted_upto) {
+        if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
             cryptfs_reboot(reboot);
         } else {
             cryptfs_reboot(shutdown);