Bug 758103 - Return charging time of zero if no battery interface exists. r=mounir, r=dhylands
authorThomas Zimmermann <tdz@users.sourceforge.net>
Thu, 29 Nov 2012 20:18:46 +0100
changeset 121904 52557de563d79a9582558ae51b1304325268fd95
parent 121903 9a99043b80e7a1901776e663187b7e8bccd06e48
child 121905 87ec624190f251450623789c9f315e721fe7202a
push idunknown
push userunknown
push dateunknown
reviewersmounir, dhylands
bugs758103
milestone20.0a1
Bug 758103 - Return charging time of zero if no battery interface exists. r=mounir, r=dhylands On the PandaBoard, and probably other platforms, no battery exists and the related kernel interfaces are missing. The HAL returns 'charging' at a battery level of 100%. The charging time is set to 'unknown'. This is inconsistent according to the battery manager. With this patch, the returned charging time is set to zero, which fulfills the battery manager's requirements. The patch also cleans up and simplifies the source code.
hal/gonk/GonkHal.cpp
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -349,68 +349,139 @@ UnregisterBatteryObserverIOThread()
 void
 DisableBatteryNotifications()
 {
   XRE_GetIOMessageLoop()->PostTask(
       FROM_HERE,
       NewRunnableFunction(UnregisterBatteryObserverIOThread));
 }
 
-void
-GetCurrentBatteryInformation(hal::BatteryInformation *aBatteryInfo)
+// See bug 819016 about moving the ReadSysFile functions to a
+// central location.
+static bool
+ReadSysFile(const char *aFilename, char *aBuf, size_t aBufSize,
+            size_t *aBytesRead = NULL)
+{
+  int fd = TEMP_FAILURE_RETRY(open(aFilename, O_RDONLY));
+  if (fd < 0) {
+    HAL_LOG(("Unable to open file '%s' for reading", aFilename));
+    return false;
+  }
+  ScopedClose autoClose(fd);
+  ssize_t bytesRead = TEMP_FAILURE_RETRY(read(fd, aBuf, aBufSize - 1));
+  if (bytesRead < 0) {
+    HAL_LOG(("Unable to read from file '%s'", aFilename));
+    return false;
+  }
+  if (bytesRead && (aBuf[bytesRead - 1] == '\n')) {
+    bytesRead--;
+  }
+  aBuf[bytesRead] = '\0';
+  if (aBytesRead) {
+    *aBytesRead = bytesRead;
+  }
+  return true;
+}
+
+static bool
+ReadSysFile(const char *aFilename, int *aVal)
+{
+  char valBuf[20];
+  if (!ReadSysFile(aFilename, valBuf, sizeof(valBuf))) {
+    return false;
+  }
+  return sscanf(valBuf, "%d", aVal) == 1;
+}
+
+static bool
+GetCurrentBatteryCharge(int* aCharge)
+{
+  bool success = ReadSysFile("/sys/class/power_supply/battery/capacity",
+                             aCharge);
+  if (!success) {
+    return false;
+  }
+
+  #ifdef DEBUG
+  if ((*aCharge < 0) || (*aCharge > 100)) {
+    HAL_LOG(("charge level containes unknown value: %d", *aCharge));
+  }
+  #endif
+
+  return (*aCharge >= 0) && (*aCharge <= 100);
+}
+
+static bool
+GetCurrentBatteryCharging(int* aCharging)
 {
   static const int BATTERY_NOT_CHARGING = 0;
   static const int BATTERY_CHARGING_USB = 1;
   static const int BATTERY_CHARGING_AC  = 2;
 
-  FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r");
-  double capacity = dom::battery::kDefaultLevel * 100;
-  if (capacityFile) {
-    fscanf(capacityFile, "%lf", &capacity);
-    fclose(capacityFile);
-  }
+  // Generic device support
+
+  int chargingSrc;
+  bool success =
+    ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc);
 
-  FILE *chargingFile = fopen("/sys/class/power_supply/battery/charging_source", "r");
-  int chargingSrc = BATTERY_CHARGING_USB;
-  bool done = false;
-  if (chargingFile) {
-    fscanf(chargingFile, "%d", &chargingSrc);
-    fclose(chargingFile);
-    done = true;
+  if (success) {
+    #ifdef DEBUG
+    if (chargingSrc != BATTERY_NOT_CHARGING &&
+        chargingSrc != BATTERY_CHARGING_USB &&
+        chargingSrc != BATTERY_CHARGING_AC) {
+      HAL_LOG(("charging_source contained unknown value: %d", chargingSrc));
+    }
+    #endif
+
+    *aCharging = (chargingSrc == BATTERY_CHARGING_USB ||
+                  chargingSrc == BATTERY_CHARGING_AC);
+    return true;
   }
 
-  if (!done) {
-    // toro devices support
-    chargingFile = fopen("/sys/class/power_supply/battery/status", "r");
-    if (chargingFile) {
-      char status[16];
-      char *str = fgets(status, sizeof(status), chargingFile);
-      if (str && (!strcmp(str, "Charging\n") || !strcmp(str, "Full\n"))) {
-        // no way here to know if we're charging from USB or AC.
-        chargingSrc = BATTERY_CHARGING_USB;
-      } else {
-        chargingSrc = BATTERY_NOT_CHARGING;
-      }
-      fclose(chargingFile);
-      done = true;
-    }
+  // Otoro device support
+
+  char chargingSrcString[16];
+  size_t chargingSrcLen;
+
+  success = ReadSysFile("/sys/class/power_supply/battery/status",
+                        chargingSrcString, sizeof(chargingSrcString),
+                        &chargingSrcLen);
+  if (success) {
+    *aCharging = !memcmp(chargingSrcString, "Charging", chargingSrcLen) ||
+                 !memcmp(chargingSrcString, "Full", chargingSrcLen);
+    return true;
   }
 
-  #ifdef DEBUG
-  if (chargingSrc != BATTERY_NOT_CHARGING &&
-      chargingSrc != BATTERY_CHARGING_USB &&
-      chargingSrc != BATTERY_CHARGING_AC) {
-    HAL_LOG(("charging_source contained unknown value: %d", chargingSrc));
+  return false;
+}
+
+void
+GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
+{
+  int charge;
+
+  if (GetCurrentBatteryCharge(&charge)) {
+    aBatteryInfo->level() = (double)charge / 100.0;
+  } else {
+    aBatteryInfo->level() = dom::battery::kDefaultLevel;
   }
-  #endif
+
+  int charging;
 
-  aBatteryInfo->level() = capacity / 100;
-  aBatteryInfo->charging() = (chargingSrc == BATTERY_CHARGING_USB ||
-                              chargingSrc == BATTERY_CHARGING_AC);
-  aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+  if (GetCurrentBatteryCharging(&charging)) {
+    aBatteryInfo->charging() = charging;
+  } else {
+    aBatteryInfo->charging() = true;
+  }
+
+  if (aBatteryInfo->charging() && (aBatteryInfo->level() < 1.0)) {
+    aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+  } else {
+    aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
+  }
 }
 
 namespace {
 
 /**
  * RAII class to help us remember to close file descriptors.
  */
 const char *wakeLockFilename = "/sys/power/wake_lock";