diff options
author | Enrico Granata <egranata@google.com> | 2017-10-12 12:25:06 -0700 |
---|---|---|
committer | Enrico Granata <egranata@google.com> | 2017-10-17 13:11:48 -0700 |
commit | b19bc326413285806ecca7fb7b54ec7a9074f286 (patch) | |
tree | a870f3d504e10d0ce0e23c4c5b9a77837f6c234f | |
parent | 9739b3cb1c663f54157a55189a448da607e063c0 (diff) | |
download | Car-b19bc326413285806ecca7fb7b54ec7a9074f286.tar.gz |
Refactor SystemInterface.
Split SystemInterface into a set of smaller chunks, each wrapping one specific functional set of system APIs.
Provide default implementations of each of those chunks.
Rework SystemInterface to be a class that wraps all the chunks and forwards to each of them.
Add a Builder API to allow one to construct a full SystemInterface from individual chunks.
This turns a fairly heavy-weight interface into smaller pieces which are easier to use individually, and it also makes
it easier for tests to only change a subset of SystemInterface functionality when they need to do so.
Test: runtest -x packages/services/Car/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
runtest -x packages/services/Car/tests/carservice_unit_test/src/com/android/car/UptimeTrackerTest.java
runtest -x packages/services/Car/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java
runtest -x packages/services/Car/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java
runtest -x packages/services/Car/tests/carservice_test/src/com/android/car/CarDiagnosticManagerTest.java
runtest -x packages/services/Car/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
Change-Id: I34c89b526d052126198a148d742123af78eafcbd
Fixes: 67739411
19 files changed, 985 insertions, 539 deletions
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java index 4eb04b46c5..745c46d5ae 100644 --- a/service/src/com/android/car/CarPowerManagementService.java +++ b/service/src/com/android/car/CarPowerManagementService.java @@ -24,6 +24,7 @@ import android.util.Log; import com.android.car.hal.PowerHalService; import com.android.car.hal.PowerHalService.PowerState; +import com.android.car.systeminterface.SystemInterface; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; diff --git a/service/src/com/android/car/CarService.java b/service/src/com/android/car/CarService.java index ae5f0f8152..497135e69b 100644 --- a/service/src/com/android/car/CarService.java +++ b/service/src/com/android/car/CarService.java @@ -31,6 +31,8 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.util.Log; +import com.android.car.systeminterface.SystemInterface; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.RingBufferIndices; @@ -85,7 +87,9 @@ public class CarService extends Service { Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName); - mICarImpl = new ICarImpl(this, mVehicle, SystemInterface.createDefault(this), + mICarImpl = new ICarImpl(this, + mVehicle, + SystemInterface.Builder.defaultSystemInterface(this).build(), mCanBusErrorNotifier); mICarImpl.init(); SystemProperties.set("boot.car_service_created", "1"); diff --git a/service/src/com/android/car/CarStorageMonitoringService.java b/service/src/com/android/car/CarStorageMonitoringService.java index d933455afc..ae2c710aa4 100644 --- a/service/src/com/android/car/CarStorageMonitoringService.java +++ b/service/src/com/android/car/CarStorageMonitoringService.java @@ -31,6 +31,7 @@ import com.android.car.storagemonitoring.WearEstimateRecord; import com.android.car.storagemonitoring.WearHistory; import com.android.car.storagemonitoring.WearInformation; import com.android.car.storagemonitoring.WearInformationProvider; +import com.android.car.systeminterface.SystemInterface; import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -41,8 +42,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.function.BiPredicate; -import java.util.function.Function; import org.json.JSONException; public class CarStorageMonitoringService extends ICarStorageMonitoring.Stub diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java index d522debd52..1d1f997459 100644 --- a/service/src/com/android/car/ICarImpl.java +++ b/service/src/com/android/car/ICarImpl.java @@ -36,6 +36,7 @@ import com.android.car.hal.VehicleHal; import com.android.car.internal.FeatureConfiguration; import com.android.car.internal.FeatureUtil; import com.android.car.pm.CarPackageManagerService; +import com.android.car.systeminterface.SystemInterface; import com.android.internal.annotations.GuardedBy; import com.android.internal.car.ICarServiceHelper; import java.io.PrintWriter; diff --git a/service/src/com/android/car/SystemInterface.java b/service/src/com/android/car/SystemInterface.java deleted file mode 100644 index 7272355dc1..0000000000 --- a/service/src/com/android/car/SystemInterface.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.car; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.hardware.display.DisplayManager; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.SystemClock; -import android.util.Log; -import android.util.Pair; -import android.view.Display; -import com.android.car.storagemonitoring.EMmcWearInformationProvider; -import com.android.car.storagemonitoring.UfsWearInformationProvider; -import com.android.car.storagemonitoring.WearInformationProvider; -import java.io.File; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * Interface that abstracts all interactions with Android system APIs. - */ -public interface SystemInterface { - public static final boolean INCLUDE_DEEP_SLEEP_TIME = true; - public static final boolean EXCLUDE_DEEP_SLEEP_TIME = false; - - void setDisplayState(boolean on); - void releaseAllWakeLocks(); - void shutdown(); - void enterDeepSleep(int wakeupTimeSec); - void switchToPartialWakeLock(); - void switchToFullWakeLock(); - void startDisplayStateMonitoring(CarPowerManagementService service); - void stopDisplayStateMonitoring(); - File getFilesDir(); - void scheduleActionForBootCompleted(Runnable action, Duration delay); - - default WearInformationProvider[] getFlashWearInformationProviders() { - return new WearInformationProvider[] { - new EMmcWearInformationProvider(), - new UfsWearInformationProvider() - }; - } - - default long getUptime() { - return getUptime(EXCLUDE_DEEP_SLEEP_TIME); - } - default long getUptime(boolean includeDeepSleepTime) { - return includeDeepSleepTime ? - SystemClock.elapsedRealtime() : - SystemClock.uptimeMillis(); - } - - default boolean isWakeupCausedByTimer() { - //TODO bug: 32061842, check wake up reason and do necessary operation information should - // come from kernel. it can be either power on or wake up for maintenance - // power on will involve GPIO trigger from power controller - // its own wakeup will involve timer expiration. - return false; - } - - default boolean isSystemSupportingDeepSleep() { - //TODO should return by checking some kernel suspend control sysfs, bug: 32061842 - return false; - } - - public static SystemInterface createDefault(Context context) { - return new SystemInterfaceImpl(context); - } - - class SystemInterfaceImpl implements SystemInterface { - private final static Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10); - - private final Context mContext; - private final PowerManager mPowerManager; - private final DisplayManager mDisplayManager; - private final WakeLock mFullWakeLock; - private final WakeLock mPartialWakeLock; - private final DisplayStateListener mDisplayListener; - private final File mFilesDir; - private CarPowerManagementService mService; - private boolean mDisplayStateSet; - private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); - private ScheduledExecutorService mExecutorService; - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - for (Pair<Runnable, Duration> action : mActionsList) { - mExecutorService.schedule(action.first, - action.second.toMillis(), TimeUnit.MILLISECONDS); - } - } - } - }; - - private SystemInterfaceImpl(Context context) { - mContext = context; - mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - mFullWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, - CarLog.TAG_POWER); - mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, - CarLog.TAG_POWER); - mDisplayListener = new DisplayStateListener(); - mFilesDir = context.getFilesDir(); - } - - @Override - public void startDisplayStateMonitoring(CarPowerManagementService service) { - synchronized (this) { - mService = service; - mDisplayStateSet = isMainDisplayOn(); - } - mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); - } - - @Override - public void stopDisplayStateMonitoring() { - mDisplayManager.unregisterDisplayListener(mDisplayListener); - } - - @Override - public void setDisplayState(boolean on) { - synchronized (this) { - mDisplayStateSet = on; - } - if (on) { - switchToFullWakeLock(); - Log.i(CarLog.TAG_POWER, "on display"); - mPowerManager.wakeUp(SystemClock.uptimeMillis()); - } else { - switchToPartialWakeLock(); - Log.i(CarLog.TAG_POWER, "off display"); - mPowerManager.goToSleep(SystemClock.uptimeMillis()); - } - } - - private boolean isMainDisplayOn() { - Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); - return disp.getState() == Display.STATE_ON; - } - - @Override - public void shutdown() { - mPowerManager.shutdown(false /* no confirm*/, null, true /* true */); - } - - @Override - public void enterDeepSleep(int wakeupTimeSec) { - //TODO set wake up time, bug: 32061842 - mPowerManager.goToSleep(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, - PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - } - - @Override - public void switchToPartialWakeLock() { - if (!mPartialWakeLock.isHeld()) { - mPartialWakeLock.acquire(); - } - if (mFullWakeLock.isHeld()) { - mFullWakeLock.release(); - } - } - - @Override - public void switchToFullWakeLock() { - if (!mFullWakeLock.isHeld()) { - mFullWakeLock.acquire(); - } - if (mPartialWakeLock.isHeld()) { - mPartialWakeLock.release(); - } - } - - @Override - public void releaseAllWakeLocks() { - if (mPartialWakeLock.isHeld()) { - mPartialWakeLock.release(); - } - if (mFullWakeLock.isHeld()) { - mFullWakeLock.release(); - } - } - - @Override - public File getFilesDir() { - return mFilesDir; - } - - @Override - public void scheduleActionForBootCompleted(Runnable action, Duration delay) { - if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) { - // TODO: consider adding some degree of randomness here - delay = MIN_BOOT_COMPLETE_ACTION_DELAY; - } - if (mActionsList.isEmpty()) { - final int corePoolSize = 1; - mExecutorService = Executors.newScheduledThreadPool(corePoolSize); - IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - mContext.registerReceiver(mBroadcastReceiver, intentFilter); - } - mActionsList.add(Pair.create(action, delay)); - } - - private void handleMainDisplayChanged() { - boolean isOn = isMainDisplayOn(); - CarPowerManagementService service; - synchronized (this) { - if (mDisplayStateSet == isOn) { // same as what is set - return; - } - service = mService; - } - service.handleMainDisplayChanged(isOn); - } - - private class DisplayStateListener implements DisplayManager.DisplayListener { - - @Override - public void onDisplayAdded(int displayId) { - //ignore - } - - @Override - public void onDisplayChanged(int displayId) { - if (displayId == Display.DEFAULT_DISPLAY) { - handleMainDisplayChanged(); - } - } - - @Override - public void onDisplayRemoved(int displayId) { - //ignore - } - } - } -}
\ No newline at end of file diff --git a/service/src/com/android/car/UptimeTracker.java b/service/src/com/android/car/UptimeTracker.java index 1b8906fa54..2a1d26eae1 100644 --- a/service/src/com/android/car/UptimeTracker.java +++ b/service/src/com/android/car/UptimeTracker.java @@ -16,15 +16,13 @@ package com.android.car; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; -import static java.util.concurrent.TimeUnit.MILLISECONDS; - -import android.annotation.Nullable; -import android.os.SystemClock; import android.util.JsonReader; import android.util.JsonWriter; import android.util.Log; +import com.android.car.systeminterface.SystemInterface; + +import com.android.car.systeminterface.TimeInterface; import com.android.internal.annotations.VisibleForTesting; import java.io.File; @@ -33,7 +31,6 @@ import java.io.FileWriter; import java.io.IOException; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ScheduledExecutorService; /** * A class that can keep track of how long its instances are alive for. @@ -60,46 +57,6 @@ import java.util.concurrent.ScheduledExecutorService; * ensure that crashes do not cause more than a certain amount of uptime to go untracked. */ public class UptimeTracker { - @VisibleForTesting - interface TimingProvider { - long getCurrentRealtime(); - void schedule(Runnable r, long delay); - void cancelAll(); - } - - private static final class DefaultTimingProvider implements TimingProvider { - @Nullable - private final SystemInterface mSystemInterface; - private final ScheduledExecutorService mExecutor = newSingleThreadScheduledExecutor(); - - DefaultTimingProvider() { - this(null); - } - - DefaultTimingProvider(SystemInterface systemInterface) { - mSystemInterface = systemInterface; - } - - @Override - public long getCurrentRealtime() { - if (mSystemInterface != null) { - return mSystemInterface.getUptime(false); - } else { - return SystemClock.uptimeMillis(); - } - } - - @Override - public void schedule(Runnable r, long delay) { - mExecutor.scheduleWithFixedDelay(r, delay, delay, MILLISECONDS); - } - - @Override - public void cancelAll() { - mExecutor.shutdownNow(); - } - } - /** * In order to prevent excessive wear-out of the storage, do not allow snapshots to happen * more frequently than this value @@ -131,43 +88,42 @@ public class UptimeTracker { /** * The source of real-time and scheduling */ - private TimingProvider mTimingProvider; + private TimeInterface mTimeInterface; public UptimeTracker(File file) { this(file, DEFAULT_SNAPSHOT_INTERVAL_MS); } public UptimeTracker(File file, long snapshotInterval) { - this(file, snapshotInterval, new DefaultTimingProvider()); + this(file, snapshotInterval, new TimeInterface.DefaultImpl()); } UptimeTracker(File file, long snapshotInterval, SystemInterface systemInterface) { - this(file, snapshotInterval, new DefaultTimingProvider(systemInterface)); + this(file, snapshotInterval, systemInterface.getTimeInterface()); } - // By default, SystemClock::elapsedRealtime is used as the source of the uptime clock - // and a ScheduledExecutorService provides snapshot synchronization. For testing purposes - // this constructor allows using a controlled source of time information and scheduling. + // This constructor allows one to replace the source of time-based truths with + // a mock version. This is mostly useful for testing purposes. @VisibleForTesting UptimeTracker(File file, long snapshotInterval, - TimingProvider timingProvider) { + TimeInterface timeInterface) { snapshotInterval = Math.max(snapshotInterval, MINIMUM_SNAPSHOT_INTERVAL_MS); mUptimeFile = Objects.requireNonNull(file); - mTimingProvider = timingProvider; - mLastRealTimeSnapshot = mTimingProvider.getCurrentRealtime(); + mTimeInterface = timeInterface; + mLastRealTimeSnapshot = mTimeInterface.getUptime(TimeInterface.EXCLUDE_DEEP_SLEEP_TIME); mHistoricalUptime = Optional.empty(); - mTimingProvider.schedule(this::flushSnapshot, snapshotInterval); + mTimeInterface.scheduleAction(this::flushSnapshot, snapshotInterval); } void onDestroy() { synchronized (mLock) { - if (mTimingProvider != null) { - mTimingProvider.cancelAll(); + if (mTimeInterface != null) { + mTimeInterface.cancelAllActions(); } flushSnapshot(); - mTimingProvider = null; + mTimeInterface = null; mUptimeFile = null; } } @@ -179,11 +135,12 @@ public class UptimeTracker { */ long getTotalUptime() { synchronized (mLock) { - if (mTimingProvider == null) { + if (mTimeInterface == null) { return 0; } return getHistoricalUptimeLocked() + ( - mTimingProvider.getCurrentRealtime() - mLastRealTimeSnapshot); + mTimeInterface.getUptime(TimeInterface.EXCLUDE_DEEP_SLEEP_TIME) + - mLastRealTimeSnapshot); } } @@ -216,7 +173,8 @@ public class UptimeTracker { try { long newUptime = getTotalUptime(); mHistoricalUptime = Optional.of(newUptime); - mLastRealTimeSnapshot = mTimingProvider.getCurrentRealtime(); + mLastRealTimeSnapshot = mTimeInterface.getUptime( + TimeInterface.EXCLUDE_DEEP_SLEEP_TIME); JsonWriter writer = new JsonWriter(new FileWriter(mUptimeFile)); writer.beginObject(); diff --git a/service/src/com/android/car/systeminterface/DisplayInterface.java b/service/src/com/android/car/systeminterface/DisplayInterface.java new file mode 100644 index 0000000000..f798b0d096 --- /dev/null +++ b/service/src/com/android/car/systeminterface/DisplayInterface.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Log; +import android.view.Display; +import com.android.car.CarLog; +import com.android.car.CarPowerManagementService; + +/** + * Interface that abstracts display operations + */ +public interface DisplayInterface { + void setDisplayState(boolean on); + void startDisplayStateMonitoring(CarPowerManagementService service); + void stopDisplayStateMonitoring(); + + class DefaultImpl implements DisplayInterface { + private final DisplayManager mDisplayManager; + private final PowerManager mPowerManager; + private final WakeLockInterface mWakeLockInterface; + private CarPowerManagementService mService; + private boolean mDisplayStateSet; + private final DisplayManager.DisplayListener mDisplayListener = new DisplayListener() { + @Override + public void onDisplayAdded(int displayId) { + //ignore + } + + @Override + public void onDisplayRemoved(int displayId) { + //ignore + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + handleMainDisplayChanged(); + } + } + }; + + DefaultImpl(Context context, WakeLockInterface wakeLockInterface) { + mWakeLockInterface = wakeLockInterface; + mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + } + + private void handleMainDisplayChanged() { + boolean isOn = isMainDisplayOn(); + CarPowerManagementService service; + synchronized (this) { + if (mDisplayStateSet == isOn) { // same as what is set + return; + } + service = mService; + } + service.handleMainDisplayChanged(isOn); + } + + private boolean isMainDisplayOn() { + Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); + return disp.getState() == Display.STATE_ON; + } + + @Override + public void startDisplayStateMonitoring(CarPowerManagementService service) { + synchronized (this) { + mService = service; + mDisplayStateSet = isMainDisplayOn(); + } + mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); + } + + @Override + public void stopDisplayStateMonitoring() { + mDisplayManager.unregisterDisplayListener(mDisplayListener); + } + + @Override + public void setDisplayState(boolean on) { + synchronized (this) { + mDisplayStateSet = on; + } + if (on) { + mWakeLockInterface.switchToFullWakeLock(); + Log.i(CarLog.TAG_POWER, "on display"); + mPowerManager.wakeUp(SystemClock.uptimeMillis()); + } else { + mWakeLockInterface.switchToPartialWakeLock(); + Log.i(CarLog.TAG_POWER, "off display"); + mPowerManager.goToSleep(SystemClock.uptimeMillis()); + } + } + } +} diff --git a/service/src/com/android/car/systeminterface/IOInterface.java b/service/src/com/android/car/systeminterface/IOInterface.java new file mode 100644 index 0000000000..2ce917495b --- /dev/null +++ b/service/src/com/android/car/systeminterface/IOInterface.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import android.content.Context; +import java.io.File; + +/** + * Interface that abstracts I/O operations + */ +public interface IOInterface { + File getFilesDir(); + + class DefaultImpl implements IOInterface { + private final File mFilesDir; + + DefaultImpl(Context context) { + mFilesDir = context.getFilesDir(); + } + + @Override + public File getFilesDir() { + return mFilesDir; + } + } +} diff --git a/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java b/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java new file mode 100644 index 0000000000..5825f8f250 --- /dev/null +++ b/service/src/com/android/car/systeminterface/StorageMonitoringInterface.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import com.android.car.storagemonitoring.EMmcWearInformationProvider; +import com.android.car.storagemonitoring.ProcfsUidIoStatsProvider; +import com.android.car.storagemonitoring.UfsWearInformationProvider; +import com.android.car.storagemonitoring.UidIoStatsProvider; +import com.android.car.storagemonitoring.WearInformationProvider; + +/** + * Interface that abstracts storage monitoring operations + */ +public interface StorageMonitoringInterface { + default WearInformationProvider[] getFlashWearInformationProviders() { + return new WearInformationProvider[] { + new EMmcWearInformationProvider(), + new UfsWearInformationProvider() + }; + } + + default UidIoStatsProvider getUidIoStatsProvider() { + return new ProcfsUidIoStatsProvider(); + } + + class DefaultImpl implements StorageMonitoringInterface {} +} diff --git a/service/src/com/android/car/systeminterface/SystemInterface.java b/service/src/com/android/car/systeminterface/SystemInterface.java new file mode 100644 index 0000000000..72a8a0ac57 --- /dev/null +++ b/service/src/com/android/car/systeminterface/SystemInterface.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import android.content.Context; +import com.android.car.CarPowerManagementService; +import com.android.car.storagemonitoring.UidIoStatsProvider; +import com.android.car.storagemonitoring.WearInformationProvider; +import java.io.File; +import java.time.Duration; +import java.util.Objects; + +/** + * This class contains references to all the different wrapper interfaces between + * CarService and the Android OS APIs. + */ +public final class SystemInterface implements DisplayInterface, IOInterface, + StorageMonitoringInterface, SystemStateInterface, TimeInterface, + WakeLockInterface { + private final DisplayInterface mDisplayInterface; + private final IOInterface mIOInterface; + private final StorageMonitoringInterface mStorageMonitoringInterface; + private final SystemStateInterface mSystemStateInterface; + private final TimeInterface mTimeInterface; + private final WakeLockInterface mWakeLockInterface; + + SystemInterface(DisplayInterface displayInterface, + IOInterface ioInterface, + StorageMonitoringInterface storageMonitoringInterface, + SystemStateInterface systemStateInterface, + TimeInterface timeInterface, + WakeLockInterface wakeLockInterface) { + mDisplayInterface = displayInterface; + mIOInterface = ioInterface; + mStorageMonitoringInterface = storageMonitoringInterface; + mSystemStateInterface = systemStateInterface; + mTimeInterface = timeInterface; + mWakeLockInterface = wakeLockInterface; + } + + public DisplayInterface getDisplayInterface() { return mDisplayInterface; } + public IOInterface getIOInterface() { return mIOInterface; } + public SystemStateInterface getSystemStateInterface() { return mSystemStateInterface; } + public TimeInterface getTimeInterface() { return mTimeInterface; } + public WakeLockInterface getWakeLockInterface() { return mWakeLockInterface; } + + @Override + public File getFilesDir() { + return mIOInterface.getFilesDir(); + } + + @Override + public void releaseAllWakeLocks() { + mWakeLockInterface.releaseAllWakeLocks(); + } + + @Override + public void switchToPartialWakeLock() { + mWakeLockInterface.switchToPartialWakeLock(); + } + + @Override + public void switchToFullWakeLock() { + mWakeLockInterface.switchToFullWakeLock(); + } + + @Override + public long getUptime() { + return mTimeInterface.getUptime(); + } + + @Override + public long getUptime(boolean includeDeepSleepTime) { + return mTimeInterface.getUptime(includeDeepSleepTime); + } + + @Override + public void scheduleAction(Runnable r, long delayMs) { + mTimeInterface.scheduleAction(r, delayMs); + } + + @Override + public void cancelAllActions() { + mTimeInterface.cancelAllActions(); + } + + @Override + public void setDisplayState(boolean on) { + mDisplayInterface.setDisplayState(on); + } + + @Override + public void startDisplayStateMonitoring(CarPowerManagementService service) { + mDisplayInterface.startDisplayStateMonitoring(service); + } + + @Override + public void stopDisplayStateMonitoring() { + mDisplayInterface.stopDisplayStateMonitoring(); + } + + @Override + public WearInformationProvider[] getFlashWearInformationProviders() { + return mStorageMonitoringInterface.getFlashWearInformationProviders(); + } + + @Override + public UidIoStatsProvider getUidIoStatsProvider() { + return mStorageMonitoringInterface.getUidIoStatsProvider(); + } + + @Override + public void shutdown() { + mSystemStateInterface.shutdown(); + } + + @Override + public void enterDeepSleep(int wakeupTimeSec) { + mSystemStateInterface.enterDeepSleep(wakeupTimeSec); + } + + @Override + public void scheduleActionForBootCompleted(Runnable action, Duration delay) { + mSystemStateInterface.scheduleActionForBootCompleted(action, delay); + } + + @Override + public boolean isWakeupCausedByTimer() { + return mSystemStateInterface.isWakeupCausedByTimer(); + } + + @Override + public boolean isSystemSupportingDeepSleep() { + return mSystemStateInterface.isSystemSupportingDeepSleep(); + } + + public final static class Builder { + private DisplayInterface mDisplayInterface; + private IOInterface mIOInterface; + private StorageMonitoringInterface mStorageMonitoringInterface; + private SystemStateInterface mSystemStateInterface; + private TimeInterface mTimeInterface; + private WakeLockInterface mWakeLockInterface; + + private Builder() {} + + public static Builder newSystemInterface() { + return new Builder(); + } + + public static Builder defaultSystemInterface(Context context) { + context = Objects.requireNonNull(context); + Builder builder = newSystemInterface(); + builder.withWakeLockInterface(new WakeLockInterface.DefaultImpl(context)); + builder.withDisplayInterface(new DisplayInterface.DefaultImpl(context, + builder.mWakeLockInterface)); + builder.withIOInterface(new IOInterface.DefaultImpl(context)); + builder.withStorageMonitoringInterface(new StorageMonitoringInterface.DefaultImpl()); + builder.withSystemStateInterface(new SystemStateInterface.DefaultImpl(context)); + return builder.withTimeInterface(new TimeInterface.DefaultImpl()); + } + + public static Builder fromBuilder(Builder otherBuilder) { + return newSystemInterface() + .withDisplayInterface(otherBuilder.mDisplayInterface) + .withIOInterface(otherBuilder.mIOInterface) + .withStorageMonitoringInterface(otherBuilder.mStorageMonitoringInterface) + .withSystemStateInterface(otherBuilder.mSystemStateInterface) + .withTimeInterface(otherBuilder.mTimeInterface) + .withWakeLockInterface(otherBuilder.mWakeLockInterface); + } + + public Builder withDisplayInterface(DisplayInterface displayInterface) { + mDisplayInterface = displayInterface; + return this; + } + + public Builder withIOInterface(IOInterface ioInterface) { + mIOInterface = ioInterface; + return this; + } + + public Builder withStorageMonitoringInterface(StorageMonitoringInterface + storageMonitoringInterface) { + mStorageMonitoringInterface = storageMonitoringInterface; + return this; + } + + public Builder withSystemStateInterface(SystemStateInterface systemStateInterface) { + mSystemStateInterface = systemStateInterface; + return this; + } + + public Builder withTimeInterface(TimeInterface timeInterface) { + mTimeInterface = timeInterface; + return this; + } + + public Builder withWakeLockInterface(WakeLockInterface wakeLockInterface) { + mWakeLockInterface = wakeLockInterface; + return this; + } + + public SystemInterface build() { + return new SystemInterface(Objects.requireNonNull(mDisplayInterface), + Objects.requireNonNull(mIOInterface), + Objects.requireNonNull(mStorageMonitoringInterface), + Objects.requireNonNull(mSystemStateInterface), + Objects.requireNonNull(mTimeInterface), + Objects.requireNonNull(mWakeLockInterface)); + } + } +} diff --git a/service/src/com/android/car/systeminterface/SystemStateInterface.java b/service/src/com/android/car/systeminterface/SystemStateInterface.java new file mode 100644 index 0000000000..bfb63b8554 --- /dev/null +++ b/service/src/com/android/car/systeminterface/SystemStateInterface.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; +import android.os.SystemClock; +import android.util.Pair; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Interface that abstracts system status (booted, sleeping, ...) operations + */ +public interface SystemStateInterface { + void shutdown(); + void enterDeepSleep(int wakeupTimeSec); + void scheduleActionForBootCompleted(Runnable action, Duration delay); + + default boolean isWakeupCausedByTimer() { + //TODO bug: 32061842, check wake up reason and do necessary operation information should + // come from kernel. it can be either power on or wake up for maintenance + // power on will involve GPIO trigger from power controller + // its own wakeup will involve timer expiration. + return false; + } + + default boolean isSystemSupportingDeepSleep() { + //TODO should return by checking some kernel suspend control sysfs, bug: 32061842 + return false; + } + + class DefaultImpl implements SystemStateInterface { + private final static Duration MIN_BOOT_COMPLETE_ACTION_DELAY = Duration.ofSeconds(10); + + private final Context mContext; + private final PowerManager mPowerManager; + private List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); + private ScheduledExecutorService mExecutorService; + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + for (Pair<Runnable, Duration> action : mActionsList) { + mExecutorService.schedule(action.first, + action.second.toMillis(), TimeUnit.MILLISECONDS); + } + } + } + }; + + DefaultImpl(Context context) { + mContext = context; + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + } + + @Override + public void shutdown() { + mPowerManager.shutdown(false /* no confirm*/, null, true /* true */); + } + + @Override + public void enterDeepSleep(int wakeupTimeSec) { + //TODO set wake up time, bug: 32061842 + mPowerManager.goToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, + PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); + } + + @Override + public void scheduleActionForBootCompleted(Runnable action, Duration delay) { + if (MIN_BOOT_COMPLETE_ACTION_DELAY.compareTo(delay) < 0) { + // TODO: consider adding some degree of randomness here + delay = MIN_BOOT_COMPLETE_ACTION_DELAY; + } + if (mActionsList.isEmpty()) { + final int corePoolSize = 1; + mExecutorService = Executors.newScheduledThreadPool(corePoolSize); + IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); + } + mActionsList.add(Pair.create(action, delay)); + } + + } +} diff --git a/service/src/com/android/car/systeminterface/TimeInterface.java b/service/src/com/android/car/systeminterface/TimeInterface.java new file mode 100644 index 0000000000..dea1153050 --- /dev/null +++ b/service/src/com/android/car/systeminterface/TimeInterface.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; + +import android.os.SystemClock; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Interface that abstracts time operations + */ +public interface TimeInterface { + public static final boolean INCLUDE_DEEP_SLEEP_TIME = true; + public static final boolean EXCLUDE_DEEP_SLEEP_TIME = false; + + default long getUptime() { + return getUptime(EXCLUDE_DEEP_SLEEP_TIME); + } + default long getUptime(boolean includeDeepSleepTime) { + return includeDeepSleepTime ? + SystemClock.elapsedRealtime() : + SystemClock.uptimeMillis(); + } + + void scheduleAction(Runnable r, long delayMs); + void cancelAllActions(); + + class DefaultImpl implements TimeInterface { + private final ScheduledExecutorService mExecutor = newSingleThreadScheduledExecutor(); + + @Override + public void scheduleAction(Runnable r, long delayMs) { + mExecutor.scheduleAtFixedRate(r, delayMs, delayMs, TimeUnit.MILLISECONDS); + } + + @Override + public void cancelAllActions() { + mExecutor.shutdownNow(); + } + } +} diff --git a/service/src/com/android/car/systeminterface/WakeLockInterface.java b/service/src/com/android/car/systeminterface/WakeLockInterface.java new file mode 100644 index 0000000000..c7a5f8e3e3 --- /dev/null +++ b/service/src/com/android/car/systeminterface/WakeLockInterface.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.car.systeminterface; + +import android.content.Context; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import com.android.car.CarLog; + +/** + * Interface that abstracts wake lock operations + */ +public interface WakeLockInterface { + void releaseAllWakeLocks(); + void switchToPartialWakeLock(); + void switchToFullWakeLock(); + + class DefaultImpl implements WakeLockInterface { + private final WakeLock mPartialWakeLock; + private final WakeLock mFullWakeLock; + + DefaultImpl(Context context) { + PowerManager powerManager = + (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mFullWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, + CarLog.TAG_POWER); + mPartialWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + CarLog.TAG_POWER); + } + + @Override + public void switchToPartialWakeLock() { + if (!mPartialWakeLock.isHeld()) { + mPartialWakeLock.acquire(); + } + if (mFullWakeLock.isHeld()) { + mFullWakeLock.release(); + } + } + + @Override + public void switchToFullWakeLock() { + if (!mFullWakeLock.isHeld()) { + mFullWakeLock.acquire(); + } + if (mPartialWakeLock.isHeld()) { + mPartialWakeLock.release(); + } + } + + @Override + public void releaseAllWakeLocks() { + if (mPartialWakeLock.isHeld()) { + mPartialWakeLock.release(); + } + if (mFullWakeLock.isHeld()) { + mFullWakeLock.release(); + } + } + } +} diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarEmulator.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarEmulator.java index 474b3416a0..064d06d5f6 100644 --- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarEmulator.java +++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/CarEmulator.java @@ -1,3 +1,4 @@ + /* * Copyright (C) 2015 The Android Open Source Project * @@ -35,7 +36,7 @@ import android.os.SystemClock; import android.util.SparseIntArray; import com.android.car.ICarImpl; -import com.android.car.SystemInterface; +import com.android.car.systeminterface.SystemInterface; import com.android.car.vehiclehal.VehiclePropValueBuilder; import com.android.car.vehiclehal.test.MockedVehicleHal; import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; @@ -66,7 +67,8 @@ public class CarEmulator { private CarEmulator(Context context) { mHalEmulator = new MockedVehicleHal(); ICarImpl carService = new ICarImpl(context, mHalEmulator, - SystemInterface.createDefault(context), null /* error notifier */); + SystemInterface.Builder.defaultSystemInterface(context).build(), + null /* error notifier */); mCar = new Car(context, carService, null /* Handler */); } diff --git a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java index 64d9b826a4..b0ac2e793b 100644 --- a/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java +++ b/tests/carservice_test/src/com/android/car/CarPowerManagementTest.java @@ -26,6 +26,8 @@ import android.hardware.automotive.vehicle.V2_0.VehicleProperty; import android.os.SystemClock; import android.test.suitebuilder.annotation.MediumTest; +import com.android.car.systeminterface.DisplayInterface; +import com.android.car.systeminterface.SystemInterface; import com.google.android.collect.Lists; import com.android.car.vehiclehal.VehiclePropValueBuilder; @@ -40,6 +42,13 @@ import java.util.concurrent.TimeUnit; public class CarPowerManagementTest extends MockedCarTestBase { private final PowerStatePropertyHandler mPowerStateHandler = new PowerStatePropertyHandler(); + private final MockDisplayInterface mMockDisplayInterface = new MockDisplayInterface(); + + @Override + protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() { + SystemInterface.Builder builder = super.getSystemInterfaceBuilder(); + return builder.withDisplayInterface(mMockDisplayInterface); + } private void setupPowerPropertyAndStart(boolean allowSleep) { addProperty(VehicleProperty.AP_POWER_STATE, mPowerStateHandler) @@ -70,9 +79,9 @@ public class CarPowerManagementTest extends MockedCarTestBase { assertBootComplete(); for (int i = 0; i < 2; i++) { mPowerStateHandler.sendPowerState(VehicleApPowerState.ON_DISP_OFF, 0); - waitForFakeDisplayState(false); + mMockDisplayInterface.waitForDisplayState(false); mPowerStateHandler.sendPowerState(VehicleApPowerState.ON_FULL, 0); - waitForFakeDisplayState(true); + mMockDisplayInterface.waitForDisplayState(true); } } @@ -107,6 +116,33 @@ public class CarPowerManagementTest extends MockedCarTestBase { assertEquals(0, first[1]); } + private final class MockDisplayInterface implements DisplayInterface { + private boolean mDisplayOn = true; + private final Semaphore mDisplayStateWait = new Semaphore(0); + + @Override + public synchronized void setDisplayState(boolean on) { + mDisplayOn = on; + mDisplayStateWait.release(); + } + + boolean waitForDisplayState(boolean expectedState) + throws Exception { + if (expectedState == mDisplayOn) { + return true; + } + mDisplayStateWait.tryAcquire(MockedCarTestBase.SHORT_WAIT_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + return expectedState == mDisplayOn; + } + + @Override + public void startDisplayStateMonitoring(CarPowerManagementService service) {} + + @Override + public void stopDisplayStateMonitoring() {} + } + private class PowerStatePropertyHandler implements VehicleHalPropertyHandler { private int mPowerState = VehicleApPowerState.ON_FULL; diff --git a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java index 7d7387cbf1..53e3abbd21 100644 --- a/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java +++ b/tests/carservice_test/src/com/android/car/CarStorageMonitoringTest.java @@ -25,13 +25,22 @@ import android.car.storagemonitoring.WearEstimateChange; import android.test.suitebuilder.annotation.MediumTest; import android.util.JsonWriter; import android.util.Log; +import android.util.Pair; import com.android.car.storagemonitoring.WearEstimateRecord; import com.android.car.storagemonitoring.WearHistory; import com.android.car.storagemonitoring.WearInformation; +import com.android.car.storagemonitoring.WearInformationProvider; +import com.android.car.systeminterface.StorageMonitoringInterface; +import com.android.car.systeminterface.SystemInterface; +import com.android.car.systeminterface.SystemStateInterface; +import com.android.car.systeminterface.TimeInterface; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -123,17 +132,29 @@ public class CarStorageMonitoringTest extends MockedCarTestBase { .atTimestamp(Instant.ofEpochMilli(17000)).build()))); }}; + private final MockSystemStateInterface mMockSystemStateInterface = + new MockSystemStateInterface(); + private final MockStorageMonitoringInterface mMockStorageMonitoringInterface = + new MockStorageMonitoringInterface(); + private CarStorageMonitoringManager mCarStorageMonitoringManager; @Override + protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() { + SystemInterface.Builder builder = super.getSystemInterfaceBuilder(); + return builder.withSystemStateInterface(mMockSystemStateInterface) + .withStorageMonitoringInterface(mMockStorageMonitoringInterface) + .withTimeInterface(new MockTimeInterface()); + } + + @Override protected synchronized void configureFakeSystemInterface() { try { final String testName = getName(); final WearData wearData = PER_TEST_WEAR_DATA.getOrDefault(testName, WearData.DEFAULT); final WearHistory wearHistory = wearData.wearHistory; - setFlashWearInformation(wearData.wearInformation); - setUptimeProvider( (boolean b) -> 0 ); + mMockStorageMonitoringInterface.setWearInformation(wearData.wearInformation); if (wearHistory != null) { File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(), @@ -145,7 +166,7 @@ public class CarStorageMonitoringTest extends MockedCarTestBase { if (wearData.uptime > 0) { File uptimeFile = new File(getFakeSystemInterface().getFilesDir(), - CarStorageMonitoringService.UPTIME_TRACKER_FILENAME); + CarStorageMonitoringService.UPTIME_TRACKER_FILENAME); try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) { jsonWriter.beginObject(); jsonWriter.name("uptime").value(wearData.uptime); @@ -156,13 +177,14 @@ public class CarStorageMonitoringTest extends MockedCarTestBase { Log.e(TAG, "failed to configure fake system interface", e); fail("failed to configure fake system interface instance"); } + } @Override protected void setUp() throws Exception { super.setUp(); - fakeBootCompletedEvent(); + mMockSystemStateInterface.executeBootCompletedActions(); mCarStorageMonitoringManager = (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE); @@ -226,4 +248,59 @@ public class CarStorageMonitoringTest extends MockedCarTestBase { public void testAcceptableWearEvent() throws Exception { checkLastWearEvent(true); } + + static final class MockStorageMonitoringInterface implements StorageMonitoringInterface, + WearInformationProvider { + private WearInformation mWearInformation = null; + + void setWearInformation(WearInformation wearInformation) { + mWearInformation = wearInformation; + } + + @Override + public WearInformation load() { + return mWearInformation; + } + + @Override + public WearInformationProvider[] getFlashWearInformationProviders() { + return new WearInformationProvider[] {this}; + } + } + + static final class MockTimeInterface implements TimeInterface { + + @Override + public long getUptime(boolean includeDeepSleepTime) { + return 0; + } + + @Override + public void scheduleAction(Runnable r, long delayMs) {} + + @Override + public void cancelAllActions() {} + } + + static final class MockSystemStateInterface implements SystemStateInterface { + private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); + + @Override + public void shutdown() {} + + @Override + public void enterDeepSleep(int wakeupTimeSec) {} + + @Override + public void scheduleActionForBootCompleted(Runnable action, Duration delay) { + mActionsList.add(Pair.create(action, delay)); + mActionsList.sort(Comparator.comparing(d -> d.second)); + } + + void executeBootCompletedActions() { + for (Pair<Runnable, Duration> action : mActionsList) { + action.first.run(); + } + } + } } diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java index 1437e27df1..e6ed401260 100644 --- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java +++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java @@ -33,12 +33,16 @@ import android.os.Looper; import android.test.AndroidTestCase; import android.util.Log; -import android.util.Pair; import android.util.SparseArray; -import com.android.car.MockedCarTestBase.FakeSystemInterface.UptimeProvider; -import com.android.car.storagemonitoring.WearInformation; -import com.android.car.storagemonitoring.WearInformationProvider; +import com.android.car.systeminterface.DisplayInterface; +import com.android.car.systeminterface.IOInterface; +import com.android.car.systeminterface.StorageMonitoringInterface; +import com.android.car.systeminterface.SystemInterface; +import com.android.car.systeminterface.SystemInterface.Builder; +import com.android.car.systeminterface.SystemStateInterface; +import com.android.car.systeminterface.TimeInterface; +import com.android.car.systeminterface.WakeLockInterface; import com.android.car.test.utils.TemporaryDirectory; import com.android.car.vehiclehal.VehiclePropValueBuilder; import com.android.car.vehiclehal.test.MockedVehicleHal; @@ -50,14 +54,10 @@ import com.android.car.vehiclehal.test.VehiclePropConfigBuilder; import java.io.File; import java.io.IOException; import java.time.Duration; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; /** * Base class for testing with mocked vehicle HAL (=car). @@ -72,7 +72,8 @@ public class MockedCarTestBase extends AndroidTestCase { private android.car.Car mCar; private ICarImpl mCarImpl; private MockedVehicleHal mMockedVehicleHal; - private FakeSystemInterface mFakeSystemInterface; + private SystemInterface mFakeSystemInterface; + private final MockIOInterface mMockIOInterface = new MockIOInterface(); private final Semaphore mWaitForMain = new Semaphore(0); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); @@ -92,27 +93,24 @@ public class MockedCarTestBase extends AndroidTestCase { return mMockedVehicleHal; } - protected synchronized FakeSystemInterface getFakeSystemInterface() { + protected synchronized SystemInterface getFakeSystemInterface() { return mFakeSystemInterface; } protected synchronized void configureMockedHal() { } - protected synchronized void configureFakeSystemInterface() { + protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() { + return Builder.newSystemInterface() + .withSystemStateInterface(new MockSystemStateInterface()) + .withDisplayInterface(new MockDisplayInterface()) + .withIOInterface(mMockIOInterface) + .withStorageMonitoringInterface(new MockStorageMonitoringInterface()) + .withTimeInterface(new MockTimeInterface()) + .withWakeLockInterface(new MockWakeLockInterface()); } - protected synchronized void setFlashWearInformation(WearInformation wearInformation) { - mFakeSystemInterface.mWearInformationProvider.setWearInformation(wearInformation); - } - - protected synchronized void setUptimeProvider(UptimeProvider uptimeProvider) { - mFakeSystemInterface.mUptimeProvider = uptimeProvider; - } - - protected synchronized void fakeBootCompletedEvent() { - mFakeSystemInterface.executeBootCompletedActions(); - } + protected synchronized void configureFakeSystemInterface() {} @Override protected synchronized void setUp() throws Exception { @@ -127,7 +125,7 @@ public class MockedCarTestBase extends AndroidTestCase { .build()); configureMockedHal(); - mFakeSystemInterface = new FakeSystemInterface(); + mFakeSystemInterface = getSystemInterfaceBuilder().build(); configureFakeSystemInterface(); Context context = getCarServiceContext(); @@ -146,7 +144,7 @@ public class MockedCarTestBase extends AndroidTestCase { mCar.disconnect(); mCarImpl.release(); - mFakeSystemInterface.tearDown(); + mMockIOInterface.tearDown(); } protected Context getCarServiceContext() throws NameNotFoundException { @@ -233,10 +231,6 @@ public class MockedCarTestBase extends AndroidTestCase { mWaitForMain.acquire(); } - protected boolean waitForFakeDisplayState(boolean expectedState) throws Exception { - return mFakeSystemInterface.waitForDisplayState(expectedState, SHORT_WAIT_TIMEOUT_MS); - } - public static <T> void assertArrayEquals(T[] expected, T[] actual) { if (!Arrays.equals(expected, actual)) { fail("expected:<" + Arrays.toString(expected) + @@ -293,76 +287,20 @@ public class MockedCarTestBase extends AndroidTestCase { } } - static class FakeSystemInterface implements SystemInterface { - interface UptimeProvider { - long getUptime(boolean includeDeepSleepTime); - } - - private boolean mDisplayOn = true; - private final Semaphore mDisplayStateWait = new Semaphore(0); - private final class FakeWearInformationProvider implements WearInformationProvider { - private WearInformation mWearInformation = null; - public void setWearInformation(WearInformation wearInformation) { - mWearInformation = wearInformation; - } - - @Override - public WearInformation load() { - return mWearInformation; - } - } - private final FakeWearInformationProvider mWearInformationProvider = - new FakeWearInformationProvider(); - private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>(); - - private TemporaryDirectory mFilesDir = null; - private UptimeProvider mUptimeProvider = null; - - @Override - public synchronized void setDisplayState(boolean on) { - mDisplayOn = on; - mDisplayStateWait.release(); - } - - boolean waitForDisplayState(boolean expectedState, long timeoutMs) - throws Exception { - if (expectedState == mDisplayOn) { - return true; - } - mDisplayStateWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS); - return expectedState == mDisplayOn; - } - - @Override - public void releaseAllWakeLocks() { - } - - @Override - public void shutdown() { } - - @Override - public void enterDeepSleep(int wakeupTimeSec) { } + static final class MockDisplayInterface implements DisplayInterface { @Override - public void switchToPartialWakeLock() { - } + public void setDisplayState(boolean on) {} @Override - public void switchToFullWakeLock() { - } + public void startDisplayStateMonitoring(CarPowerManagementService service) {} @Override - public void startDisplayStateMonitoring(CarPowerManagementService service) { - } - - @Override - public void stopDisplayStateMonitoring() { - } + public void stopDisplayStateMonitoring() {} + } - @Override - public WearInformationProvider[] getFlashWearInformationProviders() { - return new WearInformationProvider[] { mWearInformationProvider }; - } + static final class MockIOInterface implements IOInterface { + private TemporaryDirectory mFilesDir = null; @Override public File getFilesDir() { @@ -377,27 +315,7 @@ public class MockedCarTestBase extends AndroidTestCase { return mFilesDir.getDirectory(); } - @Override - public void scheduleActionForBootCompleted(Runnable action, Duration delay) { - mActionsList.add(Pair.create(action, delay)); - mActionsList.sort(Comparator.comparing(d -> d.second)); - } - - @Override - public long getUptime(boolean includeDeepSleepTime) { - if (mUptimeProvider != null) { - return mUptimeProvider.getUptime(includeDeepSleepTime); - } - return SystemInterface.super.getUptime(includeDeepSleepTime); - } - - void executeBootCompletedActions() { - for (Pair<Runnable, Duration> action : mActionsList) { - action.first.run(); - } - } - - void tearDown() { + public void tearDown() { if (mFilesDir != null) { try { mFilesDir.close(); @@ -407,4 +325,39 @@ public class MockedCarTestBase extends AndroidTestCase { } } } + + static final class MockStorageMonitoringInterface implements StorageMonitoringInterface {} + + static final class MockSystemStateInterface implements SystemStateInterface { + @Override + public void shutdown() {} + + @Override + public void enterDeepSleep(int wakeupTimeSec) {} + + @Override + public void scheduleActionForBootCompleted(Runnable action, Duration delay) {} + } + + static final class MockTimeInterface implements TimeInterface { + + @Override + public void scheduleAction(Runnable r, long delayMs) {} + + @Override + public void cancelAllActions() {} + } + + static final class MockWakeLockInterface implements WakeLockInterface { + + @Override + public void releaseAllWakeLocks() {} + + @Override + public void switchToPartialWakeLock() {} + + @Override + public void switchToFullWakeLock() {} + } + } 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 2ce1186ee7..db240490af 100644 --- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java @@ -16,7 +16,6 @@ package com.android.car; -import android.os.SystemClock; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; @@ -26,7 +25,11 @@ import com.android.car.CarPowerManagementService.PowerServiceEventListener; import com.android.car.hal.PowerHalService; import com.android.car.hal.PowerHalService.PowerState; -import com.android.car.storagemonitoring.WearInformationProvider; +import com.android.car.systeminterface.DisplayInterface; +import com.android.car.systeminterface.IOInterface; +import com.android.car.systeminterface.SystemInterface; +import com.android.car.systeminterface.SystemStateInterface; +import com.android.car.systeminterface.WakeLockInterface; import com.android.car.test.utils.TemporaryDirectory; import java.io.File; import java.io.IOException; @@ -40,8 +43,13 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { private static final long WAIT_TIMEOUT_MS = 2000; private static final long WAIT_TIMEOUT_LONG_MS = 5000; + private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface(); + private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface(); + private final MockWakeLockInterface mWakeLockInterface = new MockWakeLockInterface(); + private final MockIOInterface mIOInterface = new MockIOInterface(); + private MockedPowerHalService mPowerHal; - private SystemInterfaceImpl mSystemInterface; + private SystemInterface mSystemInterface; private CarPowerManagementService mService; private final PowerEventListener mPowerEventListener = new PowerEventListener(); private PowerEventProcessingHandlerImpl mPowerEventProcessingHandler; @@ -51,7 +59,11 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { super.setUp(); mPowerHal = new MockedPowerHalService(true /*isPowerStateSupported*/, true /*isDeepSleepAllowed*/, true /*isTimedWakeupAllowed*/); - mSystemInterface = new SystemInterfaceImpl(); + mSystemInterface = SystemInterface.Builder.defaultSystemInterface(getContext()) + .withDisplayInterface(mDisplayInterface) + .withSystemStateInterface(mSystemStateInterface) + .withWakeLockInterface(mWakeLockInterface) + .withIOInterface(mIOInterface).build(); } @Override @@ -60,9 +72,7 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { if (mService != null) { mService.release(); } - if (mSystemInterface != null) { - mSystemInterface.tearDown(); - } + mIOInterface.tearDown(); } public void testBootComplete() throws Exception { @@ -84,15 +94,15 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); // it will call display on for initial state - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_ON_DISP_OFF, 0)); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); } public void testDisplayOn() throws Exception { // start with display off mSystemInterface.setDisplayState(false); - mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS); + mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS); mService = new CarPowerManagementService(mPowerHal, mSystemInterface); mService.init(); mService.registerPowerEventListener(mPowerEventListener); @@ -102,7 +112,7 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); // display should be turned on as it started with off state. - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); } public void testShutdown() throws Exception { @@ -114,14 +124,14 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, PowerHalService.FLAG_SHUTDOWN_IMMEDIATELY)); assertStateReceived(PowerHalService.SET_SHUTDOWN_START, wakeupTime); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); - mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); + mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS); } public void testShutdownWithProcessing() throws Exception { @@ -135,15 +145,15 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, 0)); mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, wakeupTime); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); - mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); + mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS); } public void testSleepEntryAndWakeup() throws Exception { @@ -155,14 +165,14 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); assertStateReceived(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0); mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); - int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); + int wakeupTimeReceived = mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); assertEquals(wakeupTime, wakeupTimeReceived); assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); @@ -180,19 +190,19 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, 0); mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); // set power on here without notification. PowerManager should check the state after sleep // exit mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_ON_DISP_OFF, 0), false); - int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); + int wakeupTimeReceived = mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); assertEquals(wakeupTime, wakeupTimeReceived); assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); @@ -210,35 +220,35 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { mService.registerPowerEventProcessingHandler(mPowerEventProcessingHandler); assertStateReceived(MockedPowerHalService.SET_BOOT_COMPLETE, 0); mPowerEventProcessingHandler.waitForPowerOn(WAIT_TIMEOUT_MS); - assertTrue(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); mPowerHal.setCurrentPowerState(new PowerState(PowerHalService.STATE_SHUTDOWN_PREPARE, PowerHalService.FLAG_SHUTDOWN_PARAM_CAN_SLEEP)); mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); - assertFalse(mSystemInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); + assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)); assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, 0); mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); - mSystemInterface.setWakeupCausedByTimer(true); - int wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); + mSystemStateInterface.setWakeupCausedByTimer(true); + int wakeupTimeReceived = mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); assertEquals(wakeupTime, wakeupTimeReceived); assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); mPowerEventListener.waitForSleepExit(WAIT_TIMEOUT_MS); // second processing after wakeup - assertFalse(mSystemInterface.getDisplayState()); + assertFalse(mDisplayInterface.getDisplayState()); mPowerEventProcessingHandler.waitForPrepareShutdown(WAIT_TIMEOUT_MS); assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, 0); mPowerEventListener.waitForSleepEntry(WAIT_TIMEOUT_MS); // PM will shutdown system as it was not woken-up due to timer and it is not power on. - mSystemInterface.setWakeupCausedByTimer(false); - wakeupTimeReceived = mSystemInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); + mSystemStateInterface.setWakeupCausedByTimer(false); + wakeupTimeReceived = mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS); assertEquals(wakeupTime, wakeupTimeReceived); assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0); assertStateReceived(PowerHalService.SET_SHUTDOWN_START, wakeupTime); mPowerEventListener.waitForShutdown(WAIT_TIMEOUT_MS); - mSystemInterface.waitForShutdown(WAIT_TIMEOUT_MS); - assertFalse(mSystemInterface.getDisplayState()); + mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS); + assertFalse(mDisplayInterface.getDisplayState()); } private void assertStateReceived(int expectedState, int expectedParam) throws Exception { @@ -268,16 +278,9 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { } } - private static class SystemInterfaceImpl implements SystemInterface { - + private static final class MockDisplayInterface implements DisplayInterface { private boolean mDisplayOn = true; private final Semaphore mDisplayStateWait = new Semaphore(0); - private final Semaphore mShutdownWait = new Semaphore(0); - private final Semaphore mSleepWait = new Semaphore(0); - private final Semaphore mSleepExitWait = new Semaphore(0); - private TemporaryDirectory mFilesDir; - private int mWakeupTime; - private boolean mWakeupCausedByTimer = false; @Override public synchronized void setDisplayState(boolean on) { @@ -295,8 +298,18 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { } @Override - public void releaseAllWakeLocks() { - } + public void startDisplayStateMonitoring(CarPowerManagementService service) {} + + @Override + public void stopDisplayStateMonitoring() {} + } + + private static final class MockSystemStateInterface implements SystemStateInterface { + private final Semaphore mShutdownWait = new Semaphore(0); + private final Semaphore mSleepWait = new Semaphore(0); + private final Semaphore mSleepExitWait = new Semaphore(0); + private int mWakeupTime; + private boolean mWakeupCausedByTimer = false; @Override public void shutdown() { @@ -317,11 +330,6 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { } } - @Override - public boolean isSystemSupportingDeepSleep() { - return true; - } - public int waitForSleepEntryAndWakeup(long timeoutMs) throws Exception { waitForSemaphore(mSleepWait, timeoutMs); mSleepExitWait.release(); @@ -329,26 +337,38 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { } @Override - public void switchToPartialWakeLock() { - } + public void scheduleActionForBootCompleted(Runnable action, Duration delay) {} @Override - public void switchToFullWakeLock() { + public boolean isWakeupCausedByTimer() { + Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer); + return mWakeupCausedByTimer; } - @Override - public void startDisplayStateMonitoring(CarPowerManagementService service) { + public synchronized void setWakeupCausedByTimer(boolean set) { + mWakeupCausedByTimer = set; } @Override - public void stopDisplayStateMonitoring() { + public boolean isSystemSupportingDeepSleep() { + return true; } + } + + private static final class MockWakeLockInterface implements WakeLockInterface { @Override - public synchronized boolean isWakeupCausedByTimer() { - Log.i(TAG, "isWakeupCausedByTimer:" + mWakeupCausedByTimer); - return mWakeupCausedByTimer; - } + public void releaseAllWakeLocks() {} + + @Override + public void switchToPartialWakeLock() {} + + @Override + public void switchToFullWakeLock() {} + } + + private static final class MockIOInterface implements IOInterface { + private TemporaryDirectory mFilesDir; @Override public File getFilesDir() { @@ -363,10 +383,7 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { return mFilesDir.getDirectory(); } - @Override - public void scheduleActionForBootCompleted(Runnable action, Duration delay) {} - - void tearDown() { + public void tearDown() { if (mFilesDir != null) { try { mFilesDir.close(); @@ -375,10 +392,6 @@ public class CarPowerManagementServiceTest extends AndroidTestCase { } } } - - public synchronized void setWakeupCausedByTimer(boolean set) { - mWakeupCausedByTimer = set; - } } private class PowerEventListener implements PowerServiceEventListener { diff --git a/tests/carservice_unit_test/src/com/android/car/UptimeTrackerTest.java b/tests/carservice_unit_test/src/com/android/car/UptimeTrackerTest.java index a5f12dd159..1b46825e0d 100644 --- a/tests/carservice_unit_test/src/com/android/car/UptimeTrackerTest.java +++ b/tests/carservice_unit_test/src/com/android/car/UptimeTrackerTest.java @@ -16,6 +16,7 @@ package com.android.car; import android.test.suitebuilder.annotation.MediumTest; +import com.android.car.systeminterface.TimeInterface; import com.android.car.test.utils.TemporaryFile; import junit.framework.TestCase; @@ -24,16 +25,16 @@ import junit.framework.TestCase; public class UptimeTrackerTest extends TestCase { static final String TAG = UptimeTrackerTest.class.getSimpleName(); - static final class TestTimingProvider implements UptimeTracker.TimingProvider { + static final class MockTimeInterface implements TimeInterface { private long mCurrentTime = 0; private Runnable mRunnable = null; - TestTimingProvider incrementTime(long by) { + MockTimeInterface incrementTime(long by) { mCurrentTime += by; return this; } - TestTimingProvider tick() { + MockTimeInterface tick() { if (mRunnable != null) { mRunnable.run(); } @@ -41,12 +42,12 @@ public class UptimeTrackerTest extends TestCase { } @Override - public long getCurrentRealtime() { + public long getUptime(boolean includeDeepSleepTime) { return mCurrentTime; } @Override - public void schedule(Runnable r, long delay) { + public void scheduleAction(Runnable r, long delayMs) { if (mRunnable != null) { throw new IllegalStateException("task already scheduled"); } @@ -54,7 +55,7 @@ public class UptimeTrackerTest extends TestCase { } @Override - public void cancelAll() { + public void cancelAllActions() { mRunnable = null; } } @@ -62,80 +63,80 @@ public class UptimeTrackerTest extends TestCase { private static final long SNAPSHOT_INTERVAL = 0; // actual time doesn't matter for this test public void testUptimeTrackerFromCleanSlate() throws Exception { - TestTimingProvider timingProvider = new TestTimingProvider(); + MockTimeInterface timeInterface = new MockTimeInterface(); try (TemporaryFile uptimeFile = new TemporaryFile(TAG)) { UptimeTracker uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); assertEquals(0, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(5000).tick(); + timeInterface.incrementTime(5000).tick(); assertEquals(5000, uptimeTracker.getTotalUptime()); - timingProvider.tick(); + timeInterface.tick(); assertEquals(5000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(1000).tick(); + timeInterface.incrementTime(1000).tick(); assertEquals(6000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(400).tick(); + timeInterface.incrementTime(400).tick(); assertEquals(6400, uptimeTracker.getTotalUptime()); } } public void testUptimeTrackerWithHistoricalState() throws Exception { - TestTimingProvider timingProvider = new TestTimingProvider(); + MockTimeInterface timeInterface = new MockTimeInterface(); try (TemporaryFile uptimeFile = new TemporaryFile(TAG)) { uptimeFile.write("{\"uptime\" : 5000}"); UptimeTracker uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); assertEquals(5000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(5000).tick(); + timeInterface.incrementTime(5000).tick(); assertEquals(10000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(1000).tick(); + timeInterface.incrementTime(1000).tick(); assertEquals(11000, uptimeTracker.getTotalUptime()); } } public void testUptimeTrackerAcrossHistoricalState() throws Exception { - TestTimingProvider timingProvider = new TestTimingProvider(); + MockTimeInterface timeInterface = new MockTimeInterface(); try (TemporaryFile uptimeFile = new TemporaryFile(TAG)) { uptimeFile.write("{\"uptime\" : 5000}"); UptimeTracker uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); assertEquals(5000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(5000).tick(); + timeInterface.incrementTime(5000).tick(); assertEquals(10000, uptimeTracker.getTotalUptime()); - timingProvider.incrementTime(500).tick(); + timeInterface.incrementTime(500).tick(); uptimeTracker.onDestroy(); - timingProvider.cancelAll(); + timeInterface.cancelAllActions(); uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); - timingProvider.incrementTime(3000).tick(); + timeInterface.incrementTime(3000).tick(); assertEquals(13500, uptimeTracker.getTotalUptime()); } } public void testUptimeTrackerShutdown() throws Exception { - TestTimingProvider timingProvider = new TestTimingProvider(); + MockTimeInterface timeInterface = new MockTimeInterface(); try (TemporaryFile uptimeFile = new TemporaryFile(TAG)) { UptimeTracker uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); - timingProvider.incrementTime(6000); + timeInterface.incrementTime(6000); uptimeTracker.onDestroy(); - timingProvider.cancelAll(); + timeInterface.cancelAllActions(); uptimeTracker = new UptimeTracker(uptimeFile.getFile(), - SNAPSHOT_INTERVAL, timingProvider); + SNAPSHOT_INTERVAL, timeInterface); assertEquals(6000, uptimeTracker.getTotalUptime()); } } |