• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 com.android.car.systeminterface;
18 
19 import static com.android.car.systeminterface.SystemPowerControlHelper.SUSPEND_RESULT_SUCCESS;
20 
21 import android.car.builtin.power.PowerManagerHelper;
22 import android.car.builtin.util.Slogf;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.util.Pair;
28 
29 import com.android.car.procfsinspector.ProcessInfo;
30 import com.android.car.procfsinspector.ProcfsInspector;
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.time.Duration;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.Executors;
37 import java.util.concurrent.ScheduledExecutorService;
38 import java.util.concurrent.TimeUnit;
39 
40 /**
41  * Interface that abstracts system status (booted, sleeping, ...) operations
42  */
43 public interface SystemStateInterface {
44     static final String TAG = SystemStateInterface.class.getSimpleName();
shutdown()45     void shutdown();
46     /**
47      * Put the device into Suspend to RAM mode
48      * @return boolean true if suspend succeeded
49      */
enterDeepSleep()50     boolean enterDeepSleep();
51 
52     /**
53      * Puts the device into Suspend-to-disk (hibernation)
54      *
55      * @return boolean {@code true} if hibernation succeeded
56     */
enterHibernation()57     boolean enterHibernation();
58 
scheduleActionForBootCompleted(Runnable action, Duration delay)59     void scheduleActionForBootCompleted(Runnable action, Duration delay);
60 
isWakeupCausedByTimer()61     default boolean isWakeupCausedByTimer() {
62         //TODO bug: 32061842, check wake up reason and do necessary operation information should
63         // come from kernel. it can be either power on or wake up for maintenance
64         // power on will involve GPIO trigger from power controller
65         // its own wakeup will involve timer expiration.
66         return false;
67     }
68 
69     /**
70      * Gets whether the device supports deep sleep
71      */
isSystemSupportingDeepSleep()72     default boolean isSystemSupportingDeepSleep() {
73         return true;
74     }
75 
76     /**
77      * Gets whether the device supports hibernation
78      */
isSystemSupportingHibernation()79     default boolean isSystemSupportingHibernation() {
80         return true;
81     }
82 
83     /**
84      * @deprecated see {@link ProcfsInspector}
85      */
86     @Deprecated
getRunningProcesses()87     default List<ProcessInfo> getRunningProcesses() {
88         return ProcfsInspector.readProcessTable();
89     }
90 
91     /**
92      * Default implementation that is used internally.
93      */
94     @VisibleForTesting
95     class DefaultImpl implements SystemStateInterface {
96         private static final int MAX_WAIT_FOR_HELPER_SEC = 10;
97         private static final Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10);
98         private static final int SUSPEND_TRY_TIMEOUT_MS = 1_000;
99 
100         private final Context mContext;
101         private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
102         private ScheduledExecutorService mExecutorService;
103         private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
104             @Override
105             public void onReceive(Context context, Intent intent) {
106                 if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
107                     for (Pair<Runnable, Duration> action : mActionsList) {
108                         mExecutorService.schedule(action.first,
109                                 action.second.toMillis(), TimeUnit.MILLISECONDS);
110                     }
111                 }
112             }
113         };
114 
115         @VisibleForTesting
DefaultImpl(Context context)116         public DefaultImpl(Context context) {
117             mContext = context;
118         }
119 
120         @Override
shutdown()121         public void shutdown() {
122             PowerManagerHelper.shutdown(mContext, /* confirm= */ false , /* reason= */ null,
123                     /* wait= */ true);
124         }
125 
126         @Override
enterDeepSleep()127         public boolean enterDeepSleep() {
128             // TODO(b/32061842) Set wake up time via VHAL
129 
130             boolean deviceEnteredSleep = false;
131             try {
132                 int retVal = SystemPowerControlHelper.forceDeepSleep();
133                 deviceEnteredSleep = retVal == SUSPEND_RESULT_SUCCESS;
134             } catch (Exception e) {
135                 Slogf.e(TAG, "Unable to enter deep sleep", e);
136             }
137             return deviceEnteredSleep;
138         }
139 
140         @Override
enterHibernation()141         public boolean enterHibernation() {
142             boolean deviceHibernated = false;
143             try {
144                 int retVal = SystemPowerControlHelper.forceHibernate();
145                 deviceHibernated = retVal == SUSPEND_RESULT_SUCCESS;
146             } catch (Exception e) {
147                 Slogf.e(TAG, "Unable to enter hibernation", e);
148             }
149             return deviceHibernated;
150         }
151 
152         @Override
scheduleActionForBootCompleted(Runnable action, Duration delay)153         public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
154             if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) {
155                 // TODO: consider adding some degree of randomness here
156                 delay = MIN_BOOT_COMPLETE_ACTION_DELAY;
157             }
158             if (mActionsList.isEmpty()) {
159                 final int corePoolSize = 1;
160                 mExecutorService = Executors.newScheduledThreadPool(corePoolSize);
161                 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
162                 mContext.registerReceiver(mBroadcastReceiver, intentFilter,
163                         Context.RECEIVER_NOT_EXPORTED);
164             }
165             mActionsList.add(Pair.create(action, delay));
166         }
167 
168         @Override
isSystemSupportingDeepSleep()169         public boolean isSystemSupportingDeepSleep() {
170             return SystemPowerControlHelper.isSystemSupportingDeepSleep();
171         }
172 
173         @Override
isSystemSupportingHibernation()174         public boolean isSystemSupportingHibernation() {
175             return SystemPowerControlHelper.isSystemSupportingHibernation();
176         }
177     }
178 }
179