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 java.time.Duration; 20 import java.util.ArrayList; 21 import java.util.Collections; 22 import java.util.List; 23 import java.util.concurrent.Executors; 24 import java.util.concurrent.ScheduledExecutorService; 25 import java.util.concurrent.TimeUnit; 26 27 import com.android.car.procfsinspector.ProcessInfo; 28 import com.android.car.procfsinspector.ProcfsInspector; 29 import com.android.internal.car.ICarServiceHelper; 30 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.os.PowerManager; 36 import android.os.SystemClock; 37 import android.util.Log; 38 import android.util.Pair; 39 40 /** 41 * Interface that abstracts system status (booted, sleeping, ...) operations 42 */ 43 public interface SystemStateInterface { 44 static final String TAG = SystemStateInterface.class.getSimpleName(); 45 void shutdown(); 46 boolean enterDeepSleep(int sleepDurationSec); 47 void scheduleActionForBootCompleted(Runnable action, Duration delay); 48 49 default boolean isWakeupCausedByTimer() { 50 //TODO bug: 32061842, check wake up reason and do necessary operation information should 51 // come from kernel. it can be either power on or wake up for maintenance 52 // power on will involve GPIO trigger from power controller 53 // its own wakeup will involve timer expiration. 54 return false; 55 } 56 57 default boolean isSystemSupportingDeepSleep() { 58 //TODO should return by checking some kernel suspend control sysfs, bug: 32061842 59 return false; 60 } 61 62 default List<ProcessInfo> getRunningProcesses() { 63 return ProcfsInspector.readProcessTable(); 64 } 65 66 default void setCarServiceHelper(ICarServiceHelper helper) { 67 // Do nothing 68 } 69 70 class DefaultImpl implements SystemStateInterface { 71 private final static Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10); 72 private final static int SUSPEND_TRY_TIMEOUT_MS = 1000; 73 74 private ICarServiceHelper mICarServiceHelper; 75 private final Context mContext; 76 private final PowerManager mPowerManager; 77 private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); 78 private ScheduledExecutorService mExecutorService; 79 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 80 @Override 81 public void onReceive(Context context, Intent intent) { 82 if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { 83 for (Pair<Runnable, Duration> action : mActionsList) { 84 mExecutorService.schedule(action.first, 85 action.second.toMillis(), TimeUnit.MILLISECONDS); 86 } 87 } 88 } 89 }; 90 91 DefaultImpl(Context context) { 92 mContext = context; 93 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 94 } 95 96 @Override 97 public void shutdown() { 98 mPowerManager.shutdown(false /* no confirm*/, null, true /* true */); 99 } 100 101 @Override 102 public boolean enterDeepSleep(int sleepDurationSec) { 103 boolean deviceEnteredSleep; 104 //TODO set wake up time via VHAL, bug: 32061842 105 try { 106 int retVal; 107 retVal = mICarServiceHelper.forceSuspend(SUSPEND_TRY_TIMEOUT_MS); 108 deviceEnteredSleep = retVal == 0; 109 110 } catch (Exception e) { 111 Log.e(TAG, "Unable to enter deep sleep", e); 112 deviceEnteredSleep = false; 113 } 114 return deviceEnteredSleep; 115 } 116 117 @Override 118 public void scheduleActionForBootCompleted(Runnable action, Duration delay) { 119 if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) { 120 // TODO: consider adding some degree of randomness here 121 delay = MIN_BOOT_COMPLETE_ACTION_DELAY; 122 } 123 if (mActionsList.isEmpty()) { 124 final int corePoolSize = 1; 125 mExecutorService = Executors.newScheduledThreadPool(corePoolSize); 126 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 127 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 128 } 129 mActionsList.add(Pair.create(action, delay)); 130 } 131 132 @Override 133 public void setCarServiceHelper(ICarServiceHelper helper) { 134 mICarServiceHelper = helper; 135 } 136 } 137 } 138