blob: 491c5ab2ac03aeccb57ccca73e7fe667589dd42d [file] [log] [blame]
Wei Wangbad7c202018-11-01 11:57:39 -07001/*
2 * Copyright (C) 2018 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
17package com.android.server.power;
18
Wei Wang37b17542018-11-12 11:02:09 -080019import android.annotation.Nullable;
Wei Wangbad7c202018-11-01 11:57:39 -070020import android.content.Context;
21import android.hardware.thermal.V1_0.ThermalStatus;
22import android.hardware.thermal.V1_0.ThermalStatusCode;
23import android.hardware.thermal.V1_1.IThermalCallback;
24import android.hardware.thermal.V2_0.IThermalChangedCallback;
25import android.hardware.thermal.V2_0.ThrottlingSeverity;
26import android.os.Binder;
Wei Wang38e5bd72019-04-03 14:58:42 -070027import android.os.CoolingDevice;
Wei Wangbad7c202018-11-01 11:57:39 -070028import android.os.HwBinder;
29import android.os.IThermalEventListener;
30import android.os.IThermalService;
Wei Wang37b17542018-11-12 11:02:09 -080031import android.os.IThermalStatusListener;
Wei Wangbad7c202018-11-01 11:57:39 -070032import android.os.PowerManager;
Wei Wangcc913612018-11-28 23:34:43 -080033import android.os.Process;
Wei Wangbad7c202018-11-01 11:57:39 -070034import android.os.RemoteCallbackList;
35import android.os.RemoteException;
Wei Wangcc913612018-11-28 23:34:43 -080036import android.os.ResultReceiver;
37import android.os.ShellCallback;
38import android.os.ShellCommand;
Wei Wang37b17542018-11-12 11:02:09 -080039import android.os.Temperature;
40import android.util.ArrayMap;
Wei Wangd8783892019-08-01 11:51:15 -070041import android.util.EventLog;
Wei Wangbad7c202018-11-01 11:57:39 -070042import android.util.Slog;
43
44import com.android.internal.annotations.GuardedBy;
Wei Wang37b17542018-11-12 11:02:09 -080045import com.android.internal.annotations.VisibleForTesting;
Wei Wangbad7c202018-11-01 11:57:39 -070046import com.android.internal.util.DumpUtils;
Wei Wangd8783892019-08-01 11:51:15 -070047import com.android.server.EventLogTags;
Wei Wangbad7c202018-11-01 11:57:39 -070048import com.android.server.FgThread;
49import com.android.server.SystemService;
50
51import java.io.FileDescriptor;
52import java.io.PrintWriter;
53import java.util.ArrayList;
Wei Wang37b17542018-11-12 11:02:09 -080054import java.util.Collection;
Wei Wang38e5bd72019-04-03 14:58:42 -070055import java.util.Iterator;
Wei Wangbad7c202018-11-01 11:57:39 -070056import java.util.List;
57import java.util.NoSuchElementException;
Wei Wang38e5bd72019-04-03 14:58:42 -070058import java.util.concurrent.atomic.AtomicBoolean;
Wei Wangbad7c202018-11-01 11:57:39 -070059
60/**
61 * This is a system service that listens to HAL thermal events and dispatch those to listeners.
62 * <p>The service will also trigger actions based on severity of the throttling status.</p>
63 *
64 * @hide
65 */
66public class ThermalManagerService extends SystemService {
67 private static final String TAG = ThermalManagerService.class.getSimpleName();
68
Wei Wang37b17542018-11-12 11:02:09 -080069 /** Lock to protect listen list. */
70 private final Object mLock = new Object();
71
72 /**
73 * Registered observers of the thermal events. Cookie is used to store type as Integer, null
74 * means no filter.
75 */
Wei Wangbad7c202018-11-01 11:57:39 -070076 @GuardedBy("mLock")
77 private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners =
78 new RemoteCallbackList<>();
79
Wei Wang37b17542018-11-12 11:02:09 -080080 /** Registered observers of the thermal status. */
Wei Wangbad7c202018-11-01 11:57:39 -070081 @GuardedBy("mLock")
Wei Wang37b17542018-11-12 11:02:09 -080082 private final RemoteCallbackList<IThermalStatusListener> mThermalStatusListeners =
83 new RemoteCallbackList<>();
Wei Wangbad7c202018-11-01 11:57:39 -070084
Wei Wang37b17542018-11-12 11:02:09 -080085 /** Current thermal status */
Wei Wangbad7c202018-11-01 11:57:39 -070086 @GuardedBy("mLock")
Wei Wang37b17542018-11-12 11:02:09 -080087 private int mStatus;
88
Wei Wangcc913612018-11-28 23:34:43 -080089 /** If override status takes effect*/
90 @GuardedBy("mLock")
91 private boolean mIsStatusOverride;
92
Wei Wang37b17542018-11-12 11:02:09 -080093 /** Current thermal map, key as name */
94 @GuardedBy("mLock")
95 private ArrayMap<String, Temperature> mTemperatureMap = new ArrayMap<>();
Wei Wangbad7c202018-11-01 11:57:39 -070096
Wei Wang37b17542018-11-12 11:02:09 -080097 /** HAL wrapper. */
98 private ThermalHalWrapper mHalWrapper;
99
100 /** Hal ready. */
Wei Wang38e5bd72019-04-03 14:58:42 -0700101 private final AtomicBoolean mHalReady = new AtomicBoolean();
Wei Wangbad7c202018-11-01 11:57:39 -0700102
Wei Wang37b17542018-11-12 11:02:09 -0800103 /** Invalid throttling status */
104 private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
Wei Wangbad7c202018-11-01 11:57:39 -0700105
106 public ThermalManagerService(Context context) {
Wei Wang37b17542018-11-12 11:02:09 -0800107 this(context, null);
108 }
109
110 @VisibleForTesting
111 ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) {
Wei Wangbad7c202018-11-01 11:57:39 -0700112 super(context);
Wei Wang37b17542018-11-12 11:02:09 -0800113 mHalWrapper = halWrapper;
114 // Initialize to invalid to send status onActivityManagerReady
115 mStatus = INVALID_THROTTLING;
Wei Wangbad7c202018-11-01 11:57:39 -0700116 }
117
Wei Wang37b17542018-11-12 11:02:09 -0800118 @Override
119 public void onStart() {
120 publishBinderService(Context.THERMAL_SERVICE, mService);
121 }
122
123 @Override
124 public void onBootPhase(int phase) {
125 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
126 onActivityManagerReady();
Wei Wangbad7c202018-11-01 11:57:39 -0700127 }
128 }
129
Wei Wang37b17542018-11-12 11:02:09 -0800130 private void onActivityManagerReady() {
Wei Wangbad7c202018-11-01 11:57:39 -0700131 synchronized (mLock) {
Wei Wang37b17542018-11-12 11:02:09 -0800132 // Connect to HAL and post to listeners.
133 boolean halConnected = (mHalWrapper != null);
134 if (!halConnected) {
135 mHalWrapper = new ThermalHal20Wrapper();
136 halConnected = mHalWrapper.connectToHal();
Wei Wangfb21bd82019-01-10 14:16:23 -0800137 }
138 if (!halConnected) {
139 mHalWrapper = new ThermalHal11Wrapper();
140 halConnected = mHalWrapper.connectToHal();
141 }
142 if (!halConnected) {
143 mHalWrapper = new ThermalHal10Wrapper();
144 halConnected = mHalWrapper.connectToHal();
Wei Wangbad7c202018-11-01 11:57:39 -0700145 }
Wei Wang37b17542018-11-12 11:02:09 -0800146 mHalWrapper.setCallback(this::onTemperatureChangedCallback);
147 if (!halConnected) {
148 return;
Wei Wangbad7c202018-11-01 11:57:39 -0700149 }
Wei Wang37b17542018-11-12 11:02:09 -0800150 List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(false,
151 0);
152 final int count = temperatures.size();
153 for (int i = 0; i < count; i++) {
154 onTemperatureChanged(temperatures.get(i), false);
Wei Wangbad7c202018-11-01 11:57:39 -0700155 }
Wei Wang37b17542018-11-12 11:02:09 -0800156 onTemperatureMapChangedLocked();
Wei Wang38e5bd72019-04-03 14:58:42 -0700157 mHalReady.set(true);
Wei Wangbad7c202018-11-01 11:57:39 -0700158 }
Wei Wangbad7c202018-11-01 11:57:39 -0700159 }
160
Wei Wang37b17542018-11-12 11:02:09 -0800161 private void postStatusListener(IThermalStatusListener listener) {
162 final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
163 try {
164 listener.onStatusChange(mStatus);
165 } catch (RemoteException | RuntimeException e) {
166 Slog.e(TAG, "Thermal callback failed to call", e);
167 }
168 });
169 if (!thermalCallbackQueued) {
170 Slog.e(TAG, "Thermal callback failed to queue");
171 }
172 }
173
174 private void notifyStatusListenersLocked() {
175 if (!Temperature.isValidStatus(mStatus)) {
176 return;
177 }
178 final int length = mThermalStatusListeners.beginBroadcast();
179 try {
180 for (int i = 0; i < length; i++) {
181 final IThermalStatusListener listener =
182 mThermalStatusListeners.getBroadcastItem(i);
183 postStatusListener(listener);
184 }
185 } finally {
186 mThermalStatusListeners.finishBroadcast();
187 }
188 }
189
190 private void onTemperatureMapChangedLocked() {
191 int newStatus = INVALID_THROTTLING;
192 final int count = mTemperatureMap.size();
193 for (int i = 0; i < count; i++) {
194 Temperature t = mTemperatureMap.valueAt(i);
195 if (t.getStatus() >= newStatus) {
196 newStatus = t.getStatus();
197 }
198 }
Wei Wangcc913612018-11-28 23:34:43 -0800199 // Do not update if override from shell
200 if (!mIsStatusOverride) {
201 setStatusLocked(newStatus);
202 }
203 }
204
205 private void setStatusLocked(int newStatus) {
Wei Wang37b17542018-11-12 11:02:09 -0800206 if (newStatus != mStatus) {
207 mStatus = newStatus;
208 notifyStatusListenersLocked();
209 }
210 }
211
Wei Wang37b17542018-11-12 11:02:09 -0800212 private void postEventListenerCurrentTemperatures(IThermalEventListener listener,
213 @Nullable Integer type) {
214 synchronized (mLock) {
215 final int count = mTemperatureMap.size();
216 for (int i = 0; i < count; i++) {
217 postEventListener(mTemperatureMap.valueAt(i), listener,
218 type);
219 }
220 }
221 }
222
223 private void postEventListener(Temperature temperature,
224 IThermalEventListener listener,
225 @Nullable Integer type) {
Wei Wangbad7c202018-11-01 11:57:39 -0700226 // Skip if listener registered with a different type
227 if (type != null && type != temperature.getType()) {
228 return;
229 }
230 final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
231 try {
232 listener.notifyThrottling(temperature);
233 } catch (RemoteException | RuntimeException e) {
234 Slog.e(TAG, "Thermal callback failed to call", e);
235 }
236 });
237 if (!thermalCallbackQueued) {
238 Slog.e(TAG, "Thermal callback failed to queue");
239 }
240 }
241
Wei Wang37b17542018-11-12 11:02:09 -0800242 private void notifyEventListenersLocked(Temperature temperature) {
243 final int length = mThermalEventListeners.beginBroadcast();
244 try {
245 for (int i = 0; i < length; i++) {
246 final IThermalEventListener listener =
247 mThermalEventListeners.getBroadcastItem(i);
248 final Integer type =
249 (Integer) mThermalEventListeners.getBroadcastCookie(i);
250 postEventListener(temperature, listener, type);
251 }
252 } finally {
253 mThermalEventListeners.finishBroadcast();
254 }
Wei Wangd8783892019-08-01 11:51:15 -0700255 EventLog.writeEvent(EventLogTags.THERMAL_CHANGED, temperature.getName(),
256 temperature.getType(), temperature.getValue(), temperature.getStatus(), mStatus);
Wei Wang37b17542018-11-12 11:02:09 -0800257 }
258
Wei Wang6942ff02019-03-11 10:22:33 -0700259 private void shutdownIfNeeded(Temperature temperature) {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800260 if (temperature.getStatus() != Temperature.THROTTLING_SHUTDOWN) {
261 return;
262 }
Wei Wang6942ff02019-03-11 10:22:33 -0700263 final PowerManager powerManager = getContext().getSystemService(PowerManager.class);
Wei Wangbc79c4f2018-12-10 11:40:40 -0800264 switch (temperature.getType()) {
265 case Temperature.TYPE_CPU:
266 // Fall through
267 case Temperature.TYPE_GPU:
268 // Fall through
269 case Temperature.TYPE_NPU:
270 // Fall through
271 case Temperature.TYPE_SKIN:
Wei Wang6942ff02019-03-11 10:22:33 -0700272 powerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
Wei Wangbc79c4f2018-12-10 11:40:40 -0800273 break;
274 case Temperature.TYPE_BATTERY:
Wei Wang6942ff02019-03-11 10:22:33 -0700275 powerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
Wei Wangbc79c4f2018-12-10 11:40:40 -0800276 break;
277 }
278 }
279
Wei Wang37b17542018-11-12 11:02:09 -0800280 private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
Wei Wang6942ff02019-03-11 10:22:33 -0700281 shutdownIfNeeded(temperature);
Wei Wangbad7c202018-11-01 11:57:39 -0700282 synchronized (mLock) {
Wei Wang37b17542018-11-12 11:02:09 -0800283 Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
284 if (old != null) {
285 if (old.getStatus() != temperature.getStatus()) {
286 notifyEventListenersLocked(temperature);
287 }
Wei Wangbad7c202018-11-01 11:57:39 -0700288 } else {
Wei Wang37b17542018-11-12 11:02:09 -0800289 notifyEventListenersLocked(temperature);
290 }
291 if (sendStatus) {
292 onTemperatureMapChangedLocked();
Wei Wangbad7c202018-11-01 11:57:39 -0700293 }
294 }
295 }
296
Wei Wangcc913612018-11-28 23:34:43 -0800297 /* HwBinder callback **/
Wei Wang37b17542018-11-12 11:02:09 -0800298 private void onTemperatureChangedCallback(Temperature temperature) {
Wei Wangcc913612018-11-28 23:34:43 -0800299 final long token = Binder.clearCallingIdentity();
300 try {
301 onTemperatureChanged(temperature, true);
302 } finally {
303 Binder.restoreCallingIdentity(token);
304 }
Wei Wangbad7c202018-11-01 11:57:39 -0700305 }
306
Wei Wang37b17542018-11-12 11:02:09 -0800307 @VisibleForTesting
308 final IThermalService.Stub mService = new IThermalService.Stub() {
Wei Wangbad7c202018-11-01 11:57:39 -0700309 @Override
Wei Wang37b17542018-11-12 11:02:09 -0800310 public boolean registerThermalEventListener(IThermalEventListener listener) {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800311 getContext().enforceCallingOrSelfPermission(
312 android.Manifest.permission.DEVICE_POWER, null);
Wei Wang37b17542018-11-12 11:02:09 -0800313 synchronized (mLock) {
314 final long token = Binder.clearCallingIdentity();
315 try {
316 if (!mThermalEventListeners.register(listener, null)) {
317 return false;
318 }
Wei Wang7edba732019-04-16 22:34:43 -0700319 // Notify its callback after new client registered.
320 postEventListenerCurrentTemperatures(listener, null);
Wei Wang37b17542018-11-12 11:02:09 -0800321 return true;
322 } finally {
323 Binder.restoreCallingIdentity(token);
324 }
325 }
326 }
327
328 @Override
329 public boolean registerThermalEventListenerWithType(IThermalEventListener listener,
330 int type) {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800331 getContext().enforceCallingOrSelfPermission(
332 android.Manifest.permission.DEVICE_POWER, null);
Wei Wang37b17542018-11-12 11:02:09 -0800333 synchronized (mLock) {
334 final long token = Binder.clearCallingIdentity();
335 try {
336 if (!mThermalEventListeners.register(listener, new Integer(type))) {
337 return false;
338 }
Wei Wang7edba732019-04-16 22:34:43 -0700339 // Notify its callback after new client registered.
340 postEventListenerCurrentTemperatures(listener, new Integer(type));
Wei Wang37b17542018-11-12 11:02:09 -0800341 return true;
342 } finally {
343 Binder.restoreCallingIdentity(token);
344 }
345 }
346 }
347
348 @Override
349 public boolean unregisterThermalEventListener(IThermalEventListener listener) {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800350 getContext().enforceCallingOrSelfPermission(
351 android.Manifest.permission.DEVICE_POWER, null);
Wei Wang37b17542018-11-12 11:02:09 -0800352 synchronized (mLock) {
353 final long token = Binder.clearCallingIdentity();
354 try {
355 return mThermalEventListeners.unregister(listener);
356 } finally {
357 Binder.restoreCallingIdentity(token);
358 }
359 }
360 }
361
362 @Override
363 public List<Temperature> getCurrentTemperatures() {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800364 getContext().enforceCallingOrSelfPermission(
365 android.Manifest.permission.DEVICE_POWER, null);
Wei Wang37b17542018-11-12 11:02:09 -0800366 final long token = Binder.clearCallingIdentity();
367 try {
Wei Wang38e5bd72019-04-03 14:58:42 -0700368 if (!mHalReady.get()) {
Wei Wang37b17542018-11-12 11:02:09 -0800369 return new ArrayList<>();
370 }
371 return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
372 } finally {
373 Binder.restoreCallingIdentity(token);
374 }
375 }
376
377 @Override
378 public List<Temperature> getCurrentTemperaturesWithType(int type) {
Wei Wangbc79c4f2018-12-10 11:40:40 -0800379 getContext().enforceCallingOrSelfPermission(
380 android.Manifest.permission.DEVICE_POWER, null);
Wei Wang37b17542018-11-12 11:02:09 -0800381 final long token = Binder.clearCallingIdentity();
382 try {
Wei Wang38e5bd72019-04-03 14:58:42 -0700383 if (!mHalReady.get()) {
Wei Wang37b17542018-11-12 11:02:09 -0800384 return new ArrayList<>();
385 }
386 return mHalWrapper.getCurrentTemperatures(true, type);
387 } finally {
388 Binder.restoreCallingIdentity(token);
389 }
390 }
391
392 @Override
393 public boolean registerThermalStatusListener(IThermalStatusListener listener) {
394 synchronized (mLock) {
395 // Notify its callback after new client registered.
396 final long token = Binder.clearCallingIdentity();
397 try {
398 if (!mThermalStatusListeners.register(listener)) {
399 return false;
400 }
Wei Wang7edba732019-04-16 22:34:43 -0700401 // Notify its callback after new client registered.
402 postStatusListener(listener);
Wei Wang37b17542018-11-12 11:02:09 -0800403 return true;
404 } finally {
405 Binder.restoreCallingIdentity(token);
406 }
407 }
408 }
409
410 @Override
411 public boolean unregisterThermalStatusListener(IThermalStatusListener listener) {
412 synchronized (mLock) {
413 final long token = Binder.clearCallingIdentity();
414 try {
415 return mThermalStatusListeners.unregister(listener);
416 } finally {
417 Binder.restoreCallingIdentity(token);
418 }
419 }
420 }
421
422 @Override
Wei Wangcc913612018-11-28 23:34:43 -0800423 public int getCurrentThermalStatus() {
Wei Wang37b17542018-11-12 11:02:09 -0800424 synchronized (mLock) {
425 final long token = Binder.clearCallingIdentity();
426 try {
427 return Temperature.isValidStatus(mStatus) ? mStatus
428 : Temperature.THROTTLING_NONE;
429 } finally {
430 Binder.restoreCallingIdentity(token);
431 }
432 }
433 }
434
435 @Override
Wei Wang38e5bd72019-04-03 14:58:42 -0700436 public List<CoolingDevice> getCurrentCoolingDevices() {
437 getContext().enforceCallingOrSelfPermission(
438 android.Manifest.permission.DEVICE_POWER, null);
439 final long token = Binder.clearCallingIdentity();
440 try {
441 if (!mHalReady.get()) {
442 return new ArrayList<>();
443 }
444 return mHalWrapper.getCurrentCoolingDevices(false, 0);
445 } finally {
446 Binder.restoreCallingIdentity(token);
447 }
448 }
449
450 @Override
451 public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) {
452 getContext().enforceCallingOrSelfPermission(
453 android.Manifest.permission.DEVICE_POWER, null);
454 final long token = Binder.clearCallingIdentity();
455 try {
456 if (!mHalReady.get()) {
457 return new ArrayList<>();
458 }
459 return mHalWrapper.getCurrentCoolingDevices(true, type);
460 } finally {
461 Binder.restoreCallingIdentity(token);
462 }
463 }
464
465 private void dumpItemsLocked(PrintWriter pw, String prefix,
466 Collection<?> items) {
467 for (Iterator iterator = items.iterator(); iterator.hasNext();) {
468 pw.println(prefix + iterator.next().toString());
469 }
470 }
471
472 @Override
Wei Wang37b17542018-11-12 11:02:09 -0800473 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
474 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
475 return;
476 }
477 final long token = Binder.clearCallingIdentity();
478 try {
Wei Wangbad7c202018-11-01 11:57:39 -0700479 synchronized (mLock) {
Wei Wang7f5dfba2018-12-11 11:32:00 -0800480 pw.println("IsStatusOverride: " + mIsStatusOverride);
Wei Wang37b17542018-11-12 11:02:09 -0800481 pw.println("ThermalEventListeners:");
482 mThermalEventListeners.dump(pw, "\t");
483 pw.println("ThermalStatusListeners:");
484 mThermalStatusListeners.dump(pw, "\t");
Wei Wang7f5dfba2018-12-11 11:32:00 -0800485 pw.println("Thermal Status: " + mStatus);
Wei Wang37b17542018-11-12 11:02:09 -0800486 pw.println("Cached temperatures:");
Wei Wang38e5bd72019-04-03 14:58:42 -0700487 dumpItemsLocked(pw, "\t", mTemperatureMap.values());
488 pw.println("HAL Ready: " + mHalReady.get());
489 if (mHalReady.get()) {
Wei Wang37b17542018-11-12 11:02:09 -0800490 pw.println("HAL connection:");
491 mHalWrapper.dump(pw, "\t");
492 pw.println("Current temperatures from HAL:");
Wei Wang38e5bd72019-04-03 14:58:42 -0700493 dumpItemsLocked(pw, "\t",
Wei Wang37b17542018-11-12 11:02:09 -0800494 mHalWrapper.getCurrentTemperatures(false, 0));
Wei Wang38e5bd72019-04-03 14:58:42 -0700495 pw.println("Current cooling devices from HAL:");
496 dumpItemsLocked(pw, "\t",
497 mHalWrapper.getCurrentCoolingDevices(false, 0));
Wei Wang37b17542018-11-12 11:02:09 -0800498 }
499 }
Wei Wang37b17542018-11-12 11:02:09 -0800500 } finally {
501 Binder.restoreCallingIdentity(token);
502 }
503 }
Wei Wangcc913612018-11-28 23:34:43 -0800504
505 private boolean isCallerShell() {
506 final int callingUid = Binder.getCallingUid();
507 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
508 }
509
510 @Override
511 public void onShellCommand(FileDescriptor in, FileDescriptor out,
512 FileDescriptor err, String[] args, ShellCallback callback,
513 ResultReceiver resultReceiver) {
514 if (!isCallerShell()) {
515 Slog.w(TAG, "Only shell is allowed to call thermalservice shell commands");
516 return;
517 }
518 (new ThermalShellCommand()).exec(
519 this, in, out, err, args, callback, resultReceiver);
520 }
521
Wei Wang37b17542018-11-12 11:02:09 -0800522 };
523
Wei Wangcc913612018-11-28 23:34:43 -0800524 class ThermalShellCommand extends ShellCommand {
525 @Override
526 public int onCommand(String cmd) {
527 switch(cmd != null ? cmd : "") {
528 case "override-status":
529 return runOverrideStatus();
530 case "reset":
531 return runReset();
532 default:
533 return handleDefaultCommands(cmd);
534 }
535 }
536
537 private int runReset() {
538 final long token = Binder.clearCallingIdentity();
539 try {
540 synchronized (mLock) {
541 mIsStatusOverride = false;
542 onTemperatureMapChangedLocked();
543 return 0;
544 }
545 } finally {
546 Binder.restoreCallingIdentity(token);
547 }
548 }
549
550 private int runOverrideStatus() {
551 final long token = Binder.clearCallingIdentity();
552 try {
553 final PrintWriter pw = getOutPrintWriter();
554 int status;
555 try {
556 status = Integer.parseInt(getNextArgRequired());
557 } catch (RuntimeException ex) {
558 pw.println("Error: " + ex.toString());
559 return -1;
560 }
561 if (!Temperature.isValidStatus(status)) {
Wei Wang7f5dfba2018-12-11 11:32:00 -0800562 pw.println("Invalid status: " + status);
Wei Wangcc913612018-11-28 23:34:43 -0800563 return -1;
564 }
565 synchronized (mLock) {
566 mIsStatusOverride = true;
567 setStatusLocked(status);
568 }
569 return 0;
570 } finally {
571 Binder.restoreCallingIdentity(token);
572 }
573 }
574
575 @Override
576 public void onHelp() {
577 final PrintWriter pw = getOutPrintWriter();
578 pw.println("Thermal service (thermalservice) commands:");
579 pw.println(" help");
580 pw.println(" Print this help text.");
581 pw.println("");
582 pw.println(" override-status STATUS");
583 pw.println(" sets and locks the thermal status of the device to STATUS.");
584 pw.println(" status code is defined in android.os.Temperature.");
585 pw.println(" reset");
586 pw.println(" unlocks the thermal status of the device.");
587 pw.println();
588 }
589 }
590
Wei Wang37b17542018-11-12 11:02:09 -0800591 abstract static class ThermalHalWrapper {
592 protected static final String TAG = ThermalHalWrapper.class.getSimpleName();
593
594 /** Lock to protect HAL handle. */
595 protected final Object mHalLock = new Object();
596
597 @FunctionalInterface
598 interface TemperatureChangedCallback {
599 void onValues(Temperature temperature);
600 }
601
602 /** Temperature callback. */
603 protected TemperatureChangedCallback mCallback;
604
605 /** Cookie for matching the right end point. */
606 protected static final int THERMAL_HAL_DEATH_COOKIE = 5612;
607
608 @VisibleForTesting
609 protected void setCallback(TemperatureChangedCallback cb) {
610 mCallback = cb;
611 }
612
613 protected abstract List<Temperature> getCurrentTemperatures(boolean shouldFilter,
614 int type);
615
Wei Wang38e5bd72019-04-03 14:58:42 -0700616 protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
617 int type);
618
Wei Wang37b17542018-11-12 11:02:09 -0800619 protected abstract boolean connectToHal();
620
621 protected abstract void dump(PrintWriter pw, String prefix);
622
623 protected void resendCurrentTemperatures() {
624 synchronized (mHalLock) {
625 List<Temperature> temperatures = getCurrentTemperatures(false, 0);
626 final int count = temperatures.size();
627 for (int i = 0; i < count; i++) {
628 mCallback.onValues(temperatures.get(i));
629 }
630 }
631 }
632
633 final class DeathRecipient implements HwBinder.DeathRecipient {
634 @Override
635 public void serviceDied(long cookie) {
636 if (cookie == THERMAL_HAL_DEATH_COOKIE) {
637 Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
638 synchronized (mHalLock) {
639 connectToHal();
640 // Post to listeners after reconnect to HAL.
641 resendCurrentTemperatures();
642 }
Wei Wangbad7c202018-11-01 11:57:39 -0700643 }
644 }
645 }
646 }
647
Wei Wangfb21bd82019-01-10 14:16:23 -0800648
649 static class ThermalHal10Wrapper extends ThermalHalWrapper {
650 /** Proxy object for the Thermal HAL 1.0 service. */
651 @GuardedBy("mHalLock")
652 private android.hardware.thermal.V1_0.IThermal mThermalHal10 = null;
653
654 @Override
655 protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
656 int type) {
657 synchronized (mHalLock) {
658 List<Temperature> ret = new ArrayList<>();
659 if (mThermalHal10 == null) {
660 return ret;
661 }
662 try {
663 mThermalHal10.getTemperatures(
664 (ThermalStatus status,
665 ArrayList<android.hardware.thermal.V1_0.Temperature>
666 temperatures) -> {
667 if (ThermalStatusCode.SUCCESS == status.code) {
668 for (android.hardware.thermal.V1_0.Temperature
669 temperature : temperatures) {
670 if (shouldFilter && type != temperature.type) {
671 continue;
672 }
673 // Thermal HAL 1.0 doesn't report current throttling status
674 ret.add(new Temperature(
675 temperature.currentValue, temperature.type,
676 temperature.name,
677 Temperature.THROTTLING_NONE));
678 }
679 } else {
680 Slog.e(TAG,
681 "Couldn't get temperatures because of HAL error: "
682 + status.debugMessage);
683 }
684
685 });
686 } catch (RemoteException e) {
687 Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
688 connectToHal();
689 }
690 return ret;
691 }
692 }
693
694 @Override
Wei Wang38e5bd72019-04-03 14:58:42 -0700695 protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
696 int type) {
697 synchronized (mHalLock) {
698 List<CoolingDevice> ret = new ArrayList<>();
699 if (mThermalHal10 == null) {
700 return ret;
701 }
702 try {
703 mThermalHal10.getCoolingDevices((status, coolingDevices) -> {
704 if (ThermalStatusCode.SUCCESS == status.code) {
705 for (android.hardware.thermal.V1_0.CoolingDevice
706 coolingDevice : coolingDevices) {
707 if (shouldFilter && type != coolingDevice.type) {
708 continue;
709 }
710 ret.add(new CoolingDevice(
711 (long) coolingDevice.currentValue,
712 coolingDevice.type,
713 coolingDevice.name));
714 }
715 } else {
716 Slog.e(TAG,
717 "Couldn't get cooling device because of HAL error: "
718 + status.debugMessage);
719 }
720
721 });
722 } catch (RemoteException e) {
723 Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
724 connectToHal();
725 }
726 return ret;
727 }
728 }
729
730 @Override
Wei Wangfb21bd82019-01-10 14:16:23 -0800731 protected boolean connectToHal() {
732 synchronized (mHalLock) {
733 try {
734 mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
735 mThermalHal10.linkToDeath(new DeathRecipient(),
736 THERMAL_HAL_DEATH_COOKIE);
737 Slog.i(TAG,
738 "Thermal HAL 1.0 service connected, no thermal call back will be "
739 + "called due to legacy API.");
740 } catch (NoSuchElementException | RemoteException e) {
741 Slog.e(TAG,
742 "Thermal HAL 1.0 service not connected.");
743 mThermalHal10 = null;
744 }
745 return (mThermalHal10 != null);
746 }
747 }
748
749 @Override
750 protected void dump(PrintWriter pw, String prefix) {
751 synchronized (mHalLock) {
752 pw.print(prefix);
753 pw.println("ThermalHAL 1.0 connected: " + (mThermalHal10 != null ? "yes"
754 : "no"));
755 }
756 }
757 }
758
Wei Wang37b17542018-11-12 11:02:09 -0800759 static class ThermalHal11Wrapper extends ThermalHalWrapper {
760 /** Proxy object for the Thermal HAL 1.1 service. */
761 @GuardedBy("mHalLock")
762 private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
763
764 /** HWbinder callback for Thermal HAL 1.1. */
765 private final IThermalCallback.Stub mThermalCallback11 =
766 new IThermalCallback.Stub() {
767 @Override
768 public void notifyThrottling(boolean isThrottling,
769 android.hardware.thermal.V1_0.Temperature temperature) {
770 Temperature thermalSvcTemp = new Temperature(
771 temperature.currentValue, temperature.type, temperature.name,
772 isThrottling ? ThrottlingSeverity.SEVERE
773 : ThrottlingSeverity.NONE);
774 final long token = Binder.clearCallingIdentity();
775 try {
776 mCallback.onValues(thermalSvcTemp);
777 } finally {
778 Binder.restoreCallingIdentity(token);
779 }
780 }
781 };
782
783 @Override
784 protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
785 int type) {
786 synchronized (mHalLock) {
787 List<Temperature> ret = new ArrayList<>();
788 if (mThermalHal11 == null) {
789 return ret;
790 }
791 try {
792 mThermalHal11.getTemperatures(
793 (ThermalStatus status,
794 ArrayList<android.hardware.thermal.V1_0.Temperature>
795 temperatures) -> {
796 if (ThermalStatusCode.SUCCESS == status.code) {
797 for (android.hardware.thermal.V1_0.Temperature
798 temperature : temperatures) {
799 if (shouldFilter && type != temperature.type) {
800 continue;
801 }
802 // Thermal HAL 1.1 doesn't report current throttling status
803 ret.add(new Temperature(
804 temperature.currentValue, temperature.type,
805 temperature.name,
806 Temperature.THROTTLING_NONE));
807 }
808 } else {
809 Slog.e(TAG,
810 "Couldn't get temperatures because of HAL error: "
811 + status.debugMessage);
812 }
813
814 });
815 } catch (RemoteException e) {
816 Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
817 connectToHal();
818 }
819 return ret;
820 }
821 }
822
823 @Override
Wei Wang38e5bd72019-04-03 14:58:42 -0700824 protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
825 int type) {
826 synchronized (mHalLock) {
827 List<CoolingDevice> ret = new ArrayList<>();
828 if (mThermalHal11 == null) {
829 return ret;
830 }
831 try {
832 mThermalHal11.getCoolingDevices((status, coolingDevices) -> {
833 if (ThermalStatusCode.SUCCESS == status.code) {
834 for (android.hardware.thermal.V1_0.CoolingDevice
835 coolingDevice : coolingDevices) {
836 if (shouldFilter && type != coolingDevice.type) {
837 continue;
838 }
839 ret.add(new CoolingDevice(
840 (long) coolingDevice.currentValue,
841 coolingDevice.type,
842 coolingDevice.name));
843 }
844 } else {
845 Slog.e(TAG,
846 "Couldn't get cooling device because of HAL error: "
847 + status.debugMessage);
848 }
849
850 });
851 } catch (RemoteException e) {
852 Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
853 connectToHal();
854 }
855 return ret;
856 }
857 }
858
859 @Override
Wei Wang37b17542018-11-12 11:02:09 -0800860 protected boolean connectToHal() {
861 synchronized (mHalLock) {
862 try {
863 mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
864 mThermalHal11.linkToDeath(new DeathRecipient(),
865 THERMAL_HAL_DEATH_COOKIE);
866 mThermalHal11.registerThermalCallback(mThermalCallback11);
Wei Wangd8783892019-08-01 11:51:15 -0700867 Slog.i(TAG, "Thermal HAL 1.1 service connected, limited thermal functions "
868 + "due to legacy API.");
Wei Wang37b17542018-11-12 11:02:09 -0800869 } catch (NoSuchElementException | RemoteException e) {
Wei Wangd8783892019-08-01 11:51:15 -0700870 Slog.e(TAG, "Thermal HAL 1.1 service not connected.");
Wei Wang37b17542018-11-12 11:02:09 -0800871 mThermalHal11 = null;
872 }
873 return (mThermalHal11 != null);
874 }
875 }
876
877 @Override
878 protected void dump(PrintWriter pw, String prefix) {
879 synchronized (mHalLock) {
880 pw.print(prefix);
881 pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes"
882 : "no"));
883 }
884 }
885 }
886
887 static class ThermalHal20Wrapper extends ThermalHalWrapper {
888 /** Proxy object for the Thermal HAL 2.0 service. */
889 @GuardedBy("mHalLock")
890 private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
891
892 /** HWbinder callback for Thermal HAL 2.0. */
893 private final IThermalChangedCallback.Stub mThermalCallback20 =
894 new IThermalChangedCallback.Stub() {
895 @Override
896 public void notifyThrottling(
897 android.hardware.thermal.V2_0.Temperature temperature) {
898 Temperature thermalSvcTemp = new Temperature(
899 temperature.value, temperature.type, temperature.name,
900 temperature.throttlingStatus);
901 final long token = Binder.clearCallingIdentity();
902 try {
903 mCallback.onValues(thermalSvcTemp);
904 } finally {
905 Binder.restoreCallingIdentity(token);
906 }
907 }
908 };
909
910 @Override
911 protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
912 int type) {
913 synchronized (mHalLock) {
914 List<Temperature> ret = new ArrayList<>();
915 if (mThermalHal20 == null) {
916 return ret;
917 }
918 try {
919 mThermalHal20.getCurrentTemperatures(shouldFilter, type,
Wei Wang38e5bd72019-04-03 14:58:42 -0700920 (status, temperatures) -> {
Wei Wang37b17542018-11-12 11:02:09 -0800921 if (ThermalStatusCode.SUCCESS == status.code) {
922 for (android.hardware.thermal.V2_0.Temperature
923 temperature : temperatures) {
924 ret.add(new Temperature(
925 temperature.value, temperature.type,
926 temperature.name,
927 temperature.throttlingStatus));
928 }
929 } else {
930 Slog.e(TAG,
931 "Couldn't get temperatures because of HAL error: "
932 + status.debugMessage);
933 }
934
935 });
936 } catch (RemoteException e) {
937 Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
938 connectToHal();
939 }
940 return ret;
941 }
942 }
943
944 @Override
Wei Wang38e5bd72019-04-03 14:58:42 -0700945 protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
946 int type) {
947 synchronized (mHalLock) {
948 List<CoolingDevice> ret = new ArrayList<>();
949 if (mThermalHal20 == null) {
950 return ret;
951 }
952 try {
953 mThermalHal20.getCurrentCoolingDevices(shouldFilter, type,
954 (status, coolingDevices) -> {
955 if (ThermalStatusCode.SUCCESS == status.code) {
956 for (android.hardware.thermal.V2_0.CoolingDevice
957 coolingDevice : coolingDevices) {
958 ret.add(new CoolingDevice(
959 coolingDevice.value, coolingDevice.type,
960 coolingDevice.name));
961 }
962 } else {
963 Slog.e(TAG,
964 "Couldn't get cooling device because of HAL error: "
965 + status.debugMessage);
966 }
967
968 });
969 } catch (RemoteException e) {
970 Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
971 connectToHal();
972 }
973 return ret;
974 }
975 }
976
977 @Override
Wei Wang37b17542018-11-12 11:02:09 -0800978 protected boolean connectToHal() {
979 synchronized (mHalLock) {
980 try {
981 mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
982 mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
983 mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
984 0 /* not used */);
Wei Wangd8783892019-08-01 11:51:15 -0700985 Slog.i(TAG, "Thermal HAL 2.0 service connected.");
Wei Wang37b17542018-11-12 11:02:09 -0800986 } catch (NoSuchElementException | RemoteException e) {
Wei Wangd8783892019-08-01 11:51:15 -0700987 Slog.e(TAG, "Thermal HAL 2.0 service not connected.");
Wei Wang37b17542018-11-12 11:02:09 -0800988 mThermalHal20 = null;
989 }
990 return (mThermalHal20 != null);
991 }
992 }
993
994 @Override
995 protected void dump(PrintWriter pw, String prefix) {
996 synchronized (mHalLock) {
997 pw.print(prefix);
998 pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes"
999 : "no"));
Wei Wangbad7c202018-11-01 11:57:39 -07001000 }
1001 }
1002 }
1003
1004}