Merge "Add support for pulling and pushing statsd atoms to CarService." into qt-qpr1-dev
diff --git a/car_product/init/init.bootstat.rc b/car_product/init/init.bootstat.rc
index 5c5e796..4122ea4 100644
--- a/car_product/init/init.bootstat.rc
+++ b/car_product/init/init.bootstat.rc
@@ -4,4 +4,4 @@
# This is a common source of Android security bugs.
#
on property:boot.car_service_created=1
- exec - root root -- /system/bin/bootstat -r car_service_created
+ exec - system log -- /system/bin/bootstat -r car_service_created
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index 6b5ddac..1d5fd14 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -93,4 +93,8 @@
<string name="config_dataUsageSummaryComponent">com.android.car.settings/com.android.car.settings.datausage.DataWarningAndLimitActivity</string>
<bool name="config_automotiveHideNavBarForKeyboard">true</bool>
+
+ <!-- Turn off Wallpaper service -->
+ <bool name="config_enableWallpaperService">false</bool>
+
</resources>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 81e0620..c756510 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -241,4 +241,8 @@
<integer name="config_mediaSourceChangedAutoplay">2</integer>
<!-- Configuration to enable media center to autoplay on boot -->
<integer name="config_mediaBootAutoplay">2</integer>
+
+ <!-- Disable switching the user while the system is resuming from Suspend to RAM.
+ This default says to prevent changing the user during Resume. -->
+ <bool name="config_disableUserSwitchDuringResume" translatable="false">true</bool>
</resources>
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index c1341da..83c5051 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -54,6 +54,10 @@
*/
public class CarPowerManagementService extends ICarPower.Stub implements
CarServiceBase, PowerHalService.PowerEventListener {
+
+ private final Object mLock = new Object();
+ private final Object mSimulationWaitObject = new Object();
+
private final Context mContext;
private final PowerHalService mHal;
private final SystemInterface mSystemInterface;
@@ -62,32 +66,38 @@
// The listeners that must indicate asynchronous completion by calling finished().
private final PowerManagerCallbackList mPowerManagerListenersWithCompletion =
new PowerManagerCallbackList();
- private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
- private final Object mSimulationSleepObject = new Object();
- @GuardedBy("this")
+ @GuardedBy("mSimulationWaitObject")
+ private boolean mWakeFromSimulatedSleep;
+ @GuardedBy("mSimulationWaitObject")
+ private boolean mInSimulatedDeepSleepMode;
+
+ @GuardedBy("mLock")
+ private final Set<IBinder> mListenersWeAreWaitingFor = new HashSet<>();
+ @GuardedBy("mLock")
private CpmsState mCurrentState;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private Timer mTimer;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private long mProcessingStartTime;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private long mLastSleepEntryTime;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private final LinkedList<CpmsState> mPendingPowerStates = new LinkedList<>();
- @GuardedBy("this")
+ @GuardedBy("mLock")
private HandlerThread mHandlerThread;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private PowerHandler mHandler;
- @GuardedBy("this")
+ @GuardedBy("mLock")
private boolean mTimerActive;
- @GuardedBy("mSimulationSleepObject")
- private boolean mInSimulatedDeepSleepMode = false;
- @GuardedBy("mSimulationSleepObject")
- private boolean mWakeFromSimulatedSleep = false;
- private int mNextWakeupSec = 0;
- private boolean mShutdownOnFinish = false;
+ @GuardedBy("mLock")
+ private int mNextWakeupSec;
+ @GuardedBy("mLock")
+ private boolean mShutdownOnFinish;
+ @GuardedBy("mLock")
private boolean mIsBooting = true;
+ @GuardedBy("mLock")
+ private boolean mIsResuming;
private final CarUserManagerHelper mCarUserManagerHelper;
@@ -160,7 +170,7 @@
@Override
public void init() {
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
mHandlerThread.start();
mHandler = new PowerHandler(mHandlerThread.getLooper());
@@ -180,11 +190,12 @@
@Override
public void release() {
HandlerThread handlerThread;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
releaseTimerLocked();
mCurrentState = null;
mHandler.cancelAll();
handlerThread = mHandlerThread;
+ mListenersWeAreWaitingFor.clear();
}
handlerThread.quitSafely();
try {
@@ -194,7 +205,6 @@
}
mSystemInterface.stopDisplayStateMonitoring();
mPowerManagerListeners.kill();
- mListenersWeAreWaitingFor.clear();
mSystemInterface.releaseAllWakeLocks();
}
@@ -212,7 +222,7 @@
@Override
public void onApPowerStateChange(PowerState state) {
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
mPendingPowerStates.addFirst(new CpmsState(state));
handler = mHandler;
}
@@ -220,8 +230,11 @@
}
@VisibleForTesting
- protected void clearIsBooting() {
- mIsBooting = false;
+ protected void clearIsBootingOrResuming() {
+ synchronized (mLock) {
+ mIsBooting = false;
+ mIsResuming = false;
+ }
}
/**
@@ -230,7 +243,7 @@
private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
mPendingPowerStates.addFirst(newState);
handler = mHandler;
}
@@ -240,7 +253,7 @@
private void doHandlePowerStateChange() {
CpmsState state;
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
state = mPendingPowerStates.peekFirst();
mPendingPowerStates.clear();
if (state == null) {
@@ -304,10 +317,30 @@
}
private void handleOn() {
- // Do not switch user if it is booting as there can be a race with CarServiceHelperService
- if (mIsBooting) {
- mIsBooting = false;
- } else {
+ // Some OEMs have their own user-switching logic, which may not be coordinated with this
+ // code. To avoid contention, we don't switch users when we coming alive. The OEM's code
+ // should do the switch.
+ boolean allowUserSwitch = true;
+ synchronized (mLock) {
+ if (mIsBooting) {
+ // The system is booting, so don't switch users
+ allowUserSwitch = false;
+ mIsBooting = false;
+ mIsResuming = false;
+ Log.i(CarLog.TAG_POWER, "User switch disallowed while booting");
+ } else if (mIsResuming) {
+ // The system is resuming after a suspension. Optionally disable user switching.
+ allowUserSwitch = !mContext.getResources()
+ .getBoolean(R.bool.config_disableUserSwitchDuringResume);
+ mIsBooting = false;
+ mIsResuming = false;
+ if (!allowUserSwitch) {
+ Log.i(CarLog.TAG_POWER, "User switch disallowed while resuming");
+ }
+ }
+ }
+
+ if (allowUserSwitch) {
int targetUserId = mCarUserManagerHelper.getInitialUser();
if (targetUserId != UserHandle.USER_SYSTEM
&& targetUserId != mCarUserManagerHelper.getCurrentForegroundUserId()) {
@@ -323,9 +356,11 @@
private void handleShutdownPrepare(CpmsState newState) {
mSystemInterface.setDisplayState(false);
// Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
- mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
- || !mSystemInterface.isSystemSupportingDeepSleep()
- || !newState.mCanSleep;
+ synchronized (mLock) {
+ mShutdownOnFinish |= !mHal.isDeepSleepAllowed()
+ || !mSystemInterface.isSystemSupportingDeepSleep()
+ || !newState.mCanSleep;
+ }
if (newState.mCanPostpone) {
Log.i(CarLog.TAG_POWER, "starting shutdown prepare");
sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
@@ -333,7 +368,7 @@
doHandlePreprocessing();
} else {
Log.i(CarLog.TAG_POWER, "starting shutdown immediately");
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
releaseTimerLocked();
}
// Notify hal that we are shutting down and since it is immediate, don't schedule next
@@ -355,21 +390,27 @@
private void handleWaitForFinish(CpmsState state) {
sendPowerManagerEvent(state.mCarPowerStateListenerState);
+ int wakeupSec;
+ synchronized (mLock) {
+ wakeupSec = mNextWakeupSec;
+ }
switch (state.mCarPowerStateListenerState) {
case CarPowerStateListener.SUSPEND_ENTER:
- mHal.sendSleepEntry(mNextWakeupSec);
+ mHal.sendSleepEntry(wakeupSec);
break;
case CarPowerStateListener.SHUTDOWN_ENTER:
- mHal.sendShutdownStart(mNextWakeupSec);
+ mHal.sendShutdownStart(wakeupSec);
break;
}
}
private void handleFinish() {
- boolean mustShutDown;
boolean simulatedMode;
- synchronized (mSimulationSleepObject) {
+ synchronized (mSimulationWaitObject) {
simulatedMode = mInSimulatedDeepSleepMode;
+ }
+ boolean mustShutDown;
+ synchronized (mLock) {
mustShutDown = mShutdownOnFinish && !simulatedMode;
}
if (mustShutDown) {
@@ -380,15 +421,13 @@
}
}
- @GuardedBy("this")
+ @GuardedBy("mLock")
private void releaseTimerLocked() {
- synchronized (CarPowerManagementService.this) {
- if (mTimer != null) {
- mTimer.cancel();
- }
- mTimer = null;
- mTimerActive = false;
+ if (mTimer != null) {
+ mTimer.cancel();
}
+ mTimer = null;
+ mTimerActive = false;
}
private void doHandlePreprocessing() {
@@ -407,7 +446,7 @@
}
Log.i(CarLog.TAG_POWER, "processing before shutdown expected for: "
+ sShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
mProcessingStartTime = SystemClock.elapsedRealtime();
releaseTimerLocked();
mTimer = new Timer();
@@ -433,7 +472,7 @@
// see the list go empty and we will think that we are done.
boolean haveSomeCompleters = false;
PowerManagerCallbackList completingListeners = new PowerManagerCallbackList();
- synchronized (mListenersWeAreWaitingFor) {
+ synchronized (mLock) {
mListenersWeAreWaitingFor.clear();
int idx = mPowerManagerListenersWithCompletion.beginBroadcast();
while (idx-- > 0) {
@@ -475,28 +514,33 @@
// enterDeepSleep should force sleep entry even if wake lock is kept.
mSystemInterface.switchToPartialWakeLock();
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
handler = mHandler;
}
handler.cancelProcessingComplete();
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
mLastSleepEntryTime = SystemClock.elapsedRealtime();
}
int nextListenerState;
if (simulatedMode) {
- simulateSleepByLooping();
+ simulateSleepByWaiting();
nextListenerState = CarPowerStateListener.SHUTDOWN_CANCELLED;
} else {
boolean sleepSucceeded = mSystemInterface.enterDeepSleep();
if (!sleepSucceeded) {
- // VHAL should transition CPMS to shutdown.
+ // Suspend failed! VHAL should transition CPMS to shutdown.
Log.e(CarLog.TAG_POWER, "Sleep did not succeed. Now attempting to shut down.");
mSystemInterface.shutdown();
+ return;
}
nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
}
- // On wake, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
- mNextWakeupSec = 0;
+ // On resume, reset nextWakeup time. If not set again, system will suspend/shutdown forever.
+ synchronized (mLock) {
+ mIsResuming = true;
+ mNextWakeupSec = 0;
+ }
+ Log.i(CarLog.TAG_POWER, "Resuming after suspending");
mSystemInterface.refreshDisplayBrightness();
onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
}
@@ -537,26 +581,24 @@
}
private void doHandleProcessingComplete() {
- synchronized (CarPowerManagementService.this) {
+ int listenerState;
+ synchronized (mLock) {
releaseTimerLocked();
if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) {
// entered sleep after processing start. So this could be duplicate request.
Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore");
return;
}
+ listenerState = mShutdownOnFinish
+ ? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER;
}
-
- if (mShutdownOnFinish) {
- onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SHUTDOWN_ENTER);
- } else {
- onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, CarPowerStateListener.SUSPEND_ENTER);
- }
+ onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState);
}
@Override
public void onDisplayBrightnessChange(int brightness) {
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
handler = mHandler;
}
handler.handleDisplayBrightnessChange(brightness);
@@ -572,7 +614,7 @@
public void handleMainDisplayChanged(boolean on) {
PowerHandler handler;
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
handler = mHandler;
}
handler.handleMainDisplayStateChange(on);
@@ -586,8 +628,13 @@
mHal.sendDisplayBrightness(brightness);
}
- public synchronized Handler getHandler() {
- return mHandler;
+ /**
+ * Get the PowerHandler that we use to change power states
+ */
+ public Handler getHandler() {
+ synchronized (mLock) {
+ return mHandler;
+ }
}
// Binder interface for general use.
@@ -628,7 +675,9 @@
@Override
public void requestShutdownOnNextSuspend() {
ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
- mShutdownOnFinish = true;
+ synchronized (mLock) {
+ mShutdownOnFinish = true;
+ }
}
@Override
@@ -639,27 +688,31 @@
}
@Override
- public synchronized void scheduleNextWakeupTime(int seconds) {
+ public void scheduleNextWakeupTime(int seconds) {
if (seconds < 0) {
- Log.w(CarLog.TAG_POWER, "Next wake up can not be in negative time. Ignoring!");
+ Log.w(CarLog.TAG_POWER, "Next wake up time is negative. Ignoring!");
return;
}
- if (!mHal.isTimedWakeupAllowed()) {
- Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
- mNextWakeupSec = 0;
- return;
- }
- if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
- mNextWakeupSec = seconds;
- } else {
- Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
- + "scheduled time");
+ boolean timedWakeupAllowed = mHal.isTimedWakeupAllowed();
+ synchronized (mLock) {
+ if (!timedWakeupAllowed) {
+ Log.w(CarLog.TAG_POWER, "Setting timed wakeups are disabled in HAL. Skipping");
+ mNextWakeupSec = 0;
+ return;
+ }
+ if (mNextWakeupSec == 0 || mNextWakeupSec > seconds) {
+ // The new value is sooner than the old value. Take the new value.
+ mNextWakeupSec = seconds;
+ } else {
+ Log.d(CarLog.TAG_POWER, "Tried to schedule next wake up, but already had shorter "
+ + "scheduled time");
+ }
}
}
private void finishedImpl(IBinder binder) {
boolean allAreComplete = false;
- synchronized (mListenersWeAreWaitingFor) {
+ synchronized (mLock) {
boolean oneWasRemoved = mListenersWeAreWaitingFor.remove(binder);
allAreComplete = oneWasRemoved && mListenersWeAreWaitingFor.isEmpty();
}
@@ -673,7 +726,7 @@
|| mCurrentState.mState == CpmsState.SIMULATE_SLEEP) {
PowerHandler powerHandler;
// All apps are ready to shutdown/suspend.
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
if (!mShutdownOnFinish) {
if (mLastSleepEntryTime > mProcessingStartTime
&& mLastSleepEntryTime < SystemClock.elapsedRealtime()) {
@@ -765,7 +818,7 @@
@Override
public void run() {
- synchronized (CarPowerManagementService.this) {
+ synchronized (mLock) {
if (!mTimerActive) {
// Ignore timer expiration since we got cancelled
return;
@@ -927,9 +980,9 @@
}
handler.handlePowerStateChange();
- synchronized (mSimulationSleepObject) {
+ synchronized (mSimulationWaitObject) {
mWakeFromSimulatedSleep = true;
- mSimulationSleepObject.notify();
+ mSimulationWaitObject.notify();
}
}
@@ -940,12 +993,12 @@
* that is not directly derived from a VehicleApPowerStateReq.
*/
public void forceSimulatedSuspend() {
- synchronized (mSimulationSleepObject) {
+ synchronized (mSimulationWaitObject) {
mInSimulatedDeepSleepMode = true;
mWakeFromSimulatedSleep = false;
}
PowerHandler handler;
- synchronized (this) {
+ synchronized (mLock) {
mPendingPowerStates.addFirst(new CpmsState(CpmsState.SIMULATE_SLEEP,
CarPowerStateListener.SHUTDOWN_PREPARE));
handler = mHandler;
@@ -956,19 +1009,20 @@
// In a real Deep Sleep, the hardware removes power from the CPU (but retains power
// on the RAM). This puts the processor to sleep. Upon some external signal, power
// is re-applied to the CPU, and processing resumes right where it left off.
- // We simulate this behavior by simply going into a loop.
- // We exit the loop when forceResume() is called.
- private void simulateSleepByLooping() {
- Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by looping");
- synchronized (mSimulationSleepObject) {
+ // We simulate this behavior by calling wait().
+ // We continue from wait() when forceSimulatedResume() is called.
+ private void simulateSleepByWaiting() {
+ Log.i(CarLog.TAG_POWER, "Starting to simulate Deep Sleep by waiting");
+ synchronized (mSimulationWaitObject) {
while (!mWakeFromSimulatedSleep) {
try {
- mSimulationSleepObject.wait();
+ mSimulationWaitObject.wait();
} catch (InterruptedException ignored) {
+ Thread.currentThread().interrupt(); // Restore interrupted status
}
}
mInSimulatedDeepSleepMode = false;
}
- Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation loop");
+ Log.i(CarLog.TAG_POWER, "Exit Deep Sleep simulation");
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index fa82f90..945a9d6 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -197,7 +197,7 @@
// second processing after wakeup
assertFalse(mDisplayInterface.getDisplayState());
// do not skip user switching part.
- mService.clearIsBooting();
+ mService.clearIsBootingOrResuming();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
// user switching should have been requested.