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 Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10); 97 98 private final Context mContext; 99 private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); 100 private ScheduledExecutorService mExecutorService; 101 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 102 @Override 103 public void onReceive(Context context, Intent intent) { 104 if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { 105 for (Pair<Runnable, Duration> action : mActionsList) { 106 mExecutorService.schedule(action.first, 107 action.second.toMillis(), TimeUnit.MILLISECONDS); 108 } 109 } 110 } 111 }; 112 113 @VisibleForTesting DefaultImpl(Context context)114 public DefaultImpl(Context context) { 115 mContext = context; 116 } 117 118 @Override shutdown()119 public void shutdown() { 120 PowerManagerHelper.shutdown(mContext, /* confirm= */ false , /* reason= */ null, 121 /* wait= */ true); 122 } 123 124 @Override enterDeepSleep()125 public boolean enterDeepSleep() { 126 // TODO(b/32061842) Set wake up time via VHAL 127 128 boolean deviceEnteredSleep = false; 129 try { 130 int retVal = SystemPowerControlHelper.forceDeepSleep(); 131 deviceEnteredSleep = retVal == SUSPEND_RESULT_SUCCESS; 132 } catch (Exception e) { 133 Slogf.e(TAG, "Unable to enter deep sleep", e); 134 } 135 return deviceEnteredSleep; 136 } 137 138 @Override enterHibernation()139 public boolean enterHibernation() { 140 boolean deviceHibernated = false; 141 try { 142 int retVal = SystemPowerControlHelper.forceHibernate(); 143 deviceHibernated = retVal == SUSPEND_RESULT_SUCCESS; 144 } catch (Exception e) { 145 Slogf.e(TAG, "Unable to enter hibernation", e); 146 } 147 return deviceHibernated; 148 } 149 150 @Override scheduleActionForBootCompleted(Runnable action, Duration bootCompleteDelay)151 public void scheduleActionForBootCompleted(Runnable action, Duration bootCompleteDelay) { 152 Duration delay = bootCompleteDelay; 153 if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) { 154 // TODO: consider adding some degree of randomness here 155 delay = MIN_BOOT_COMPLETE_ACTION_DELAY; 156 } 157 if (mActionsList.isEmpty()) { 158 final int corePoolSize = 1; 159 mExecutorService = Executors.newScheduledThreadPool(corePoolSize); 160 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 161 mContext.registerReceiver(mBroadcastReceiver, intentFilter, 162 Context.RECEIVER_NOT_EXPORTED); 163 } 164 mActionsList.add(Pair.create(action, delay)); 165 } 166 167 @Override isSystemSupportingDeepSleep()168 public boolean isSystemSupportingDeepSleep() { 169 return SystemPowerControlHelper.isSystemSupportingDeepSleep(); 170 } 171 172 @Override isSystemSupportingHibernation()173 public boolean isSystemSupportingHibernation() { 174 return SystemPowerControlHelper.isSystemSupportingHibernation(); 175 } 176 } 177 } 178