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