• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "BatteryStatsService"
18 //#define LOG_NDEBUG 0
19 
20 #include <climits>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <semaphore.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <unordered_map>
32 #include <utility>
33 
34 #include <android/hardware/power/1.0/IPower.h>
35 #include <android/hardware/power/1.1/IPower.h>
36 #include <android/hardware/power/stats/1.0/IPowerStats.h>
37 #include <android/system/suspend/BnSuspendCallback.h>
38 #include <android/system/suspend/ISuspendControlService.h>
39 #include <android_runtime/AndroidRuntime.h>
40 #include <jni.h>
41 
42 #include <nativehelper/ScopedLocalRef.h>
43 #include <nativehelper/ScopedPrimitiveArray.h>
44 
45 #include <log/log.h>
46 #include <utils/misc.h>
47 #include <utils/Log.h>
48 
49 using android::hardware::Return;
50 using android::hardware::Void;
51 using android::system::suspend::BnSuspendCallback;
52 using android::hardware::power::V1_0::PowerStatePlatformSleepState;
53 using android::hardware::power::V1_0::PowerStateVoter;
54 using android::hardware::power::V1_0::Status;
55 using android::hardware::power::V1_1::PowerStateSubsystem;
56 using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
57 using android::hardware::hidl_vec;
58 using android::system::suspend::ISuspendControlService;
59 using IPowerV1_1 = android::hardware::power::V1_1::IPower;
60 using IPowerV1_0 = android::hardware::power::V1_0::IPower;
61 
62 namespace android
63 {
64 
65 #define LAST_RESUME_REASON "/sys/kernel/wakeup_reasons/last_resume_reason"
66 #define MAX_REASON_SIZE 512
67 
68 static bool wakeup_init = false;
69 static sem_t wakeup_sem;
70 extern sp<IPowerV1_0> getPowerHalHidlV1_0();
71 extern sp<IPowerV1_1> getPowerHalHidlV1_1();
72 extern bool processPowerHalReturn(bool isOk, const char* functionName);
73 extern sp<ISuspendControlService> getSuspendControl();
74 
75 // Java methods used in getLowPowerStats
76 static jmethodID jgetAndUpdatePlatformState = NULL;
77 static jmethodID jgetSubsystem = NULL;
78 static jmethodID jputVoter = NULL;
79 static jmethodID jputState = NULL;
80 
81 std::mutex gPowerHalMutex;
82 std::unordered_map<uint32_t, std::string> gPowerStatsHalEntityNames = {};
83 std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>>
84     gPowerStatsHalStateNames = {};
85 std::vector<uint32_t> gPowerStatsHalPlatformIds = {};
86 std::vector<uint32_t> gPowerStatsHalSubsystemIds = {};
87 sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
88 std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
89 std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
90 std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
91 
92 // Cellular/Wifi power monitor rail information
93 static jmethodID jupdateRailData = NULL;
94 static jmethodID jsetRailStatsAvailability = NULL;
95 
96 std::function<void(JNIEnv*, jobject)> gGetRailEnergyPowerStatsImpl = {};
97 
98 std::unordered_map<uint32_t, std::pair<std::string, std::string>> gPowerStatsHalRailNames = {};
99 static bool power_monitor_available = false;
100 
101 // The caller must be holding gPowerHalMutex.
deinitPowerStatsLocked()102 static void deinitPowerStatsLocked() {
103     gPowerStatsHalV1_0 = nullptr;
104 }
105 
106 struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient {
serviceDiedandroid::PowerHalDeathRecipient107     virtual void serviceDied(uint64_t cookie,
108             const wp<android::hidl::base::V1_0::IBase>& who) override {
109         // The HAL just died. Reset all handles to HAL services.
110         std::lock_guard<std::mutex> lock(gPowerHalMutex);
111         deinitPowerStatsLocked();
112     }
113 };
114 
115 sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
116 
117 class WakeupCallback : public BnSuspendCallback {
118    public:
notifyWakeup(bool success)119     binder::Status notifyWakeup(bool success) override {
120         ALOGI("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
121         int ret = sem_post(&wakeup_sem);
122         if (ret < 0) {
123             char buf[80];
124             strerror_r(errno, buf, sizeof(buf));
125             ALOGE("Error posting wakeup sem: %s\n", buf);
126         }
127         return binder::Status::ok();
128     }
129 };
130 
nativeWaitWakeup(JNIEnv * env,jobject clazz,jobject outBuf)131 static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
132 {
133     if (outBuf == NULL) {
134         jniThrowException(env, "java/lang/NullPointerException", "null argument");
135         return -1;
136     }
137 
138     // Register our wakeup callback if not yet done.
139     if (!wakeup_init) {
140         wakeup_init = true;
141         ALOGV("Creating semaphore...");
142         int ret = sem_init(&wakeup_sem, 0, 0);
143         if (ret < 0) {
144             char buf[80];
145             strerror_r(errno, buf, sizeof(buf));
146             ALOGE("Error creating semaphore: %s\n", buf);
147             jniThrowException(env, "java/lang/IllegalStateException", buf);
148             return -1;
149         }
150         sp<ISuspendControlService> suspendControl = getSuspendControl();
151         bool isRegistered = false;
152         suspendControl->registerCallback(new WakeupCallback(), &isRegistered);
153         if (!isRegistered) {
154             ALOGE("Failed to register wakeup callback");
155         }
156     }
157 
158     // Wait for wakeup.
159     ALOGV("Waiting for wakeup...");
160     // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup
161     // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events.
162     int ret = sem_wait(&wakeup_sem);
163     if (ret < 0) {
164         char buf[80];
165         strerror_r(errno, buf, sizeof(buf));
166         ALOGE("Error waiting on semaphore: %s\n", buf);
167         // Return 0 here to let it continue looping but not return results.
168         return 0;
169     }
170 
171     FILE *fp = fopen(LAST_RESUME_REASON, "r");
172     if (fp == NULL) {
173         ALOGE("Failed to open %s", LAST_RESUME_REASON);
174         return -1;
175     }
176 
177     char* mergedreason = (char*)env->GetDirectBufferAddress(outBuf);
178     int remainreasonlen = (int)env->GetDirectBufferCapacity(outBuf);
179 
180     ALOGV("Reading wakeup reasons");
181     char* mergedreasonpos = mergedreason;
182     char reasonline[128];
183     int i = 0;
184     while (fgets(reasonline, sizeof(reasonline), fp) != NULL) {
185         char* pos = reasonline;
186         char* endPos;
187         int len;
188         // First field is the index or 'Abort'.
189         int irq = (int)strtol(pos, &endPos, 10);
190         if (pos != endPos) {
191             // Write the irq number to the merged reason string.
192             len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq);
193         } else {
194             // The first field is not an irq, it may be the word Abort.
195             const size_t abortPrefixLen = strlen("Abort:");
196             if (strncmp(pos, "Abort:", abortPrefixLen) != 0) {
197                 // Ooops.
198                 ALOGE("Bad reason line: %s", reasonline);
199                 continue;
200             }
201 
202             // Write 'Abort' to the merged reason string.
203             len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "Abort" : ":Abort");
204             endPos = pos + abortPrefixLen;
205         }
206         pos = endPos;
207 
208         if (len >= 0 && len < remainreasonlen) {
209             mergedreasonpos += len;
210             remainreasonlen -= len;
211         }
212 
213         // Skip whitespace; rest of the buffer is the reason string.
214         while (*pos == ' ') {
215             pos++;
216         }
217 
218         // Chop newline at end.
219         char* endpos = pos;
220         while (*endpos != 0) {
221             if (*endpos == '\n') {
222                 *endpos = 0;
223                 break;
224             }
225             endpos++;
226         }
227 
228         len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos);
229         if (len >= 0 && len < remainreasonlen) {
230             mergedreasonpos += len;
231             remainreasonlen -= len;
232         }
233         i++;
234     }
235 
236     ALOGV("Got %d reasons", i);
237     if (i > 0) {
238         *mergedreasonpos = 0;
239     }
240 
241     if (fclose(fp) != 0) {
242         ALOGE("Failed to close %s", LAST_RESUME_REASON);
243         return -1;
244     }
245     return mergedreasonpos - mergedreason;
246 }
247 
248 // The caller must be holding gPowerHalMutex.
checkResultLocked(const Return<void> & ret,const char * function)249 static bool checkResultLocked(const Return<void> &ret, const char* function) {
250     if (!ret.isOk()) {
251         ALOGE("%s failed: requested HAL service not available. Description: %s",
252             function, ret.description().c_str());
253         if (ret.isDeadObject()) {
254             deinitPowerStatsLocked();
255         }
256         return false;
257     }
258     return true;
259 }
260 
261 // The caller must be holding gPowerHalMutex.
262 // gPowerStatsHalV1_0 must not be null
initializePowerStats()263 static bool initializePowerStats() {
264     using android::hardware::power::stats::V1_0::Status;
265     using android::hardware::power::stats::V1_0::PowerEntityType;
266 
267     // Clear out previous content if we are re-initializing
268     gPowerStatsHalEntityNames.clear();
269     gPowerStatsHalStateNames.clear();
270     gPowerStatsHalPlatformIds.clear();
271     gPowerStatsHalSubsystemIds.clear();
272     gPowerStatsHalRailNames.clear();
273 
274     Return<void> ret;
275     ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
276         if (status != Status::SUCCESS) {
277             ALOGE("Error getting power entity info");
278             return;
279         }
280 
281         // construct lookup table of powerEntityId to power entity name
282         // also construct vector of platform and subsystem IDs
283         for (auto info : infos) {
284             gPowerStatsHalEntityNames.emplace(info.powerEntityId, info.powerEntityName);
285             if (info.type == PowerEntityType::POWER_DOMAIN) {
286                 gPowerStatsHalPlatformIds.emplace_back(info.powerEntityId);
287             } else {
288                 gPowerStatsHalSubsystemIds.emplace_back(info.powerEntityId);
289             }
290         }
291     });
292     if (!checkResultLocked(ret, __func__)) {
293         return false;
294     }
295 
296     ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
297         if (status != Status::SUCCESS) {
298             ALOGE("Error getting state info");
299             return;
300         }
301 
302         // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
303         for (auto stateSpace : stateSpaces) {
304             std::unordered_map<uint32_t, std::string> stateNames = {};
305             for (auto state : stateSpace.states) {
306                 stateNames.emplace(state.powerEntityStateId,
307                     state.powerEntityStateName);
308             }
309             gPowerStatsHalStateNames.emplace(stateSpace.powerEntityId, stateNames);
310         }
311     });
312     if (!checkResultLocked(ret, __func__)) {
313         return false;
314     }
315 
316     // Get Power monitor rails available
317     ret = gPowerStatsHalV1_0->getRailInfo([](auto rails, auto status) {
318         if (status != Status::SUCCESS) {
319             ALOGW("Rail information is not available");
320             power_monitor_available = false;
321             return;
322         }
323 
324         // Fill out rail names/subsystems into gPowerStatsHalRailNames
325         for (auto rail : rails) {
326             gPowerStatsHalRailNames.emplace(rail.index,
327                 std::make_pair(rail.railName, rail.subsysName));
328         }
329         if (!gPowerStatsHalRailNames.empty()) {
330             power_monitor_available = true;
331         }
332     });
333     if (!checkResultLocked(ret, __func__)) {
334         return false;
335     }
336 
337     return (!gPowerStatsHalEntityNames.empty()) && (!gPowerStatsHalStateNames.empty());
338 }
339 
340 // The caller must be holding gPowerHalMutex.
getPowerStatsHalLocked()341 static bool getPowerStatsHalLocked() {
342     if (gPowerStatsHalV1_0 == nullptr) {
343         gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
344         if (gPowerStatsHalV1_0 == nullptr) {
345             ALOGE("Unable to get power.stats HAL service.");
346             return false;
347         }
348 
349         // Link death recipient to power.stats service handle
350         hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
351         if (!linked.isOk()) {
352             ALOGE("Transaction error in linking to power.stats HAL death: %s",
353                     linked.description().c_str());
354             deinitPowerStatsLocked();
355             return false;
356         } else if (!linked) {
357             ALOGW("Unable to link to power.stats HAL death notifications");
358             // We should still continue even though linking failed
359         }
360         return initializePowerStats();
361     }
362     return true;
363 }
364 
365 // The caller must be holding powerHalMutex.
getPowerStatsHalLowPowerData(JNIEnv * env,jobject jrpmStats)366 static void getPowerStatsHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
367     using android::hardware::power::stats::V1_0::Status;
368 
369     if (!getPowerStatsHalLocked()) {
370         ALOGE("failed to get low power stats");
371         return;
372     }
373 
374     // Get power entity state residency data
375     bool success = false;
376     Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
377         [&env, &jrpmStats, &success](auto results, auto status) {
378             if (status == Status::NOT_SUPPORTED) {
379                 ALOGW("getPowerEntityStateResidencyData is not supported");
380                 success = false;
381                 return;
382             }
383 
384             for (auto result : results) {
385                 jobject jsubsystem = env->CallObjectMethod(jrpmStats, jgetSubsystem,
386                     env->NewStringUTF(gPowerStatsHalEntityNames.at(result.powerEntityId).c_str()));
387                 if (jsubsystem == NULL) {
388                     ALOGE("The rpmstats jni jobject jsubsystem is null.");
389                     return;
390                 }
391                 for (auto stateResidency : result.stateResidencyData) {
392 
393                     env->CallVoidMethod(jsubsystem, jputState,
394                         env->NewStringUTF(gPowerStatsHalStateNames.at(result.powerEntityId)
395                         .at(stateResidency.powerEntityStateId).c_str()),
396                         stateResidency.totalTimeInStateMs,
397                         stateResidency.totalStateEntryCount);
398                 }
399             }
400             success = true;
401         });
402     checkResultLocked(ret, __func__);
403     if (!success) {
404         ALOGE("getPowerEntityStateResidencyData failed");
405     }
406 }
407 
getPowerStatsHalPlatformData(JNIEnv * env,jobject outBuf)408 static jint getPowerStatsHalPlatformData(JNIEnv* env, jobject outBuf) {
409     using android::hardware::power::stats::V1_0::Status;
410     using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
411     using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
412 
413     if (!getPowerStatsHalLocked()) {
414         ALOGE("failed to get low power stats");
415         return -1;
416     }
417 
418     char *output = (char*)env->GetDirectBufferAddress(outBuf);
419     char *offset = output;
420     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
421     int total_added = -1;
422 
423     // Get power entity state residency data
424     Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
425         gPowerStatsHalPlatformIds,
426         [&offset, &remaining, &total_added](auto results, auto status) {
427             if (status == Status::NOT_SUPPORTED) {
428                 ALOGW("getPowerEntityStateResidencyData is not supported");
429                 return;
430             }
431 
432             for (size_t i = 0; i < results.size(); i++) {
433                 const PowerEntityStateResidencyResult& result = results[i];
434 
435                 for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
436                     const PowerEntityStateResidencyData& stateResidency =
437                         result.stateResidencyData[j];
438                     int added = snprintf(offset, remaining,
439                         "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
440                         j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
441                            .at(stateResidency.powerEntityStateId).c_str(),
442                         stateResidency.totalTimeInStateMs,
443                         stateResidency.totalStateEntryCount);
444                     if (added < 0) {
445                         break;
446                     }
447                     if (added > remaining) {
448                         added = remaining;
449                     }
450                     offset += added;
451                     remaining -= added;
452                     total_added += added;
453                 }
454                 if (remaining <= 0) {
455                     /* rewrite NULL character*/
456                     offset--;
457                     total_added--;
458                     ALOGE("power.stats Hal: buffer not enough");
459                     break;
460                 }
461             }
462         });
463     if (!checkResultLocked(ret, __func__)) {
464         return -1;
465     }
466 
467     total_added += 1;
468     return total_added;
469 }
470 
getPowerStatsHalSubsystemData(JNIEnv * env,jobject outBuf)471 static jint getPowerStatsHalSubsystemData(JNIEnv* env, jobject outBuf) {
472     using android::hardware::power::stats::V1_0::Status;
473     using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
474     using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
475 
476     if (!getPowerStatsHalLocked()) {
477         ALOGE("failed to get low power stats");
478         return -1;
479     }
480 
481     char *output = (char*)env->GetDirectBufferAddress(outBuf);
482     char *offset = output;
483     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
484     int total_added = -1;
485 
486     // Get power entity state residency data
487     Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
488         gPowerStatsHalSubsystemIds,
489         [&offset, &remaining, &total_added](auto results, auto status) {
490             if (status == Status::NOT_SUPPORTED) {
491                 ALOGW("getPowerEntityStateResidencyData is not supported");
492                 return;
493             }
494 
495             int added = snprintf(offset, remaining, "SubsystemPowerState ");
496             offset += added;
497             remaining -= added;
498             total_added += added;
499 
500             for (size_t i = 0; i < results.size(); i++) {
501                 const PowerEntityStateResidencyResult& result = results[i];
502                 added = snprintf(offset, remaining, "subsystem_%zu name=%s ",
503                         i + 1, gPowerStatsHalEntityNames.at(result.powerEntityId).c_str());
504                 if (added < 0) {
505                     break;
506                 }
507 
508                 if (added > remaining) {
509                     added = remaining;
510                 }
511 
512                 offset += added;
513                 remaining -= added;
514                 total_added += added;
515 
516                 for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
517                     const PowerEntityStateResidencyData& stateResidency =
518                         result.stateResidencyData[j];
519                     added = snprintf(offset, remaining,
520                         "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry=%"
521                         PRIu64 " ", j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
522                            .at(stateResidency.powerEntityStateId).c_str(),
523                         stateResidency.totalTimeInStateMs,
524                         stateResidency.totalStateEntryCount,
525                         stateResidency.lastEntryTimestampMs);
526                     if (added < 0) {
527                         break;
528                     }
529                     if (added > remaining) {
530                         added = remaining;
531                     }
532                     offset += added;
533                     remaining -= added;
534                     total_added += added;
535                 }
536                 if (remaining <= 0) {
537                     /* rewrite NULL character*/
538                     offset--;
539                     total_added--;
540                     ALOGE("power.stats Hal: buffer not enough");
541                     break;
542                 }
543             }
544         });
545     if (!checkResultLocked(ret, __func__)) {
546         return -1;
547     }
548 
549     total_added += 1;
550     return total_added;
551 }
552 
getPowerStatsHalRailEnergyData(JNIEnv * env,jobject jrailStats)553 static void getPowerStatsHalRailEnergyData(JNIEnv* env, jobject jrailStats) {
554     using android::hardware::power::stats::V1_0::Status;
555     using android::hardware::power::stats::V1_0::EnergyData;
556 
557     if (!getPowerStatsHalLocked()) {
558         ALOGE("failed to get power stats");
559         return;
560     }
561 
562     if (!power_monitor_available) {
563         env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
564         ALOGW("Rail energy data is not available");
565         return;
566     }
567 
568     // Get power rail energySinceBoot data
569     Return<void> ret = gPowerStatsHalV1_0->getEnergyData({},
570         [&env, &jrailStats](auto energyData, auto status) {
571             if (status == Status::NOT_SUPPORTED) {
572                 ALOGW("getEnergyData is not supported");
573                 return;
574             }
575 
576             for (auto data : energyData) {
577                 if (!(data.timestamp > LLONG_MAX || data.energy > LLONG_MAX)) {
578                     env->CallVoidMethod(jrailStats,
579                         jupdateRailData,
580                         data.index,
581                         env->NewStringUTF(
582                             gPowerStatsHalRailNames.at(data.index).first.c_str()),
583                         env->NewStringUTF(
584                             gPowerStatsHalRailNames.at(data.index).second.c_str()),
585                         data.timestamp,
586                         data.energy);
587                 } else {
588                     ALOGE("Java long overflow seen. Rail index %d not updated", data.index);
589                 }
590             }
591         });
592     if (!checkResultLocked(ret, __func__)) {
593         ALOGE("getEnergyData failed");
594     }
595 }
596 
597 // The caller must be holding powerHalMutex.
getPowerHalLowPowerData(JNIEnv * env,jobject jrpmStats)598 static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
599     sp<IPowerV1_0> powerHalV1_0 = getPowerHalHidlV1_0();
600     if (powerHalV1_0 == nullptr) {
601         ALOGE("Power Hal not loaded");
602         return;
603     }
604 
605     Return<void> ret = powerHalV1_0->getPlatformLowPowerStats(
606             [&env, &jrpmStats](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
607 
608             if (status != Status::SUCCESS) return;
609 
610             for (size_t i = 0; i < states.size(); i++) {
611                 const PowerStatePlatformSleepState& state = states[i];
612 
613                 jobject jplatformState = env->CallObjectMethod(jrpmStats,
614                         jgetAndUpdatePlatformState,
615                         env->NewStringUTF(state.name.c_str()),
616                         state.residencyInMsecSinceBoot,
617                         state.totalTransitions);
618                 if (jplatformState == NULL) {
619                     ALOGE("The rpmstats jni jobject jplatformState is null.");
620                     return;
621                 }
622 
623                 for (size_t j = 0; j < state.voters.size(); j++) {
624                     const PowerStateVoter& voter = state.voters[j];
625                     env->CallVoidMethod(jplatformState, jputVoter,
626                             env->NewStringUTF(voter.name.c_str()),
627                             voter.totalTimeInMsecVotedForSinceBoot,
628                             voter.totalNumberOfTimesVotedSinceBoot);
629                 }
630             }
631     });
632     if (!processPowerHalReturn(ret.isOk(), "getPlatformLowPowerStats")) {
633         return;
634     }
635 
636     // Trying to get IPower 1.1, this will succeed only for devices supporting 1.1
637     sp<IPowerV1_1> powerHal_1_1 = getPowerHalHidlV1_1();
638     if (powerHal_1_1 == nullptr) {
639         // This device does not support IPower@1.1, exiting gracefully
640         return;
641     }
642     ret = powerHal_1_1->getSubsystemLowPowerStats(
643             [&env, &jrpmStats](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
644 
645         if (status != Status::SUCCESS) return;
646 
647         if (subsystems.size() > 0) {
648             for (size_t i = 0; i < subsystems.size(); i++) {
649                 const PowerStateSubsystem &subsystem = subsystems[i];
650 
651                 jobject jsubsystem = env->CallObjectMethod(jrpmStats, jgetSubsystem,
652                         env->NewStringUTF(subsystem.name.c_str()));
653                 if (jsubsystem == NULL) {
654                     ALOGE("The rpmstats jni jobject jsubsystem is null.");
655                     return;
656                 }
657 
658                 for (size_t j = 0; j < subsystem.states.size(); j++) {
659                     const PowerStateSubsystemSleepState& state = subsystem.states[j];
660                     env->CallVoidMethod(jsubsystem, jputState,
661                             env->NewStringUTF(state.name.c_str()),
662                             state.residencyInMsecSinceBoot,
663                             state.totalTransitions);
664                 }
665             }
666         }
667     });
668     processPowerHalReturn(ret.isOk(), "getSubsystemLowPowerStats");
669 }
670 
getPowerHalPlatformData(JNIEnv * env,jobject outBuf)671 static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
672     char *output = (char*)env->GetDirectBufferAddress(outBuf);
673     char *offset = output;
674     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
675     int total_added = -1;
676 
677     {
678         sp<IPowerV1_0> powerHalV1_0 = getPowerHalHidlV1_0();
679         if (powerHalV1_0 == nullptr) {
680             ALOGE("Power Hal not loaded");
681             return -1;
682         }
683 
684         Return<void> ret = powerHalV1_0->getPlatformLowPowerStats(
685             [&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
686                     Status status) {
687                 if (status != Status::SUCCESS)
688                     return;
689                 for (size_t i = 0; i < states.size(); i++) {
690                     int added;
691                     const PowerStatePlatformSleepState& state = states[i];
692 
693                     added = snprintf(offset, remaining,
694                         "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
695                         i + 1, state.name.c_str(), state.residencyInMsecSinceBoot,
696                         state.totalTransitions);
697                     if (added < 0) {
698                         break;
699                     }
700                     if (added > remaining) {
701                         added = remaining;
702                     }
703                     offset += added;
704                     remaining -= added;
705                     total_added += added;
706 
707                     for (size_t j = 0; j < state.voters.size(); j++) {
708                         const PowerStateVoter& voter = state.voters[j];
709                         added = snprintf(offset, remaining,
710                                 "voter_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
711                                 j + 1, voter.name.c_str(),
712                                 voter.totalTimeInMsecVotedForSinceBoot,
713                                 voter.totalNumberOfTimesVotedSinceBoot);
714                         if (added < 0) {
715                             break;
716                         }
717                         if (added > remaining) {
718                             added = remaining;
719                         }
720                         offset += added;
721                         remaining -= added;
722                         total_added += added;
723                     }
724 
725                     if (remaining <= 0) {
726                         /* rewrite NULL character*/
727                         offset--;
728                         total_added--;
729                         ALOGE("PowerHal: buffer not enough");
730                         break;
731                     }
732                 }
733             }
734         );
735 
736         if (!processPowerHalReturn(ret.isOk(), "getPlatformLowPowerStats")) {
737             return -1;
738         }
739     }
740     *offset = 0;
741     total_added += 1;
742     return total_added;
743 }
744 
getPowerHalSubsystemData(JNIEnv * env,jobject outBuf)745 static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
746     char *output = (char*)env->GetDirectBufferAddress(outBuf);
747     char *offset = output;
748     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
749     int total_added = -1;
750 
751     // This is a IPower 1.1 API
752     sp<IPowerV1_1> powerHal_1_1 = nullptr;
753 
754     {
755         // Trying to get 1.1, this will succeed only for devices supporting 1.1
756         powerHal_1_1 = getPowerHalHidlV1_1();
757         if (powerHal_1_1 == nullptr) {
758             //This device does not support IPower@1.1, exiting gracefully
759             return 0;
760         }
761 
762         Return<void> ret = powerHal_1_1->getSubsystemLowPowerStats(
763            [&offset, &remaining, &total_added](hidl_vec<PowerStateSubsystem> subsystems,
764                 Status status) {
765 
766             if (status != Status::SUCCESS)
767                 return;
768 
769             if (subsystems.size() > 0) {
770                 int added = snprintf(offset, remaining, "SubsystemPowerState ");
771                 offset += added;
772                 remaining -= added;
773                 total_added += added;
774 
775                 for (size_t i = 0; i < subsystems.size(); i++) {
776                     const PowerStateSubsystem &subsystem = subsystems[i];
777 
778                     added = snprintf(offset, remaining,
779                                      "subsystem_%zu name=%s ", i + 1, subsystem.name.c_str());
780                     if (added < 0) {
781                         break;
782                     }
783 
784                     if (added > remaining) {
785                         added = remaining;
786                     }
787 
788                     offset += added;
789                     remaining -= added;
790                     total_added += added;
791 
792                     for (size_t j = 0; j < subsystem.states.size(); j++) {
793                         const PowerStateSubsystemSleepState& state = subsystem.states[j];
794                         added = snprintf(offset, remaining,
795                                          "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry=%" PRIu64 " ",
796                                          j + 1, state.name.c_str(), state.residencyInMsecSinceBoot,
797                                          state.totalTransitions, state.lastEntryTimestampMs);
798                         if (added < 0) {
799                             break;
800                         }
801 
802                         if (added > remaining) {
803                             added = remaining;
804                         }
805 
806                         offset += added;
807                         remaining -= added;
808                         total_added += added;
809                     }
810 
811                     if (remaining <= 0) {
812                         /* rewrite NULL character*/
813                         offset--;
814                         total_added--;
815                         ALOGE("PowerHal: buffer not enough");
816                         break;
817                     }
818                 }
819             }
820         }
821         );
822 
823         if (!processPowerHalReturn(ret.isOk(), "getSubsystemLowPowerStats")) {
824             return -1;
825         }
826     }
827 
828     *offset = 0;
829     total_added += 1;
830     return total_added;
831 }
832 
setUpPowerStatsLocked()833 static void setUpPowerStatsLocked() {
834     // First see if power.stats HAL is available. Fall back to power HAL if
835     // power.stats HAL is unavailable.
836     if (android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
837         ALOGI("Using power.stats HAL");
838         gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
839         gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;
840         gGetSubsystemLowPowerStatsImpl = getPowerStatsHalSubsystemData;
841         gGetRailEnergyPowerStatsImpl = getPowerStatsHalRailEnergyData;
842     } else if (android::hardware::power::V1_0::IPower::getService() != nullptr) {
843         ALOGI("Using power HAL");
844         gGetLowPowerStatsImpl = getPowerHalLowPowerData;
845         gGetPlatformLowPowerStatsImpl = getPowerHalPlatformData;
846         gGetSubsystemLowPowerStatsImpl = getPowerHalSubsystemData;
847         gGetRailEnergyPowerStatsImpl = NULL;
848     }
849 }
850 
getLowPowerStats(JNIEnv * env,jobject,jobject jrpmStats)851 static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats) {
852     if (jrpmStats == NULL) {
853         jniThrowException(env, "java/lang/NullPointerException",
854                 "The rpmstats jni input jobject jrpmStats is null.");
855         return;
856     }
857     if (jgetAndUpdatePlatformState == NULL || jgetSubsystem == NULL
858             || jputVoter == NULL || jputState == NULL) {
859         ALOGE("A rpmstats jni jmethodID is null.");
860         return;
861     }
862 
863     std::lock_guard<std::mutex> lock(gPowerHalMutex);
864 
865     if (!gGetLowPowerStatsImpl) {
866         setUpPowerStatsLocked();
867     }
868 
869     if (gGetLowPowerStatsImpl) {
870         return gGetLowPowerStatsImpl(env, jrpmStats);
871     }
872 
873     ALOGE("Unable to load Power Hal or power.stats HAL");
874     return;
875 }
876 
getPlatformLowPowerStats(JNIEnv * env,jobject,jobject outBuf)877 static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
878     if (outBuf == NULL) {
879         jniThrowException(env, "java/lang/NullPointerException", "null argument");
880         return -1;
881     }
882 
883     std::lock_guard<std::mutex> lock(gPowerHalMutex);
884 
885     if (!gGetPlatformLowPowerStatsImpl) {
886         setUpPowerStatsLocked();
887     }
888 
889     if (gGetPlatformLowPowerStatsImpl) {
890         return gGetPlatformLowPowerStatsImpl(env, outBuf);
891     }
892 
893     ALOGE("Unable to load Power Hal or power.stats HAL");
894     return -1;
895 }
896 
getSubsystemLowPowerStats(JNIEnv * env,jobject,jobject outBuf)897 static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
898     if (outBuf == NULL) {
899         jniThrowException(env, "java/lang/NullPointerException", "null argument");
900         return -1;
901     }
902 
903     std::lock_guard<std::mutex> lock(gPowerHalMutex);
904 
905     if (!gGetSubsystemLowPowerStatsImpl) {
906         setUpPowerStatsLocked();
907     }
908 
909     if (gGetSubsystemLowPowerStatsImpl) {
910         return gGetSubsystemLowPowerStatsImpl(env, outBuf);
911     }
912 
913     ALOGE("Unable to load Power Hal or power.stats HAL");
914     return -1;
915 }
916 
getRailEnergyPowerStats(JNIEnv * env,jobject,jobject jrailStats)917 static void getRailEnergyPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrailStats) {
918     if (jrailStats == NULL) {
919         jniThrowException(env, "java/lang/NullPointerException",
920                 "The railstats jni input jobject jrailStats is null.");
921         return;
922     }
923     if (jupdateRailData == NULL) {
924         ALOGE("A railstats jni jmethodID is null.");
925         return;
926     }
927 
928     std::lock_guard<std::mutex> lock(gPowerHalMutex);
929 
930     if (!gGetRailEnergyPowerStatsImpl) {
931         setUpPowerStatsLocked();
932     }
933 
934     if (gGetRailEnergyPowerStatsImpl)  {
935         gGetRailEnergyPowerStatsImpl(env, jrailStats);
936         return;
937     }
938 
939     if (jsetRailStatsAvailability == NULL) {
940         ALOGE("setRailStatsAvailability jni jmethodID is null.");
941         return;
942     }
943     env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
944     ALOGE("Unable to load Power.Stats.HAL. Setting rail availability to false");
945     return;
946 }
947 
948 static const JNINativeMethod method_table[] = {
949     { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
950     { "getLowPowerStats", "(Lcom/android/internal/os/RpmStats;)V", (void*)getLowPowerStats },
951     { "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
952     { "getSubsystemLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getSubsystemLowPowerStats },
953     { "getRailEnergyPowerStats", "(Lcom/android/internal/os/RailStats;)V",
954         (void*)getRailEnergyPowerStats },
955 };
956 
register_android_server_BatteryStatsService(JNIEnv * env)957 int register_android_server_BatteryStatsService(JNIEnv *env)
958 {
959     // get java classes and methods
960     jclass clsRpmStats = env->FindClass("com/android/internal/os/RpmStats");
961     jclass clsPowerStatePlatformSleepState =
962             env->FindClass("com/android/internal/os/RpmStats$PowerStatePlatformSleepState");
963     jclass clsPowerStateSubsystem =
964             env->FindClass("com/android/internal/os/RpmStats$PowerStateSubsystem");
965     jclass clsRailStats = env->FindClass("com/android/internal/os/RailStats");
966     if (clsRpmStats == NULL || clsPowerStatePlatformSleepState == NULL
967             || clsPowerStateSubsystem == NULL || clsRailStats == NULL) {
968         ALOGE("A rpmstats jni jclass is null.");
969     } else {
970         jgetAndUpdatePlatformState = env->GetMethodID(clsRpmStats, "getAndUpdatePlatformState",
971                 "(Ljava/lang/String;JI)Lcom/android/internal/os/RpmStats$PowerStatePlatformSleepState;");
972         jgetSubsystem = env->GetMethodID(clsRpmStats, "getSubsystem",
973                 "(Ljava/lang/String;)Lcom/android/internal/os/RpmStats$PowerStateSubsystem;");
974         jputVoter = env->GetMethodID(clsPowerStatePlatformSleepState, "putVoter",
975                 "(Ljava/lang/String;JI)V");
976         jputState = env->GetMethodID(clsPowerStateSubsystem, "putState",
977                 "(Ljava/lang/String;JI)V");
978         jupdateRailData = env->GetMethodID(clsRailStats, "updateRailData",
979                 "(JLjava/lang/String;Ljava/lang/String;JJ)V");
980         jsetRailStatsAvailability = env->GetMethodID(clsRailStats, "setRailStatsAvailability",
981                 "(Z)V");
982     }
983 
984     return jniRegisterNativeMethods(env, "com/android/server/am/BatteryStatsService",
985             method_table, NELEM(method_table));
986 }
987 
988 };
989