diff options
22 files changed, 457 insertions, 222 deletions
diff --git a/api/api.go b/api/api.go index a003aba2707a..e09be03cd51d 100644 --- a/api/api.go +++ b/api/api.go @@ -146,7 +146,7 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { metalavaCmd := "$(location metalava)" // Silence reflection warnings. See b/168689341 metalavaCmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " - metalavaCmd += " --quiet --no-banner --format=v2 " + metalavaCmd += " --quiet merge-signatures --format=v2 " filename := txt.TxtFilename if txt.Scope != "public" { @@ -156,7 +156,7 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename) props.Tools = []string{"metalava"} props.Out = []string{filename} - props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --api $(out)") + props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --out $(out)") props.Srcs = append([]string{txt.BaseTxt}, createSrcs(txt.Modules, txt.ModuleTag)...) props.Dists = []android.Dist{ { diff --git a/core/java/android/os/PowerMonitor.java b/core/java/android/os/PowerMonitor.java index ebdd463d18f6..5fb0df7febc1 100644 --- a/core/java/android/os/PowerMonitor.java +++ b/core/java/android/os/PowerMonitor.java @@ -23,6 +23,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** + * A PowerMonitor represents either a Channel aka ODPM rail (on-device power monitor) or an + * EnergyConsumer, as defined in + * <a href="https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats">android.hardware.power.stats</a> + * * @hide */ public final class PowerMonitor implements Parcelable { @@ -92,6 +96,7 @@ public final class PowerMonitor implements Parcelable { return 0; } + @NonNull public static final Creator<PowerMonitor> CREATOR = new Creator<>() { @Override public PowerMonitor createFromParcel(@NonNull Parcel in) { diff --git a/core/java/android/os/PowerMonitorReadings.java b/core/java/android/os/PowerMonitorReadings.java index 3d7f859a7ed5..e76705917c7a 100644 --- a/core/java/android/os/PowerMonitorReadings.java +++ b/core/java/android/os/PowerMonitorReadings.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import java.util.Arrays; @@ -43,8 +44,8 @@ public final class PowerMonitorReadings { * @param powerMonitors array of power monitor (ODPM) rails, sorted by PowerMonitor.index * @hide */ - public PowerMonitorReadings(PowerMonitor[] powerMonitors, - long[] energyUws, long[] timestampsMs) { + public PowerMonitorReadings(@NonNull PowerMonitor[] powerMonitors, + @NonNull long[] energyUws, @NonNull long[] timestampsMs) { mPowerMonitors = powerMonitors; mEnergyUws = energyUws; mTimestampsMs = timestampsMs; @@ -55,7 +56,7 @@ public final class PowerMonitorReadings { * Does not persist across reboots. * Represents total energy: both on-battery and plugged-in. */ - public long getConsumedEnergyUws(PowerMonitor powerMonitor) { + public long getConsumedEnergyUws(@NonNull PowerMonitor powerMonitor) { int offset = Arrays.binarySearch(mPowerMonitors, powerMonitor, POWER_MONITOR_COMPARATOR); if (offset >= 0) { return mEnergyUws[offset]; @@ -64,9 +65,10 @@ public final class PowerMonitorReadings { } /** - * Elapsed realtime when the snapshot was taken. + * Elapsed realtime, in milliseconds, when the snapshot was taken. */ - public long getTimestampMs(PowerMonitor powerMonitor) { + @ElapsedRealtimeLong + public long getTimestamp(@NonNull PowerMonitor powerMonitor) { int offset = Arrays.binarySearch(mPowerMonitors, powerMonitor, POWER_MONITOR_COMPARATOR); if (offset >= 0) { return mTimestampsMs[offset]; diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index ab30a8bf1ea1..dfc43f46c57d 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -24,6 +24,8 @@ import android.content.Context; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; +import android.os.ConditionVariable; +import android.os.Handler; import android.os.IPowerStatsService; import android.os.PowerMonitor; import android.os.PowerMonitorReadings; @@ -36,8 +38,8 @@ import com.android.internal.app.IBatteryStats; import java.util.Arrays; import java.util.Comparator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; +import java.util.List; +import java.util.function.Consumer; /** * Provides access to data about how various system resources are used by applications. @@ -62,7 +64,8 @@ public class SystemHealthManager { private final IBatteryStats mBatteryStats; @Nullable private final IPowerStatsService mPowerStats; - private PowerMonitor[] mPowerMonitorsInfo; + private List<PowerMonitor> mPowerMonitorsInfo; + private final Object mPowerMonitorsLock = new Object(); /** * Construct a new SystemHealthManager object. @@ -161,53 +164,68 @@ public class SystemHealthManager { * @hide */ @NonNull - public PowerMonitor[] getSupportedPowerMonitors() { - synchronized (this) { + public List<PowerMonitor> getSupportedPowerMonitors() { + synchronized (mPowerMonitorsLock) { if (mPowerMonitorsInfo != null) { return mPowerMonitorsInfo; } + } + ConditionVariable lock = new ConditionVariable(); + // Populate mPowerMonitorsInfo by side-effect + getSupportedPowerMonitors(null, unused -> lock.open()); + lock.block(); - CompletableFuture<PowerMonitor[]> future = new CompletableFuture<>(); - getSupportedPowerMonitors(future); - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } + synchronized (mPowerMonitorsLock) { + return mPowerMonitorsInfo; } } /** - * Retrieves a list of supported power monitors, see {@link #getSupportedPowerMonitors()} + * Asynchronously retrieves a list of supported power monitors, see + * {@link #getSupportedPowerMonitors()} + * + * @param handler optional Handler to deliver the callback. If not supplied, the callback + * may be invoked on an arbitrary thread. + * @param onResult callback for the result * * @hide */ - public void getSupportedPowerMonitors(@NonNull CompletableFuture<PowerMonitor[]> future) { - synchronized (this) { + public void getSupportedPowerMonitors(@Nullable Handler handler, + @NonNull Consumer<List<PowerMonitor>> onResult) { + final List<PowerMonitor> result; + synchronized (mPowerMonitorsLock) { if (mPowerMonitorsInfo != null) { - future.complete(mPowerMonitorsInfo); - return; + result = mPowerMonitorsInfo; + } else if (mPowerStats == null) { + mPowerMonitorsInfo = List.of(); + result = mPowerMonitorsInfo; + } else { + result = null; } - try { - if (mPowerStats == null) { - mPowerMonitorsInfo = new PowerMonitor[0]; - future.complete(mPowerMonitorsInfo); - return; - } - - mPowerStats.getSupportedPowerMonitors(new ResultReceiver(null) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - synchronized (this) { - mPowerMonitorsInfo = resultData.getParcelableArray( - IPowerStatsService.KEY_MONITORS, PowerMonitor.class); - } - future.complete(mPowerMonitorsInfo); - } - }); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + } + if (result != null) { + if (handler != null) { + handler.post(() -> onResult.accept(result)); + } else { + onResult.accept(result); } + return; + } + try { + mPowerStats.getSupportedPowerMonitors(new ResultReceiver(handler) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + PowerMonitor[] array = resultData.getParcelableArray( + IPowerStatsService.KEY_MONITORS, PowerMonitor.class); + List<PowerMonitor> result = array != null ? Arrays.asList(array) : List.of(); + synchronized (mPowerMonitorsLock) { + mPowerMonitorsInfo = result; + } + onResult.accept(result); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -215,54 +233,74 @@ public class SystemHealthManager { * Retrieves the accumulated power consumption reported by the specified power monitors. * * @param powerMonitors power monitors to be returned. + * * @hide */ @NonNull - public PowerMonitorReadings getPowerMonitorReadings(@NonNull PowerMonitor[] powerMonitors) { - CompletableFuture<PowerMonitorReadings> future = new CompletableFuture<>(); - getPowerMonitorReadings(powerMonitors, future); - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); + public PowerMonitorReadings getPowerMonitorReadings(@NonNull List<PowerMonitor> powerMonitors) { + PowerMonitorReadings[] outReadings = new PowerMonitorReadings[1]; + RuntimeException[] outException = new RuntimeException[1]; + ConditionVariable lock = new ConditionVariable(); + getPowerMonitorReadings(powerMonitors, null, + pms -> { + outReadings[0] = pms; + lock.open(); + }, + error -> { + outException[0] = error; + lock.open(); + } + ); + lock.block(); + if (outException[0] != null) { + throw outException[0]; } + return outReadings[0]; } private static final Comparator<PowerMonitor> POWER_MONITOR_COMPARATOR = Comparator.comparingInt(pm -> pm.index); /** + * Asynchronously retrieves the accumulated power consumption reported by the specified power + * monitors. + * * @param powerMonitors power monitors to be retrieved. + * @param handler optional Handler to deliver the callbacks. If not supplied, the callback + * may be invoked on an arbitrary thread. + * @param onSuccess callback for the result + * @param onError callback invoked in case of an error + * * @hide */ - public void getPowerMonitorReadings(@NonNull PowerMonitor[] powerMonitors, - @NonNull CompletableFuture<PowerMonitorReadings> future) { + public void getPowerMonitorReadings(@NonNull List<PowerMonitor> powerMonitors, + @Nullable Handler handler, @NonNull Consumer<PowerMonitorReadings> onSuccess, + @NonNull Consumer<RuntimeException> onError) { if (mPowerStats == null) { - future.completeExceptionally( - new IllegalArgumentException("Unsupported power monitor")); + onError.accept(new IllegalArgumentException("Unsupported power monitor")); return; } - Arrays.sort(powerMonitors, POWER_MONITOR_COMPARATOR); - int[] indices = new int[powerMonitors.length]; - for (int i = 0; i < powerMonitors.length; i++) { - indices[i] = powerMonitors[i].index; + PowerMonitor[] powerMonitorsArray = + powerMonitors.toArray(new PowerMonitor[powerMonitors.size()]); + Arrays.sort(powerMonitorsArray, POWER_MONITOR_COMPARATOR); + int[] indices = new int[powerMonitors.size()]; + for (int i = 0; i < powerMonitors.size(); i++) { + indices[i] = powerMonitorsArray[i].index; } try { - mPowerStats.getPowerMonitorReadings(indices, new ResultReceiver(null) { + mPowerStats.getPowerMonitorReadings(indices, new ResultReceiver(handler) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == IPowerStatsService.RESULT_SUCCESS) { - future.complete(new PowerMonitorReadings(powerMonitors, + onSuccess.accept(new PowerMonitorReadings(powerMonitorsArray, resultData.getLongArray(IPowerStatsService.KEY_ENERGY), resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS))); } else if (resultCode == IPowerStatsService.RESULT_UNSUPPORTED_POWER_MONITOR) { - future.completeExceptionally( - new IllegalArgumentException("Unsupported power monitor")); + onError.accept(new IllegalArgumentException("Unsupported power monitor")); } else { - future.completeExceptionally( - new IllegalStateException( - "Unrecognized result code " + resultCode)); + onError.accept(new IllegalStateException( + "Unrecognized result code " + resultCode)); } } }); diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java index b85cf6d75cb7..fce87db2bbf0 100644 --- a/core/java/android/service/controls/ControlsProviderService.java +++ b/core/java/android/service/controls/ControlsProviderService.java @@ -25,6 +25,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -285,6 +286,7 @@ public abstract class ControlsProviderService extends Service { private IControlsSubscriber mCs; private boolean mEnforceStateless; private Context mContext; + private SubscriptionAdapter mSubscription; SubscriberProxy(boolean enforceStateless, IBinder token, IControlsSubscriber cs) { mEnforceStateless = enforceStateless; @@ -300,11 +302,14 @@ public abstract class ControlsProviderService extends Service { public void onSubscribe(Subscription subscription) { try { - mCs.onSubscribe(mToken, new SubscriptionAdapter(subscription)); + SubscriptionAdapter subscriptionAdapter = new SubscriptionAdapter(subscription); + mCs.onSubscribe(mToken, subscriptionAdapter); + mSubscription = subscriptionAdapter; } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); + handleRemoteException(ex); } } + public void onNext(@NonNull Control control) { Preconditions.checkNotNull(control); try { @@ -318,20 +323,36 @@ public abstract class ControlsProviderService extends Service { } mCs.onNext(mToken, control); } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); + handleRemoteException(ex); } } + public void onError(Throwable t) { try { mCs.onError(mToken, t.toString()); + mSubscription = null; } catch (RemoteException ex) { - ex.rethrowAsRuntimeException(); + handleRemoteException(ex); } } + public void onComplete() { try { mCs.onComplete(mToken); + mSubscription = null; } catch (RemoteException ex) { + handleRemoteException(ex); + } + } + + private void handleRemoteException(RemoteException ex) { + if (ex instanceof DeadObjectException) { + // System UI crashed or is restarting. There is no need to rethrow this + SubscriptionAdapter subscriptionAdapter = mSubscription; + if (subscriptionAdapter != null) { + subscriptionAdapter.cancel(); + } + } else { ex.rethrowAsRuntimeException(); } } diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 4464d1918565..d31f82398cdf 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -19,6 +19,7 @@ package android.view; import android.annotation.IntDef; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManagerGlobal; +import android.os.IInputConstants; import android.util.ArrayMap; import android.util.Pools.SynchronizedPool; @@ -53,11 +54,13 @@ public final class VelocityTracker { public @interface VelocityTrackableMotionEventAxis {} /** - * Velocity Tracker Strategy: Invalid. + * Use the default Velocity Tracker Strategy. Different axes may use different default + * strategies. * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_DEFAULT = -1; + public static final int VELOCITY_TRACKER_STRATEGY_DEFAULT = + IInputConstants.VELOCITY_TRACKER_STRATEGY_DEFAULT; /** * Velocity Tracker Strategy: Impulse. @@ -66,7 +69,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_IMPULSE = 0; + public static final int VELOCITY_TRACKER_STRATEGY_IMPULSE = + IInputConstants.VELOCITY_TRACKER_STRATEGY_IMPULSE; /** * Velocity Tracker Strategy: LSQ1. @@ -77,7 +81,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_LSQ1 = 1; + public static final int VELOCITY_TRACKER_STRATEGY_LSQ1 = + IInputConstants.VELOCITY_TRACKER_STRATEGY_LSQ1; /** * Velocity Tracker Strategy: LSQ2. @@ -88,7 +93,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_LSQ2 = 2; + public static final int VELOCITY_TRACKER_STRATEGY_LSQ2 = + IInputConstants.VELOCITY_TRACKER_STRATEGY_LSQ2; /** * Velocity Tracker Strategy: LSQ3. @@ -98,7 +104,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_LSQ3 = 3; + public static final int VELOCITY_TRACKER_STRATEGY_LSQ3 = + IInputConstants.VELOCITY_TRACKER_STRATEGY_LSQ3; /** * Velocity Tracker Strategy: WLSQ2_DELTA. @@ -106,7 +113,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA = 4; + public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA = + IInputConstants.VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA; /** * Velocity Tracker Strategy: WLSQ2_CENTRAL. @@ -114,7 +122,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL = 5; + public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL = + IInputConstants.VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL; /** * Velocity Tracker Strategy: WLSQ2_RECENT. @@ -122,7 +131,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT = 6; + public static final int VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT = + IInputConstants.VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT; /** * Velocity Tracker Strategy: INT1. @@ -134,7 +144,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_INT1 = 7; + public static final int VELOCITY_TRACKER_STRATEGY_INT1 = + IInputConstants.VELOCITY_TRACKER_STRATEGY_INT1; /** * Velocity Tracker Strategy: INT2. @@ -144,7 +155,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_INT2 = 8; + public static final int VELOCITY_TRACKER_STRATEGY_INT2 = + IInputConstants.VELOCITY_TRACKER_STRATEGY_INT2; /** * Velocity Tracker Strategy: Legacy. @@ -155,7 +167,8 @@ public final class VelocityTracker { * * @hide */ - public static final int VELOCITY_TRACKER_STRATEGY_LEGACY = 9; + public static final int VELOCITY_TRACKER_STRATEGY_LEGACY = + IInputConstants.VELOCITY_TRACKER_STRATEGY_LEGACY; /** diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 5d1a81fbb566..bb1d5b16340c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1302,7 +1302,7 @@ public interface WindowManager extends ViewManager { * ratio or orientation specified in the app manifest. * * <p>The aspect ratio compatibility override is exposed to users in device - * settings. A menu in device settings lists all apps that don't opt out of + * settings. A menu in device settings lists all apps that have not opted out of * the compatibility override. Users select apps from the menu and set the * app aspect ratio on a per-app basis. Typically, the menu is available * only on large screen devices. @@ -1347,11 +1347,11 @@ public interface WindowManager extends ViewManager { * Application level * {@link android.content.pm.PackageManager.Property PackageManager.Property} * tag that (when set to false) informs the system the app has opted out of the - * full-screen option of the aspect ratio compatibility override. (For - * background information about the aspect ratio compatibility override, see + * full-screen option of the user aspect ratio compatibility override settings. (For + * background information about the user aspect ratio compatibility override, see * {@link #PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE}.) * - * <p>When users apply the aspect ratio compatibility override, the orientation + * <p>When users apply the full-screen compatibility override, the orientation * of the activity is forced to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER}. * * <p>The user override is intended to improve the app experience on devices diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp index 05c9f6865061..03e9a6a9d139 100644 --- a/core/jni/android_view_VelocityTracker.cpp +++ b/core/jni/android_view_VelocityTracker.cpp @@ -16,13 +16,14 @@ #define LOG_TAG "VelocityTracker-JNI" +#include <android-base/logging.h> #include <android_runtime/AndroidRuntime.h> #include <cutils/properties.h> #include <input/Input.h> #include <input/VelocityTracker.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> -#include <utils/Log.h> + #include "android_view_MotionEvent.h" #include "core_jni_helpers.h" @@ -102,7 +103,7 @@ static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass c jobject eventObj) { const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj); if (!event) { - ALOGW("nativeAddMovement failed because MotionEvent was finalized."); + LOG(WARNING) << "nativeAddMovement failed because MotionEvent was finalized."; return; } diff --git a/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java b/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java index 2232e3a6ffa3..e1f9523f1b49 100644 --- a/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java +++ b/core/tests/coretests/src/android/os/health/SystemHealthManagerTest.java @@ -20,6 +20,7 @@ import static androidx.test.InstrumentationRegistry.getContext; import static com.google.common.truth.Truth.assertThat; +import android.os.ConditionVariable; import android.os.PowerMonitor; import android.os.PowerMonitorReadings; @@ -29,13 +30,16 @@ import java.util.ArrayList; import java.util.List; public class SystemHealthManagerTest { + private List<PowerMonitor> mPowerMonitorInfo; + private PowerMonitorReadings mReadings; + private RuntimeException mException; @Test public void getPowerMonitors() { SystemHealthManager shm = getContext().getSystemService(SystemHealthManager.class); - PowerMonitor[] powerMonitorInfo = shm.getSupportedPowerMonitors(); + List<PowerMonitor> powerMonitorInfo = shm.getSupportedPowerMonitors(); assertThat(powerMonitorInfo).isNotNull(); - if (powerMonitorInfo.length == 0) { + if (powerMonitorInfo.isEmpty()) { // This device does not support PowerStats HAL return; } @@ -50,20 +54,73 @@ public class SystemHealthManagerTest { } } - List<PowerMonitor> pmis = new ArrayList<>(); + List<PowerMonitor> selectedMonitors = new ArrayList<>(); if (consumerMonitor != null) { - pmis.add(consumerMonitor); + selectedMonitors.add(consumerMonitor); } if (measurementMonitor != null) { - pmis.add(measurementMonitor); + selectedMonitors.add(measurementMonitor); } - PowerMonitor[] selectedMonitors = pmis.toArray(new PowerMonitor[0]); PowerMonitorReadings readings = shm.getPowerMonitorReadings(selectedMonitors); for (PowerMonitor monitor : selectedMonitors) { assertThat(readings.getConsumedEnergyUws(monitor)).isAtLeast(0); - assertThat(readings.getTimestampMs(monitor)).isGreaterThan(0); + assertThat(readings.getTimestamp(monitor)).isGreaterThan(0); + } + } + + @Test + public void getPowerMonitorsAsync() { + SystemHealthManager shm = getContext().getSystemService(SystemHealthManager.class); + ConditionVariable done = new ConditionVariable(); + shm.getSupportedPowerMonitors(null, pms -> { + mPowerMonitorInfo = pms; + done.open(); + }); + done.block(); + assertThat(mPowerMonitorInfo).isNotNull(); + if (mPowerMonitorInfo.isEmpty()) { + // This device does not support PowerStats HAL + return; + } + + PowerMonitor consumerMonitor = null; + PowerMonitor measurementMonitor = null; + for (PowerMonitor pmi : mPowerMonitorInfo) { + if (pmi.type == PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT) { + measurementMonitor = pmi; + } else { + consumerMonitor = pmi; + } + } + + List<PowerMonitor> selectedMonitors = new ArrayList<>(); + if (consumerMonitor != null) { + selectedMonitors.add(consumerMonitor); + } + if (measurementMonitor != null) { + selectedMonitors.add(measurementMonitor); + } + + done.close(); + shm.getPowerMonitorReadings(selectedMonitors, null, + readings -> { + mReadings = readings; + done.open(); + }, + exception -> { + mException = exception; + done.open(); + } + ); + done.block(); + + assertThat(mException).isNull(); + + for (PowerMonitor monitor : selectedMonitors) { + assertThat(mReadings.getConsumedEnergyUws(monitor)).isAtLeast(0); + assertThat(mReadings.getTimestamp(monitor)).isGreaterThan(0); } } } diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java index 5fe17eeaac2d..4d4469011c06 100644 --- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -36,6 +37,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.os.Binder; import android.os.Bundle; +import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; import android.service.controls.actions.CommandAction; @@ -53,6 +55,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -307,6 +310,18 @@ public class ControlProviderServiceTest { intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))); } + @Test + public void testOnNextDoesntRethrowDeadObjectException() throws RemoteException { + doAnswer(invocation -> { + throw new DeadObjectException(); + }).when(mSubscriber).onNext(ArgumentMatchers.any(), ArgumentMatchers.any()); + Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); + + sendControlGetControl(control); + + assertTrue(mControlsProviderService.mSubscription.mIsCancelled); + } + /** * Sends the control through the publisher in {@code mControlsProviderService}, returning * the control obtained by the subscriber @@ -359,6 +374,7 @@ public class ControlProviderServiceTest { } private List<Control> mControls; + private FakeSubscription mSubscription; public void setControls(List<Control> controls) { mControls = controls; @@ -398,17 +414,35 @@ public class ControlProviderServiceTest { } private Subscription createSubscription(Subscriber s, List<Control> controls) { - return new Subscription() { - public void request(long n) { - int i = 0; - for (Control c : mControls) { - if (i++ < n) s.onNext(c); - else break; - } - s.onComplete(); - } - public void cancel() {} - }; + FakeSubscription subscription = new FakeSubscription(s, controls); + mSubscription = subscription; + return subscription; + } + } + + private static final class FakeSubscription implements Subscription { + + private final Subscriber mSubscriber; + private final List<Control> mControls; + + private boolean mIsCancelled = false; + + FakeSubscription(Subscriber s, List<Control> controls) { + mSubscriber = s; + mControls = controls; + } + + public void request(long n) { + int i = 0; + for (Control c : mControls) { + if (i++ < n) mSubscriber.onNext(c); + else break; + } + mSubscriber.onComplete(); + } + + public void cancel() { + mIsCancelled = true; } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 62b0799618ac..0998e7134e00 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -342,6 +342,7 @@ public class CompatUIController implements OnDisplaysChangedListener, if (!mActiveLetterboxEduLayout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(mActiveLetterboxEduLayout.getDisplayId()))) { // The layout is no longer eligible to be shown, clear active layout. + mActiveLetterboxEduLayout.release(); mActiveLetterboxEduLayout = null; } return; @@ -371,15 +372,9 @@ public class CompatUIController implements OnDisplaysChangedListener, ShellTaskOrganizer.TaskListener taskListener) { return new LetterboxEduWindowManager(context, taskInfo, mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), - mTransitionsLazy.get(), this::onLetterboxEduDismissed, mDockStateReader, - mCompatUIConfiguration); - } - - private void onLetterboxEduDismissed( - Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { - mActiveLetterboxEduLayout = null; - // We need to update the UI - createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second); + mTransitionsLazy.get(), + stateInfo -> createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second), + mDockStateReader, mCompatUIConfiguration); } private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo, @@ -448,6 +443,7 @@ public class CompatUIController implements OnDisplaysChangedListener, if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) { // The layout is no longer eligible to be shown, remove from active layouts. + mActiveReachabilityEduLayout.release(); mActiveReachabilityEduLayout = null; } return; diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 8191f5e6a83a..a958a091a830 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -15,6 +15,8 @@ */ #include "FrameInfo.h" +#include <gui/TraceUtils.h> + #include <cstring> namespace android { @@ -51,6 +53,30 @@ static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 23, void FrameInfo::importUiThreadInfo(int64_t* info) { memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); + mSkippedFrameReason.reset(); +} + +const char* toString(SkippedFrameReason reason) { + switch (reason) { + case SkippedFrameReason::DrawingOff: + return "DrawingOff"; + case SkippedFrameReason::ContextIsStopped: + return "ContextIsStopped"; + case SkippedFrameReason::NothingToDraw: + return "NothingToDraw"; + case SkippedFrameReason::NoOutputTarget: + return "NoOutputTarget"; + case SkippedFrameReason::NoBuffer: + return "NoBuffer"; + case SkippedFrameReason::AlreadyDrawn: + return "AlreadyDrawn"; + } +} + +void FrameInfo::setSkippedFrameReason(android::uirenderer::SkippedFrameReason reason) { + ATRACE_FORMAT_INSTANT("Frame skipped: %s", toString(reason)); + addFlag(FrameInfoFlags::SkippedFrame); + mSkippedFrameReason = reason; } } /* namespace uirenderer */ diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index b15b6cb9a9ec..f7ad13978a30 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -16,15 +16,17 @@ #ifndef FRAMEINFO_H_ #define FRAMEINFO_H_ -#include "utils/Macros.h" - #include <cutils/compiler.h> +#include <memory.h> #include <utils/Timers.h> #include <array> -#include <memory.h> +#include <optional> #include <string> +#include "SkippedFrameInfo.h" +#include "utils/Macros.h" + namespace android { namespace uirenderer { @@ -186,8 +188,14 @@ public: return mFrameInfo[static_cast<int>(index)]; } + void setSkippedFrameReason(SkippedFrameReason reason); + inline std::optional<SkippedFrameReason> getSkippedFrameReason() const { + return mSkippedFrameReason; + } + private: int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)]; + std::optional<SkippedFrameReason> mSkippedFrameReason; }; } /* namespace uirenderer */ diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp index 687e4dd324d3..59f21694fb77 100644 --- a/libs/hwui/FrameInfoVisualizer.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -148,7 +148,7 @@ void FrameInfoVisualizer::initializeRects(const int baseline, const int width) { int fast_i = 0, janky_i = 0; // Set the bottom of all the shapes to the baseline for (int fi = mFrameSource.size() - 1; fi >= 0; fi--) { - if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { + if (mFrameSource[fi].getSkippedFrameReason()) { continue; } float lineWidth = baseLineWidth; @@ -181,7 +181,7 @@ void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex en int janky_i = (mNumJankyRects - 1) * 4; for (size_t fi = 0; fi < mFrameSource.size(); fi++) { - if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) { + if (mFrameSource[fi].getSkippedFrameReason()) { continue; } diff --git a/libs/hwui/SkippedFrameInfo.h b/libs/hwui/SkippedFrameInfo.h new file mode 100644 index 000000000000..de56d9a26982 --- /dev/null +++ b/libs/hwui/SkippedFrameInfo.h @@ -0,0 +1,30 @@ +/* + * Copyright 2023 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. + */ + +#pragma once + +namespace android::uirenderer { + +enum class SkippedFrameReason { + DrawingOff, + ContextIsStopped, + NothingToDraw, + NoOutputTarget, + NoBuffer, + AlreadyDrawn, +}; + +} /* namespace android::uirenderer */ diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 2bff9cb74fa7..ea25f68d7170 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -16,14 +16,16 @@ #pragma once -#include "Properties.h" -#include "utils/Macros.h" - #include <utils/Timers.h> -#include "SkSize.h" +#include <optional> #include <string> +#include "Properties.h" +#include "SkSize.h" +#include "SkippedFrameInfo.h" +#include "utils/Macros.h" + namespace android { namespace uirenderer { @@ -110,13 +112,13 @@ public: // animate itself, such as if hasFunctors is true // This is only set if hasAnimations is true bool requiresUiRedraw = false; - // This is set to true if draw() can be called this frame - // false means that we must delay until the next vsync pulse as frame + // This is set to nullopt if draw() can be called this frame + // A value means that we must delay until the next vsync pulse as frame // production is outrunning consumption - // NOTE that if this is false CanvasContext will set either requiresUiRedraw + // NOTE that if this has a value CanvasContext will set either requiresUiRedraw // *OR* will post itself for the next vsync automatically, use this // only to avoid calling draw() - bool canDrawThisFrame = true; + std::optional<SkippedFrameReason> skippedFrameReason; // Sentinel for animatedImageDelay meaning there is no need to post such // a message. static constexpr nsecs_t kNoAnimatedImageDelay = -1; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 2ef7802c0a3c..2e0de3f8f590 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -357,8 +357,9 @@ bool CanvasContext::makeCurrent() { return true; } -static bool wasSkipped(FrameInfo* info) { - return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); +static std::optional<SkippedFrameReason> wasSkipped(FrameInfo* info) { + if (info) return info->getSkippedFrameReason(); + return std::nullopt; } bool CanvasContext::isSwapChainStuffed() { @@ -407,13 +408,26 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // If the previous frame was dropped we don't need to hold onto it, so // just keep using the previous frame's structure instead - if (wasSkipped(mCurrentFrameInfo)) { + if (const auto reason = wasSkipped(mCurrentFrameInfo)) { // Use the oldest skipped frame in case we skip more than a single frame if (!mSkippedFrameInfo) { - mSkippedFrameInfo.emplace(); - mSkippedFrameInfo->vsyncId = - mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId); - mSkippedFrameInfo->startTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); + switch (*reason) { + case SkippedFrameReason::AlreadyDrawn: + case SkippedFrameReason::NoBuffer: + case SkippedFrameReason::NoOutputTarget: + mSkippedFrameInfo.emplace(); + mSkippedFrameInfo->vsyncId = + mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId); + mSkippedFrameInfo->startTime = + mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); + break; + case SkippedFrameReason::DrawingOff: + case SkippedFrameReason::ContextIsStopped: + case SkippedFrameReason::NothingToDraw: + // Do not report those as skipped frames as there was no frame expected to be + // drawn + break; + } } } else { mCurrentFrameInfo = mJankTracker.startFrame(); @@ -427,7 +441,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy info.damageAccumulator = &mDamageAccumulator; info.layerUpdateQueue = &mLayerUpdateQueue; info.damageGenerationId = mDamageId++; - info.out.canDrawThisFrame = true; + info.out.skippedFrameReason = std::nullopt; mAnimationContext->startFrame(info.mode); for (const sp<RenderNode>& node : mRenderNodes) { @@ -447,8 +461,8 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy mIsDirty = true; if (CC_UNLIKELY(!hasOutputTarget())) { - mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); - info.out.canDrawThisFrame = false; + info.out.skippedFrameReason = SkippedFrameReason::NoOutputTarget; + mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason); return; } @@ -463,23 +477,23 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy if (vsyncDelta < 2_ms) { // Already drew for this vsync pulse, UI draw request missed // the deadline for RT animations - info.out.canDrawThisFrame = false; + info.out.skippedFrameReason = SkippedFrameReason::AlreadyDrawn; } } else { - info.out.canDrawThisFrame = true; + info.out.skippedFrameReason = std::nullopt; } // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even // be an allowable combination? if (mRenderNodes.size() > 2 && !mRenderNodes[1]->isRenderable()) { - info.out.canDrawThisFrame = false; + info.out.skippedFrameReason = SkippedFrameReason::NothingToDraw; } - if (info.out.canDrawThisFrame) { + if (!info.out.skippedFrameReason) { int err = mNativeSurface->reserveNext(); if (err != OK) { - mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); - info.out.canDrawThisFrame = false; + info.out.skippedFrameReason = SkippedFrameReason::NoBuffer; + mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason); ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err)); if (err != TIMED_OUT) { // A timed out surface can still recover, but assume others are permanently dead. @@ -488,11 +502,11 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy } } } else { - mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + mCurrentFrameInfo->setSkippedFrameReason(*info.out.skippedFrameReason); } bool postedFrameCallback = false; - if (info.out.hasAnimations || !info.out.canDrawThisFrame) { + if (info.out.hasAnimations || info.out.skippedFrameReason) { if (CC_UNLIKELY(!Properties::enableRTAnimations)) { info.out.requiresUiRedraw = true; } @@ -558,9 +572,20 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { mSyncDelayDuration = 0; mIdleDuration = 0; - if (!Properties::isDrawingEnabled() || - (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) { - mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + const auto skippedFrameReason = [&]() -> std::optional<SkippedFrameReason> { + if (!Properties::isDrawingEnabled()) { + return SkippedFrameReason::DrawingOff; + } + + if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) { + return SkippedFrameReason::NothingToDraw; + } + + return std::nullopt; + }(); + if (skippedFrameReason) { + mCurrentFrameInfo->setSkippedFrameReason(*skippedFrameReason); + if (auto grContext = getGrContext()) { // Submit to ensure that any texture uploads complete and Skia can // free its staging buffers. @@ -904,7 +929,7 @@ void CanvasContext::prepareAndDraw(RenderNode* node) { TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node); - if (info.out.canDrawThisFrame) { + if (!info.out.skippedFrameReason) { draw(info.out.solelyTextureViewUpdates); } else { // wait on fences so tasks don't overlap next frame diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 53b43ba417d0..1b333bfccbf1 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -104,7 +104,7 @@ void DrawFrameTask::run() { info.forceDrawFrame = mForceDrawFrame; mForceDrawFrame = false; canUnblockUiThread = syncFrameState(info); - canDrawThisFrame = info.out.canDrawThisFrame; + canDrawThisFrame = !info.out.skippedFrameReason.has_value(); solelyTextureViewUpdates = info.out.solelyTextureViewUpdates; if (mFrameCommitCallback) { @@ -192,11 +192,12 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { if (CC_UNLIKELY(!hasTarget || !canDraw)) { if (!hasTarget) { mSyncResult |= SyncResult::LostSurfaceRewardIfFound; + info.out.skippedFrameReason = SkippedFrameReason::NoOutputTarget; } else { // If we have a surface but can't draw we must be stopped mSyncResult |= SyncResult::ContextIsStopped; + info.out.skippedFrameReason = SkippedFrameReason::ContextIsStopped; } - info.out.canDrawThisFrame = false; } if (info.out.hasAnimations) { @@ -204,7 +205,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { mSyncResult |= SyncResult::UIRedrawRequired; } } - if (!info.out.canDrawThisFrame) { + if (info.out.skippedFrameReason) { mSyncResult |= SyncResult::FrameDropped; } // If prepareTextures is false, we ran out of texture cache space diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 9234d374e1ad..147412d08d2c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -22,6 +22,7 @@ import static android.media.MediaRoute2Info.TYPE_DOCK; import static android.media.MediaRoute2Info.TYPE_GROUP; import static android.media.MediaRoute2Info.TYPE_HDMI; import static android.media.MediaRoute2Info.TYPE_HEARING_AID; +import static android.media.MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; import static android.media.MediaRoute2Info.TYPE_UNKNOWN; @@ -82,7 +83,8 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { MediaDeviceType.TYPE_FAST_PAIR_BLUETOOTH_DEVICE, MediaDeviceType.TYPE_BLUETOOTH_DEVICE, MediaDeviceType.TYPE_CAST_DEVICE, - MediaDeviceType.TYPE_CAST_GROUP_DEVICE}) + MediaDeviceType.TYPE_CAST_GROUP_DEVICE, + MediaDeviceType.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER}) public @interface MediaDeviceType { int TYPE_UNKNOWN = 0; int TYPE_PHONE_DEVICE = 1; @@ -92,6 +94,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { int TYPE_BLUETOOTH_DEVICE = 5; int TYPE_CAST_DEVICE = 6; int TYPE_CAST_GROUP_DEVICE = 7; + int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 8; } @Retention(RetentionPolicy.SOURCE) @@ -161,6 +164,9 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { case TYPE_BLE_HEADSET: mType = MediaDeviceType.TYPE_BLUETOOTH_DEVICE; break; + case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER: + mType = MediaDeviceType.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER; + break; case TYPE_UNKNOWN: case TYPE_REMOTE_TV: case TYPE_REMOTE_SPEAKER: diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java index 39d4e6e8d68a..412d1a3a5013 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java @@ -56,6 +56,7 @@ public class MediaOutputMetricLogger { * Update the endpoints of a content switching operation. * This method should be called before a switching operation, so the metric logger can track * source and target devices. + * * @param source the current connected media device * @param target the target media device for content switching to */ @@ -72,37 +73,9 @@ public class MediaOutputMetricLogger { /** * Do the metric logging of content switching success. + * * @param selectedDeviceType string representation of the target media device - * @param deviceList media device list for device count updating - */ - public void logOutputSuccess(String selectedDeviceType, List<MediaDevice> deviceList) { - if (DEBUG) { - Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType); - } - - if (mSourceDevice == null && mTargetDevice == null) { - return; - } - - updateLoggingDeviceCount(deviceList); - - SysUiStatsLog.write( - SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED, - getLoggingDeviceType(mSourceDevice, true), - getLoggingDeviceType(mTargetDevice, false), - SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK, - SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR, - getLoggingPackageName(), - mWiredDeviceCount, - mConnectedBluetoothDeviceCount, - mRemoteDeviceCount, - mAppliedDeviceCountWithinRemoteGroup); - } - - /** - * Do the metric logging of content switching success. - * @param selectedDeviceType string representation of the target media device - * @param deviceItemList media item list for device count updating + * @param deviceItemList media item list for device count updating */ public void logOutputItemSuccess(String selectedDeviceType, List<MediaItem> deviceItemList) { if (DEBUG) { @@ -125,11 +98,14 @@ public class MediaOutputMetricLogger { mWiredDeviceCount, mConnectedBluetoothDeviceCount, mRemoteDeviceCount, - mAppliedDeviceCountWithinRemoteGroup); + mAppliedDeviceCountWithinRemoteGroup, + mTargetDevice.isSuggestedDevice(), + mTargetDevice.hasOngoingSession()); } /** * Do the metric logging of volume adjustment. + * * @param source the device been adjusted */ public void logInteractionAdjustVolume(MediaDevice source) { @@ -141,7 +117,8 @@ public class MediaOutputMetricLogger { SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT, SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__ADJUST_VOLUME, getInteractionDeviceType(source), - getLoggingPackageName()); + getLoggingPackageName(), + source.isSuggestedDevice()); } /** @@ -156,7 +133,8 @@ public class MediaOutputMetricLogger { SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT, SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__STOP_CASTING, SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE, - getLoggingPackageName()); + getLoggingPackageName(), + /*isSuggestedDevice = */false); } /** @@ -171,42 +149,15 @@ public class MediaOutputMetricLogger { SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT, SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__EXPANSION, getInteractionDeviceType(source), - getLoggingPackageName()); - } - - /** - * Do the metric logging of content switching failure. - * @param deviceList media device list for device count updating - * @param reason the reason of content switching failure - */ - public void logOutputFailure(List<MediaDevice> deviceList, int reason) { - if (DEBUG) { - Log.e(TAG, "logRequestFailed - " + reason); - } - - if (mSourceDevice == null && mTargetDevice == null) { - return; - } - - updateLoggingDeviceCount(deviceList); - - SysUiStatsLog.write( - SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED, - getLoggingDeviceType(mSourceDevice, true), - getLoggingDeviceType(mTargetDevice, false), - SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR, - getLoggingSwitchOpSubResult(reason), getLoggingPackageName(), - mWiredDeviceCount, - mConnectedBluetoothDeviceCount, - mRemoteDeviceCount, - mAppliedDeviceCountWithinRemoteGroup); + source.isSuggestedDevice()); } /** * Do the metric logging of content switching failure. + * * @param deviceItemList media item list for device count updating - * @param reason the reason of content switching failure + * @param reason the reason of content switching failure */ public void logOutputItemFailure(List<MediaItem> deviceItemList, int reason) { if (DEBUG) { @@ -229,7 +180,9 @@ public class MediaOutputMetricLogger { mWiredDeviceCount, mConnectedBluetoothDeviceCount, mRemoteDeviceCount, - mAppliedDeviceCountWithinRemoteGroup); + mAppliedDeviceCountWithinRemoteGroup, + mTargetDevice.isSuggestedDevice(), + mTargetDevice.hasOngoingSession()); } private void updateLoggingDeviceCount(List<MediaDevice> deviceList) { @@ -266,7 +219,7 @@ public class MediaOutputMetricLogger { mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0; mAppliedDeviceCountWithinRemoteGroup = 0; - for (MediaItem mediaItem: deviceItemList) { + for (MediaItem mediaItem : deviceItemList) { if (mediaItem.getMediaDevice().isPresent() && mediaItem.getMediaDevice().get().isConnected()) { switch (mediaItem.getMediaDevice().get().getDeviceType()) { @@ -326,6 +279,10 @@ public class MediaOutputMetricLogger { return isSourceDevice ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_GROUP : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_GROUP; + case MediaDevice.MediaDeviceType.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER: + return isSourceDevice + ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__AVR + : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__AVR; default: return isSourceDevice ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index e97a12a83b1f..6f9b7d6328c7 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -295,6 +295,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final PowerManager.WakeLock mDownloadPsdsWakeLock; @GuardedBy("mLock") private final Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>(); + @GuardedBy("mLock") + private final Set<Integer> mDownloadInProgressPsdsTypes = new HashSet<>(); /** * Properties loaded from PROPERTIES_FILE. @@ -767,8 +769,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return; } synchronized (mLock) { + if (mDownloadInProgressPsdsTypes.contains(psdsType)) { + if (DEBUG) { + Log.d(TAG, + "PSDS type " + psdsType + " download in progress. Ignore the request."); + } + return; + } // hold wake lock while task runs mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS); + mDownloadInProgressPsdsTypes.add(psdsType); } Log.i(TAG, "WakeLock acquired by handleDownloadPsdsData()"); Executors.newSingleThreadExecutor().execute(() -> { @@ -818,6 +828,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.e(TAG, "WakeLock expired before release in " + "handleDownloadPsdsData()"); } + mDownloadInProgressPsdsTypes.remove(psdsType); } }); } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index dd681aa85c3f..d77ceb2ec634 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -130,7 +130,8 @@ public final class UserManagerTest { // Keep system and current user if (user.id != UserHandle.USER_SYSTEM && user.id != currentUser && - user.id != communalProfileId) { + user.id != communalProfileId && + !user.isMain()) { removeUser(user.id); } } @@ -1105,16 +1106,16 @@ public final class UserManagerTest { public void testCreateProfileForUser_disallowAddManagedProfile() throws Exception { assumeManagedUsersSupported(); final int mainUserId = mUserManager.getMainUser().getIdentifier(); - final UserHandle mainUserHandle = asHandle(mainUserId); + final UserHandle currentUserHandle = asHandle(ActivityManager.getCurrentUser()); mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true, - mainUserHandle); + currentUserHandle); try { UserInfo userInfo = createProfileForUser("Managed", UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId); assertThat(userInfo).isNull(); } finally { mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false, - mainUserHandle); + currentUserHandle); } } @@ -1190,6 +1191,7 @@ public final class UserManagerTest { @Test public void testGetManagedProfileCreationTime() throws Exception { assumeManagedUsersSupported(); + assumeTrue("User does not have access to creation time", mUserManager.isMainUser()); final int mainUserId = mUserManager.getMainUser().getIdentifier(); final long startTime = System.currentTimeMillis(); UserInfo profile = createProfileForUser("Managed 1", |