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