blob: 3d9a23a0883c01910ec7644d08598e0187e99f82 [file] [log] [blame]
Steve Paik388d7772018-02-12 10:54:51 -08001/*
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 android.car.hardware.power;
18
Steve Paik388d7772018-02-12 10:54:51 -080019import android.annotation.SystemApi;
20import android.car.Car;
21import android.car.CarManagerBase;
Steve Paik388d7772018-02-12 10:54:51 -080022import android.content.Context;
23import android.os.Handler;
24import android.os.IBinder;
Steve Paik388d7772018-02-12 10:54:51 -080025import android.os.RemoteException;
26import android.util.Log;
27
Serik Beketayevb64dc142018-08-23 13:59:36 -070028import com.android.internal.annotations.GuardedBy;
29
Jim Kayee5133162019-04-22 12:50:27 -070030import java.util.concurrent.CancellationException;
Serik Beketayevb64dc142018-08-23 13:59:36 -070031import java.util.concurrent.CompletableFuture;
32
Steve Paik388d7772018-02-12 10:54:51 -080033/**
34 * API for receiving power state change notifications.
35 * @hide
36 */
37@SystemApi
38public class CarPowerManager implements CarManagerBase {
39 private final static boolean DBG = false;
40 private final static String TAG = "CarPowerManager";
Steve Paik388d7772018-02-12 10:54:51 -080041
Serik Beketayev004ce582019-01-27 17:56:26 -080042 private final Object mLock = new Object();
43 private final ICarPower mService;
44
45 private CarPowerStateListener mListener;
Jim Kayee5133162019-04-22 12:50:27 -070046 private CarPowerStateListenerWithCompletion mListenerWithCompletion;
Serik Beketayev004ce582019-01-27 17:56:26 -080047 private CompletableFuture<Void> mFuture;
Steve Paik388d7772018-02-12 10:54:51 -080048 @GuardedBy("mLock")
49 private ICarPowerStateListener mListenerToService;
50
Steve Paik388d7772018-02-12 10:54:51 -080051
52 /**
Steve Paik388d7772018-02-12 10:54:51 -080053 * Applications set a {@link CarPowerStateListener} for power state event updates.
54 */
55 public interface CarPowerStateListener {
56 /**
Steve Paikfe900222018-03-01 18:07:38 -080057 * onStateChanged() states. These definitions must match the ones located in the native
58 * CarPowerManager: packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.h
Steve Paikfe900222018-03-01 18:07:38 -080059 */
Serik Beketayev8a1d2362018-10-26 09:08:09 -070060
61 /**
Steve Paik07db5ed2018-09-24 16:48:52 -070062 * Android is up, but vendor is controlling the audio / display
63 * @hide
Steve Paik388d7772018-02-12 10:54:51 -080064 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080065 int WAIT_FOR_VHAL = 1;
Steve Paik388d7772018-02-12 10:54:51 -080066 /**
Steve Paik07db5ed2018-09-24 16:48:52 -070067 * Enter suspend state. CPMS is switching to WAIT_FOR_FINISHED state.
Serik Beketayev8a1d2362018-10-26 09:08:09 -070068 * @hide
Steve Paik388d7772018-02-12 10:54:51 -080069 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080070 int SUSPEND_ENTER = 2;
Steve Paik388d7772018-02-12 10:54:51 -080071 /**
Steve Paik07db5ed2018-09-24 16:48:52 -070072 * Wake up from suspend.
Serik Beketayev8a1d2362018-10-26 09:08:09 -070073 * @hide
Steve Paik388d7772018-02-12 10:54:51 -080074 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080075 int SUSPEND_EXIT = 3;
76 /**
77 * Enter shutdown state. CPMS is switching to WAIT_FOR_FINISHED state.
78 * @hide
79 */
80 int SHUTDOWN_ENTER = 5;
Serik Beketayevb64dc142018-08-23 13:59:36 -070081 /**
Steve Paik07db5ed2018-09-24 16:48:52 -070082 * On state
Serik Beketayev8a1d2362018-10-26 09:08:09 -070083 * @hide
Serik Beketayevb64dc142018-08-23 13:59:36 -070084 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080085 int ON = 6;
Serik Beketayevb64dc142018-08-23 13:59:36 -070086 /**
Steve Paik07db5ed2018-09-24 16:48:52 -070087 * State where system is getting ready for shutdown or suspend. Application is expected to
88 * cleanup and be ready to suspend
Serik Beketayev8a1d2362018-10-26 09:08:09 -070089 * @hide
Serik Beketayevb64dc142018-08-23 13:59:36 -070090 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080091 int SHUTDOWN_PREPARE = 7;
Steve Paik07db5ed2018-09-24 16:48:52 -070092 /**
Serik Beketayev92d952c2019-02-08 11:07:45 -080093 * Shutdown is cancelled, return to normal state.
94 * @hide
Steve Paik07db5ed2018-09-24 16:48:52 -070095 */
Serik Beketayev92d952c2019-02-08 11:07:45 -080096 int SHUTDOWN_CANCELLED = 8;
Steve Paik388d7772018-02-12 10:54:51 -080097
98 /**
Jim Kayee5133162019-04-22 12:50:27 -070099 * Called when power state changes. This callback is available to
100 * any listener, even if it is not running in the system process.
101 * @param state New power state of device.
102 * @hide
103 */
104 void onStateChanged(int state);
105 }
106
107 /**
108 * Applications set a {@link CarPowerStateListenerWithCompletion} for power state
109 * event updates where a CompletableFuture is used.
110 * @hide
111 */
112 public interface CarPowerStateListenerWithCompletion {
113 /**
114 * Called when power state changes. This callback is only for listeners
115 * that are running in the system process.
116 * @param state New power state of device.
117 * @param future CompletableFuture used by Car modules to notify CPMS that they
118 * are ready to continue shutting down. CPMS will wait until this
119 * future is completed.
Serik Beketayev8a1d2362018-10-26 09:08:09 -0700120 * @hide
Steve Paik388d7772018-02-12 10:54:51 -0800121 */
Serik Beketayevb64dc142018-08-23 13:59:36 -0700122 void onStateChanged(int state, CompletableFuture<Void> future);
Steve Paik388d7772018-02-12 10:54:51 -0800123 }
124
125 /**
126 * Get an instance of the CarPowerManager.
127 *
128 * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
129 * @param service
130 * @param context
131 * @param handler
132 * @hide
133 */
134 public CarPowerManager(IBinder service, Context context, Handler handler) {
135 mService = ICarPower.Stub.asInterface(service);
136 }
137
138 /**
Steve Paik388d7772018-02-12 10:54:51 -0800139 * Request power manager to shutdown in lieu of suspend at the next opportunity.
Steve Paik388d7772018-02-12 10:54:51 -0800140 * @hide
141 */
Justin Pauporeccc75a32019-02-12 18:20:48 -0800142 public void requestShutdownOnNextSuspend() {
Steve Paik388d7772018-02-12 10:54:51 -0800143 try {
144 mService.requestShutdownOnNextSuspend();
145 } catch (RemoteException e) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800146 throw e.rethrowFromSystemServer();
Steve Paik388d7772018-02-12 10:54:51 -0800147 }
148 }
149
150 /**
Serik Beketayev6e4c7822018-08-27 08:20:09 -0700151 * Schedule next wake up time in CarPowerManagementSystem
Serik Beketayev6e4c7822018-08-27 08:20:09 -0700152 * @hide
153 */
Justin Pauporeccc75a32019-02-12 18:20:48 -0800154 public void scheduleNextWakeupTime(int seconds) {
Serik Beketayev6e4c7822018-08-27 08:20:09 -0700155 try {
156 mService.scheduleNextWakeupTime(seconds);
157 } catch (RemoteException e) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800158 throw e.rethrowFromSystemServer();
Serik Beketayev6e4c7822018-08-27 08:20:09 -0700159 }
160 }
161
162 /**
Jim Kayee5133162019-04-22 12:50:27 -0700163 * Sets a listener to receive power state changes. Only one listener may be set at a
164 * time for an instance of CarPowerManager.
165 * The listener is assumed to completely handle the 'onStateChanged' before returning.
Steve Paik388d7772018-02-12 10:54:51 -0800166 *
Steve Paik388d7772018-02-12 10:54:51 -0800167 * @param listener
Justin Pauporeccc75a32019-02-12 18:20:48 -0800168 * @throws IllegalStateException
Steve Paik388d7772018-02-12 10:54:51 -0800169 * @hide
170 */
Justin Pauporeccc75a32019-02-12 18:20:48 -0800171 public void setListener(CarPowerStateListener listener) {
Jim Kayee5133162019-04-22 12:50:27 -0700172 synchronized (mLock) {
173 if (mListener != null || mListenerWithCompletion != null) {
Serik Beketayev004ce582019-01-27 17:56:26 -0800174 throw new IllegalStateException("Listener must be cleared first");
175 }
Jim Kayee5133162019-04-22 12:50:27 -0700176 // Update listener
177 mListener = listener;
178 setServiceForListenerLocked(false);
179 }
180 }
181
182 /**
183 * Sets a listener to receive power state changes. Only one listener may be set at a
184 * time for an instance of CarPowerManager.
185 * For calls that require completion before continue, we attach a {@link CompletableFuture}
186 * which is being used as a signal that caller is finished and ready to proceed.
187 * Once future is completed, the {@link finished} method will automatically be called to notify
188 * {@link CarPowerManagementService} that the application has handled the
189 * {@link #SHUTDOWN_PREPARE} state transition.
190 *
191 * @param listener
192 * @throws IllegalStateException
193 * @hide
194 */
195 public void setListenerWithCompletion(CarPowerStateListenerWithCompletion listener) {
196 synchronized(mLock) {
197 if (mListener != null || mListenerWithCompletion != null) {
198 throw new IllegalStateException("Listener must be cleared first");
199 }
200 // Update listener
201 mListenerWithCompletion = listener;
202 setServiceForListenerLocked(true);
203 }
204 }
205
206 private void setServiceForListenerLocked(boolean useCompletion) {
207 if (mListenerToService == null) {
208 ICarPowerStateListener listenerToService = new ICarPowerStateListener.Stub() {
209 @Override
210 public void onStateChanged(int state) throws RemoteException {
211 if (useCompletion) {
212 // Update CompletableFuture. This will recreate it or just clean it up.
213 updateFuture(state);
214 // Notify user that the state has changed and supply a future
215 mListenerWithCompletion.onStateChanged(state, mFuture);
216 } else {
217 // Notify the user without supplying a future
218 mListener.onStateChanged(state);
Steve Paik388d7772018-02-12 10:54:51 -0800219 }
Steve Paik388d7772018-02-12 10:54:51 -0800220 }
Jim Kayee5133162019-04-22 12:50:27 -0700221 };
222 try {
223 if (useCompletion) {
224 mService.registerListenerWithCompletion(listenerToService);
225 } else {
226 mService.registerListener(listenerToService);
227 }
228 mListenerToService = listenerToService;
229 } catch (RemoteException e) {
230 throw e.rethrowFromSystemServer();
Steve Paik388d7772018-02-12 10:54:51 -0800231 }
Steve Paik388d7772018-02-12 10:54:51 -0800232 }
233 }
234
235 /**
236 * Removes the listener from {@link CarPowerManagementService}
237 * @hide
238 */
239 public void clearListener() {
240 ICarPowerStateListener listenerToService;
241 synchronized (mLock) {
242 listenerToService = mListenerToService;
243 mListenerToService = null;
244 mListener = null;
Jim Kayee5133162019-04-22 12:50:27 -0700245 mListenerWithCompletion = null;
Serik Beketayevb64dc142018-08-23 13:59:36 -0700246 cleanupFuture();
Steve Paik388d7772018-02-12 10:54:51 -0800247 }
248
249 if (listenerToService == null) {
250 Log.w(TAG, "unregisterListener: listener was not registered");
251 return;
252 }
253
254 try {
255 mService.unregisterListener(listenerToService);
Justin Paupore0dd31772019-02-07 21:22:34 -0800256 } catch (RemoteException e) {
257 throw e.rethrowFromSystemServer();
Steve Paik388d7772018-02-12 10:54:51 -0800258 }
259 }
260
Jim Kayee5133162019-04-22 12:50:27 -0700261 private void updateFuture(int state) {
Serik Beketayevb64dc142018-08-23 13:59:36 -0700262 cleanupFuture();
Steve Paik07db5ed2018-09-24 16:48:52 -0700263 if (state == CarPowerStateListener.SHUTDOWN_PREPARE) {
Jim Kayee5133162019-04-22 12:50:27 -0700264 // Create a CompletableFuture and pass it to the listener.
265 // When the listener completes the future, tell
266 // CarPowerManagementService that this action is finished.
Serik Beketayevb64dc142018-08-23 13:59:36 -0700267 mFuture = new CompletableFuture<>();
268 mFuture.whenComplete((result, exception) -> {
Jim Kayee5133162019-04-22 12:50:27 -0700269 if (exception != null && !(exception instanceof CancellationException)) {
Serik Beketayevb64dc142018-08-23 13:59:36 -0700270 Log.e(TAG, "Exception occurred while waiting for future", exception);
Serik Beketayevb64dc142018-08-23 13:59:36 -0700271 }
272 try {
Jim Kayee5133162019-04-22 12:50:27 -0700273 mService.finished(mListenerToService);
Serik Beketayevb64dc142018-08-23 13:59:36 -0700274 } catch (RemoteException e) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800275 throw e.rethrowFromSystemServer();
Serik Beketayevb64dc142018-08-23 13:59:36 -0700276 }
Steve Paik388d7772018-02-12 10:54:51 -0800277 });
Steve Paik388d7772018-02-12 10:54:51 -0800278 }
279 }
280
Serik Beketayevb64dc142018-08-23 13:59:36 -0700281 private void cleanupFuture() {
282 if (mFuture != null) {
283 if (!mFuture.isDone()) {
284 mFuture.cancel(false);
Steve Paik388d7772018-02-12 10:54:51 -0800285 }
Serik Beketayevb64dc142018-08-23 13:59:36 -0700286 mFuture = null;
Steve Paik388d7772018-02-12 10:54:51 -0800287 }
288 }
289
290 /** @hide */
291 @Override
292 public void onCarDisconnected() {
293 ICarPowerStateListener listenerToService;
294 synchronized (mLock) {
295 listenerToService = mListenerToService;
296 }
297
298 if (listenerToService != null) {
299 clearListener();
300 }
301 }
302}