• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.car.hardware.power;
18 
19 import android.annotation.SystemApi;
20 import android.car.Car;
21 import android.car.CarManagerBase;
22 import android.content.Context;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.concurrent.CancellationException;
31 import java.util.concurrent.CompletableFuture;
32 
33 /**
34  * API for receiving power state change notifications.
35  * @hide
36  */
37 @SystemApi
38 public class CarPowerManager implements CarManagerBase {
39     private final static boolean DBG = false;
40     private final static String TAG = "CarPowerManager";
41 
42     private final Object mLock = new Object();
43     private final ICarPower mService;
44 
45     private CarPowerStateListener mListener;
46     private CarPowerStateListenerWithCompletion mListenerWithCompletion;
47     private CompletableFuture<Void> mFuture;
48     @GuardedBy("mLock")
49     private ICarPowerStateListener mListenerToService;
50 
51 
52     /**
53      *  Applications set a {@link CarPowerStateListener} for power state event updates.
54      */
55     public interface CarPowerStateListener {
56         /**
57          * onStateChanged() states.  These definitions must match the ones located in the native
58          * CarPowerManager:  packages/services/Car/car-lib/native/CarPowerManager/CarPowerManager.h
59          */
60 
61         /**
62          * Android is up, but vendor is controlling the audio / display
63          * @hide
64          */
65         int WAIT_FOR_VHAL = 1;
66         /**
67          * Enter suspend state.  CPMS is switching to WAIT_FOR_FINISHED state.
68          * @hide
69          */
70         int SUSPEND_ENTER = 2;
71         /**
72          * Wake up from suspend.
73          * @hide
74          */
75         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;
81         /**
82          * On state
83          * @hide
84          */
85         int ON = 6;
86         /**
87          * State where system is getting ready for shutdown or suspend.  Application is expected to
88          * cleanup and be ready to suspend
89          * @hide
90          */
91         int SHUTDOWN_PREPARE = 7;
92         /**
93          * Shutdown is cancelled, return to normal state.
94          * @hide
95          */
96         int SHUTDOWN_CANCELLED = 8;
97 
98         /**
99          * 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          */
onStateChanged(int state)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.
120          * @hide
121          */
onStateChanged(int state, CompletableFuture<Void> future)122         void onStateChanged(int state, CompletableFuture<Void> future);
123     }
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      */
CarPowerManager(IBinder service, Context context, Handler handler)134     public CarPowerManager(IBinder service, Context context, Handler handler) {
135         mService = ICarPower.Stub.asInterface(service);
136     }
137 
138     /**
139      * Request power manager to shutdown in lieu of suspend at the next opportunity.
140      * @hide
141      */
requestShutdownOnNextSuspend()142     public void requestShutdownOnNextSuspend() {
143         try {
144             mService.requestShutdownOnNextSuspend();
145         } catch (RemoteException e) {
146             throw e.rethrowFromSystemServer();
147         }
148     }
149 
150     /**
151      * Schedule next wake up time in CarPowerManagementSystem
152      * @hide
153      */
scheduleNextWakeupTime(int seconds)154     public void scheduleNextWakeupTime(int seconds) {
155         try {
156             mService.scheduleNextWakeupTime(seconds);
157         } catch (RemoteException e) {
158             throw e.rethrowFromSystemServer();
159         }
160     }
161 
162     /**
163      * 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.
166      *
167      * @param listener
168      * @throws IllegalStateException
169      * @hide
170      */
setListener(CarPowerStateListener listener)171     public void setListener(CarPowerStateListener listener) {
172         synchronized (mLock) {
173             if (mListener != null || mListenerWithCompletion != null) {
174                 throw new IllegalStateException("Listener must be cleared first");
175             }
176             // 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      */
setListenerWithCompletion(CarPowerStateListenerWithCompletion listener)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 
setServiceForListenerLocked(boolean useCompletion)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);
219                     }
220                 }
221             };
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();
231             }
232         }
233     }
234 
235     /**
236      * Removes the listener from {@link CarPowerManagementService}
237      * @hide
238      */
clearListener()239     public void clearListener() {
240         ICarPowerStateListener listenerToService;
241         synchronized (mLock) {
242             listenerToService = mListenerToService;
243             mListenerToService = null;
244             mListener = null;
245             mListenerWithCompletion = null;
246             cleanupFuture();
247         }
248 
249         if (listenerToService == null) {
250             Log.w(TAG, "unregisterListener: listener was not registered");
251             return;
252         }
253 
254         try {
255             mService.unregisterListener(listenerToService);
256         } catch (RemoteException e) {
257             throw e.rethrowFromSystemServer();
258         }
259     }
260 
updateFuture(int state)261     private void updateFuture(int state) {
262         cleanupFuture();
263         if (state == CarPowerStateListener.SHUTDOWN_PREPARE) {
264             // Create a CompletableFuture and pass it to the listener.
265             // When the listener completes the future, tell
266             // CarPowerManagementService that this action is finished.
267             mFuture = new CompletableFuture<>();
268             mFuture.whenComplete((result, exception) -> {
269                 if (exception != null && !(exception instanceof CancellationException)) {
270                     Log.e(TAG, "Exception occurred while waiting for future", exception);
271                 }
272                 try {
273                     mService.finished(mListenerToService);
274                 } catch (RemoteException e) {
275                     throw e.rethrowFromSystemServer();
276                 }
277             });
278         }
279     }
280 
cleanupFuture()281     private void cleanupFuture() {
282         if (mFuture != null) {
283             if (!mFuture.isDone()) {
284                 mFuture.cancel(false);
285             }
286             mFuture = null;
287         }
288     }
289 
290     /** @hide */
291     @Override
onCarDisconnected()292     public void onCarDisconnected() {
293         ICarPowerStateListener listenerToService;
294         synchronized (mLock) {
295             listenerToService = mListenerToService;
296         }
297 
298         if (listenerToService != null) {
299             clearListener();
300         }
301     }
302 }
303