summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java88
-rw-r--r--apct-tests/perftests/core/src/android/os/ParcelPerfTest.java15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java7
-rw-r--r--api/current.txt27
-rw-r--r--api/module-lib-current.txt2
-rw-r--r--api/system-current.txt67
-rw-r--r--api/test-current.txt39
-rw-r--r--cmds/statsd/src/atoms.proto26
-rw-r--r--core/java/android/app/ActivityOptions.java88
-rw-r--r--core/java/android/hardware/HardwareBuffer.java9
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java7
-rw-r--r--core/java/android/os/Parcel.java157
-rw-r--r--core/java/android/os/Process.java84
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java168
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java127
-rw-r--r--core/java/android/util/apk/SourceStampVerificationResult.java25
-rw-r--r--core/java/android/util/apk/SourceStampVerifier.java104
-rw-r--r--core/jni/android_hardware_HardwareBuffer.cpp22
-rw-r--r--core/jni/android_os_Parcel.cpp35
-rw-r--r--core/res/res/values/attrs_manifest.xml4
-rw-r--r--core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apkbin0 -> 16854 bytes
-rw-r--r--core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apkbin0 -> 16854 bytes
-rw-r--r--core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java33
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java6
-rw-r--r--graphics/java/android/graphics/ImageFormat.java12
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp13
-rw-r--r--location/java/android/location/ILocationManager.aidl8
-rw-r--r--location/java/android/location/LocationManager.java424
-rw-r--r--location/java/android/location/LocationRequest.java1251
-rw-r--r--location/lib/java/com/android/location/provider/LocationRequestUnbundled.java18
-rw-r--r--media/java/android/media/ImageUtils.java7
-rw-r--r--media/java/android/media/MicrophoneInfo.java7
-rw-r--r--media/java/android/media/session/MediaSessionManager.java7
-rw-r--r--non-updatable-api/current.txt27
-rw-r--r--non-updatable-api/module-lib-current.txt2
-rw-r--r--non-updatable-api/system-current.txt67
-rw-r--r--packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java16
-rw-r--r--packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java9
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java11
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java16
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java36
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java132
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java4
-rw-r--r--services/core/java/com/android/server/am/PhantomProcessList.java395
-rw-r--r--services/core/java/com/android/server/am/PhantomProcessRecord.java237
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java2
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java24
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java56
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java64
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java68
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProviderManager.java21
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java24
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java31
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java20
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssStatusProvider.java19
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java2
-rw-r--r--services/core/java/com/android/server/location/util/LocationUsageLogger.java12
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/DevicePermissionState.java77
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java1077
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java8
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionState.java129
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionsState.java22
-rw-r--r--services/core/java/com/android/server/pm/permission/UidPermissionState.java574
-rw-r--r--services/core/java/com/android/server/pm/permission/UserPermissionState.java103
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java46
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java4
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java3
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java31
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java33
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java258
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java99
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java90
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java17
-rw-r--r--wifi/java/android/net/wifi/nl80211/NativeScanResult.java4
96 files changed, 4047 insertions, 2914 deletions
diff --git a/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java
new file mode 100644
index 000000000000..760ae12bcc07
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 android.os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ParcelObtainPerfTest {
+ private static final int ITERATIONS = 1_000_000;
+
+ @Test
+ public void timeContention_01() throws Exception {
+ timeContention(1);
+ }
+
+ @Test
+ public void timeContention_04() throws Exception {
+ timeContention(4);
+ }
+
+ @Test
+ public void timeContention_16() throws Exception {
+ timeContention(16);
+ }
+
+ private static void timeContention(int numThreads) throws Exception {
+ final long start = SystemClock.elapsedRealtime();
+ {
+ final ObtainThread[] threads = new ObtainThread[numThreads];
+ for (int i = 0; i < numThreads; i++) {
+ final ObtainThread thread = new ObtainThread(ITERATIONS / numThreads);
+ thread.start();
+ threads[i] = thread;
+ }
+ for (int i = 0; i < numThreads; i++) {
+ threads[i].join();
+ }
+ }
+ final long duration = SystemClock.elapsedRealtime() - start;
+
+ final Bundle results = new Bundle();
+ results.putLong("duration", duration);
+ InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+ }
+
+ public static class ObtainThread extends Thread {
+ public int iterations;
+
+ public ObtainThread(int iterations) {
+ this.iterations = iterations;
+ }
+
+ @Override
+ public void run() {
+ while (iterations-- > 0) {
+ final Parcel data = Parcel.obtain();
+ final Parcel reply = Parcel.obtain();
+ try {
+ data.writeInt(32);
+ reply.writeInt(32);
+ } finally {
+ reply.recycle();
+ data.recycle();
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
index 4db9262f7fe3..be2f9d72663e 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
@@ -159,21 +159,6 @@ public class ParcelPerfTest {
}
@Test
- public void timeObtainRecycle() {
- // Use up the pooled instances.
- // A lot bigger than the actual size but in case someone increased it.
- final int POOL_SIZE = 100;
- for (int i = 0; i < POOL_SIZE; i++) {
- Parcel.obtain();
- }
-
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- Parcel.obtain().recycle();
- }
- }
-
- @Test
public void timeWriteException() {
timeWriteException(false);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index d8386b5f1153..59915e145c49 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -2178,11 +2178,10 @@ public class DeviceIdleController extends SystemService
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
- mLocationRequest = LocationRequest.create()
+ mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0)
.setQuality(LocationRequest.ACCURACY_FINE)
- .setInterval(0)
- .setFastestInterval(0)
- .setNumUpdates(1);
+ .setMaxUpdates(1)
+ .build();
}
mConstraintController = mInjector.getConstraintController(
diff --git a/api/current.txt b/api/current.txt
index 9b9e258f23a2..afd93c363e60 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23925,6 +23925,7 @@ package android.location {
method @NonNull public java.util.List<java.lang.String> getAllProviders();
method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
method @Nullable public String getGnssHardwareModelName();
method public int getGnssYearOfHardware();
@@ -23959,6 +23960,8 @@ package android.location {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
@@ -24002,6 +24005,30 @@ package android.location {
field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
+ public final class LocationRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDurationMillis();
+ method public long getIntervalMillis();
+ method public int getMaxUpdates();
+ method public float getMinUpdateDistanceMeters();
+ method public long getMinUpdateIntervalMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ }
+
+ public static final class LocationRequest.Builder {
+ ctor public LocationRequest.Builder(long);
+ ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+ method @NonNull public android.location.LocationRequest build();
+ method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+ method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+ method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c12d897b9d72..4f0e2cd3c768 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -66,6 +66,8 @@ package android.media.session {
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
+ field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 4134711035e5..84a8a1d5c7a6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4075,7 +4075,7 @@ package android.location {
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
@@ -4086,9 +4086,9 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -4097,42 +4097,49 @@ package android.location {
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
- method @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
- method public int describeContents();
+ method @Deprecated @NonNull public static android.location.LocationRequest create();
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public boolean getHideFromAppOps();
- method public long getInterval();
- method public int getNumUpdates();
- method @NonNull public String getProvider();
+ method @Deprecated public long getExpireIn();
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public boolean getHideFromAppOps();
+ method @Deprecated public long getInterval();
+ method @Deprecated public int getNumUpdates();
+ method @Deprecated @NonNull public String getProvider();
method public int getQuality();
- method public float getSmallestDisplacement();
+ method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
+ method public boolean isLowPower();
+ method @Deprecated public boolean isLowPowerMode();
method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method public void setHideFromAppOps(boolean);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
- method public void setWorkSource(@Nullable android.os.WorkSource);
- method public void writeToParcel(android.os.Parcel, int);
+ method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+ method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+ method @Deprecated public void setHideFromAppOps(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+ method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+ method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index de2919b8936a..30972b65a1fd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1686,45 +1686,34 @@ package android.location {
public class LocationManager {
method @NonNull public String[] getBackgroundThrottlingWhitelist();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public String[] getIgnoreSettingsWhitelist();
method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
field public static final String FUSED_PROVIDER = "fused";
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method public int describeContents();
- method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public long getInterval();
- method public int getNumUpdates();
- method public int getQuality();
+ method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
- method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method public void writeToParcel(android.os.Parcel, int);
+ method public boolean isLowPower();
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission("android.permission.UPDATE_APP_OPS_STATS") public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 94c2305e36f6..038f4c35bab6 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3764,6 +3764,19 @@ message AppStartOccurred {
// The reason why the package was optimized.
optional int32 package_optimization_compilation_reason = 15;
+
+ enum SourceType {
+ UNAVAILABLE = 0;
+ LAUNCHER = 1;
+ NOTIFICATION = 2;
+ LOCKSCREEN = 3;
+ }
+ // The type of the startup source.
+ optional SourceType source_type = 16;
+
+ // The time from the startup source to the beginning of handling the startup event.
+ // -1 means not available.
+ optional int32 source_event_delay_millis = 17;
}
message AppStartCanceled {
@@ -3808,6 +3821,19 @@ message AppStartFullyDrawn {
// App startup time (until call to Activity#reportFullyDrawn()).
optional int64 app_startup_time_millis = 6;
+
+ enum SourceType {
+ UNAVAILABLE = 0;
+ LAUNCHER = 1;
+ NOTIFICATION = 2;
+ LOCKSCREEN = 3;
+ }
+ // The type of the startup source.
+ optional SourceType source_type = 7;
+
+ // The time from the startup source to the beginning of handling the startup event.
+ // -1 means not available.
+ optional int32 source_event_delay_millis = 8;
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 84a6b43e7175..a61159a23c2c 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -37,6 +38,7 @@ import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -54,6 +56,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.window.WindowContainerToken;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
@@ -290,6 +294,9 @@ public class ActivityOptions {
private static final String KEY_EXIT_COORDINATOR_INDEX
= "android:activity.exitCoordinatorIndex";
+ /** See {@link SourceInfo}. */
+ private static final String KEY_SOURCE_INFO = "android.activity.sourceInfo";
+
private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport";
private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint";
@@ -369,6 +376,7 @@ public class ActivityOptions {
private boolean mAvoidMoveToFront;
private boolean mFreezeRecentTasksReordering;
private AppTransitionAnimationSpec mAnimSpecs[];
+ private SourceInfo mSourceInfo;
private int mRotationAnimationHint = -1;
private Bundle mAppVerificationBundle;
private IAppTransitionAnimationSpecsFuture mSpecsFuture;
@@ -1055,6 +1063,7 @@ public class ActivityOptions {
mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
}
+ mSourceInfo = opts.getParcelable(KEY_SOURCE_INFO);
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1);
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
if (opts.containsKey(KEY_SPECS_FUTURE)) {
@@ -1696,6 +1705,9 @@ public class ActivityOptions {
if (mSpecsFuture != null) {
b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
}
+ if (mSourceInfo != null) {
+ b.putParcelable(KEY_SOURCE_INFO, mSourceInfo);
+ }
if (mRotationAnimationHint != -1) {
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
}
@@ -1737,6 +1749,28 @@ public class ActivityOptions {
}
/**
+ * Returns the launch source information set by {@link #setSourceInfo}.
+ * @hide
+ */
+ public @Nullable SourceInfo getSourceInfo() {
+ return mSourceInfo;
+ }
+
+ /**
+ * Sets the source information of the launch event.
+ *
+ * @param type The type of the startup source.
+ * @param uptimeMillis The event time of startup source in milliseconds since boot, not
+ * including sleep (e.g. from {@link android.view.MotionEvent#getEventTime}
+ * or {@link android.os.SystemClock#uptimeMillis}).
+ * @see SourceInfo
+ * @hide
+ */
+ public void setSourceInfo(@SourceInfo.SourceType int type, long uptimeMillis) {
+ mSourceInfo = new SourceInfo(type, uptimeMillis);
+ }
+
+ /**
* Return the filtered options only meant to be seen by the target activity itself
* @hide
*/
@@ -1863,4 +1897,58 @@ public class ActivityOptions {
}
}
}
+
+ /**
+ * The information about the source of activity launch. E.g. describe an activity is launched
+ * from launcher by receiving a motion event with a timestamp.
+ * @hide
+ */
+ public static class SourceInfo implements Parcelable {
+ /** Launched from launcher. */
+ public static final int TYPE_LAUNCHER = 1;
+ /** Launched from notification. */
+ public static final int TYPE_NOTIFICATION = 2;
+ /** Launched from lockscreen, including notification while the device is locked. */
+ public static final int TYPE_LOCKSCREEN = 3;
+
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ TYPE_LAUNCHER,
+ TYPE_NOTIFICATION,
+ TYPE_LOCKSCREEN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SourceType {}
+
+ /** The type of the startup source. */
+ public final @SourceType int type;
+
+ /** The timestamp (uptime based) of the source to launch activity. */
+ public final long eventTimeMs;
+
+ SourceInfo(@SourceType int srcType, long uptimeMillis) {
+ type = srcType;
+ eventTimeMs = uptimeMillis;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type);
+ dest.writeLong(eventTimeMs);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<SourceInfo> CREATOR = new Creator<SourceInfo>() {
+ public SourceInfo createFromParcel(Parcel in) {
+ return new SourceInfo(in.readInt(), in.readLong());
+ }
+
+ public SourceInfo[] newArray(int size) {
+ return new SourceInfo[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index dd3493063e28..a9b613228070 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -26,6 +26,7 @@ import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.CloseGuard;
@@ -141,8 +142,6 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
/** Usage: The buffer contains a complete mipmap hierarchy */
public static final long USAGE_GPU_MIPMAP_COMPLETE = 1 << 26;
- // The approximate size of a native AHardwareBuffer object.
- private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
/**
* Creates a new <code>HardwareBuffer</code> instance.
*
@@ -239,10 +238,10 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private HardwareBuffer(long nativeObject) {
mNativeObject = nativeObject;
-
+ long bufferSize = nEstimateSize(nativeObject);
ClassLoader loader = HardwareBuffer.class.getClassLoader();
NativeAllocationRegistry registry = new NativeAllocationRegistry(
- loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE);
+ loader, nGetNativeFinalizer(), bufferSize);
mCleaner = registry.registerNativeAllocation(this, mNativeObject);
mCloseGuard.open("close");
}
@@ -429,4 +428,6 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
private static native long nGetUsage(long nativeObject);
private static native boolean nIsSupported(int width, int height, int format, int layers,
long usage);
+ @CriticalNative
+ private static native long nEstimateSize(long nativeObject);
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 52251ba90b98..9d32a809fe0d 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1320,6 +1320,8 @@ public final class StreamConfigurationMap {
return ImageFormat.DEPTH16;
case HAL_PIXEL_FORMAT_RAW16:
return ImageFormat.RAW_DEPTH;
+ case HAL_PIXEL_FORMAT_RAW10:
+ return ImageFormat.RAW_DEPTH10;
case ImageFormat.JPEG:
throw new IllegalArgumentException(
"ImageFormat.JPEG is an unknown internal format");
@@ -1393,6 +1395,8 @@ public final class StreamConfigurationMap {
return HAL_PIXEL_FORMAT_Y16;
case ImageFormat.RAW_DEPTH:
return HAL_PIXEL_FORMAT_RAW16;
+ case ImageFormat.RAW_DEPTH10:
+ return HAL_PIXEL_FORMAT_RAW10;
default:
return format;
}
@@ -1437,6 +1441,7 @@ public final class StreamConfigurationMap {
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.DEPTH16:
case ImageFormat.RAW_DEPTH:
+ case ImageFormat.RAW_DEPTH10:
return HAL_DATASPACE_DEPTH;
case ImageFormat.DEPTH_JPEG:
return HAL_DATASPACE_DYNAMIC_DEPTH;
@@ -1878,6 +1883,8 @@ public final class StreamConfigurationMap {
return "DEPTH_JPEG";
case ImageFormat.RAW_DEPTH:
return "RAW_DEPTH";
+ case ImageFormat.RAW_DEPTH10:
+ return "RAW_DEPTH10";
case ImageFormat.PRIVATE:
return "PRIVATE";
case ImageFormat.HEIC:
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 415e5a60a140..1bddc49f839c 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -33,9 +33,10 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
-import dalvik.system.VMRuntime;
import libcore.util.ArrayUtils;
import libcore.util.SneakyThrow;
@@ -222,9 +223,31 @@ public final class Parcel {
*/
private static boolean sParcelExceptionStackTrace;
- private static final int POOL_SIZE = 6;
- private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
- private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
+ private static final Object sPoolSync = new Object();
+
+ /** Next item in the linked list pool, if any */
+ @GuardedBy("sPoolSync")
+ private Parcel mPoolNext;
+
+ /** Head of a linked list pool of {@link Parcel} objects */
+ @GuardedBy("sPoolSync")
+ private static Parcel sOwnedPool;
+ /** Head of a linked list pool of {@link Parcel} objects */
+ @GuardedBy("sPoolSync")
+ private static Parcel sHolderPool;
+
+ /** Total size of pool with head at {@link #sOwnedPool} */
+ @GuardedBy("sPoolSync")
+ private static int sOwnedPoolSize = 0;
+ /** Total size of pool with head at {@link #sHolderPool} */
+ @GuardedBy("sPoolSync")
+ private static int sHolderPoolSize = 0;
+
+ /**
+ * We're willing to pool up to 32 objects, which is sized to accommodate
+ * both a data and reply Parcel for the maximum of 16 Binder threads.
+ */
+ private static final int POOL_SIZE = 32;
// Keep in sync with frameworks/native/include/private/binder/ParcelValTypes.h.
private static final int VAL_NULL = -1;
@@ -285,7 +308,7 @@ public final class Parcel {
@CriticalNative
private static native int nativeDataCapacity(long nativePtr);
@FastNative
- private static native long nativeSetDataSize(long nativePtr, int size);
+ private static native void nativeSetDataSize(long nativePtr, int size);
@CriticalNative
private static native void nativeSetDataPosition(long nativePtr, int pos);
@FastNative
@@ -314,7 +337,7 @@ public final class Parcel {
@FastNative
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
@FastNative
- private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
+ private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
@@ -337,14 +360,14 @@ public final class Parcel {
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
private static native long nativeCreate();
- private static native long nativeFreeBuffer(long nativePtr);
+ private static native void nativeFreeBuffer(long nativePtr);
private static native void nativeDestroy(long nativePtr);
private static native byte[] nativeMarshall(long nativePtr);
- private static native long nativeUnmarshall(
+ private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
- private static native long nativeAppendFrom(
+ private static native void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
@CriticalNative
private static native boolean nativeHasFileDescriptors(long nativePtr);
@@ -420,22 +443,27 @@ public final class Parcel {
*/
@NonNull
public static Parcel obtain() {
- final Parcel[] pool = sOwnedPool;
- synchronized (pool) {
- Parcel p;
- for (int i=0; i<POOL_SIZE; i++) {
- p = pool[i];
- if (p != null) {
- pool[i] = null;
- if (DEBUG_RECYCLE) {
- p.mStack = new RuntimeException();
- }
- p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
- return p;
- }
+ Parcel res = null;
+ synchronized (sPoolSync) {
+ if (sOwnedPool != null) {
+ res = sOwnedPool;
+ sOwnedPool = res.mPoolNext;
+ res.mPoolNext = null;
+ sOwnedPoolSize--;
+ }
+ }
+
+ // When no cache found above, create from scratch; otherwise prepare the
+ // cached object to be used
+ if (res == null) {
+ res = new Parcel(0);
+ } else {
+ if (DEBUG_RECYCLE) {
+ res.mStack = new RuntimeException();
}
+ res.mReadWriteHelper = ReadWriteHelper.DEFAULT;
}
- return new Parcel(0);
+ return res;
}
/**
@@ -446,19 +474,21 @@ public final class Parcel {
if (DEBUG_RECYCLE) mStack = null;
freeBuffer();
- final Parcel[] pool;
if (mOwnsNativeParcelObject) {
- pool = sOwnedPool;
+ synchronized (sPoolSync) {
+ if (sOwnedPoolSize < POOL_SIZE) {
+ mPoolNext = sOwnedPool;
+ sOwnedPool = this;
+ sOwnedPoolSize++;
+ }
+ }
} else {
mNativePtr = 0;
- pool = sHolderPool;
- }
-
- synchronized (pool) {
- for (int i=0; i<POOL_SIZE; i++) {
- if (pool[i] == null) {
- pool[i] = this;
- return;
+ synchronized (sPoolSync) {
+ if (sHolderPoolSize < POOL_SIZE) {
+ mPoolNext = sHolderPool;
+ sHolderPool = this;
+ sHolderPoolSize++;
}
}
}
@@ -532,7 +562,7 @@ public final class Parcel {
* @param size The new number of bytes in the Parcel.
*/
public final void setDataSize(int size) {
- updateNativeSize(nativeSetDataSize(mNativePtr, size));
+ nativeSetDataSize(mNativePtr, size);
}
/**
@@ -584,11 +614,11 @@ public final class Parcel {
* Set the bytes in data to be the raw bytes of this Parcel.
*/
public final void unmarshall(@NonNull byte[] data, int offset, int length) {
- updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
+ nativeUnmarshall(mNativePtr, data, offset, length);
}
public final void appendFrom(Parcel parcel, int offset, int length) {
- updateNativeSize(nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length));
+ nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
}
/** @hide */
@@ -871,24 +901,7 @@ public final class Parcel {
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
*/
public final void writeFileDescriptor(@NonNull FileDescriptor val) {
- updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
- }
-
- private void updateNativeSize(long newNativeSize) {
- if (mOwnsNativeParcelObject) {
- if (newNativeSize > Integer.MAX_VALUE) {
- newNativeSize = Integer.MAX_VALUE;
- }
- if (newNativeSize != mNativeSize) {
- int delta = (int) (newNativeSize - mNativeSize);
- if (delta > 0) {
- VMRuntime.getRuntime().registerNativeAllocation(delta);
- } else {
- VMRuntime.getRuntime().registerNativeFree(-delta);
- }
- mNativeSize = newNativeSize;
- }
- }
+ nativeWriteFileDescriptor(mNativePtr, val);
}
/**
@@ -3496,22 +3509,27 @@ public final class Parcel {
/** @hide */
static protected final Parcel obtain(long obj) {
- final Parcel[] pool = sHolderPool;
- synchronized (pool) {
- Parcel p;
- for (int i=0; i<POOL_SIZE; i++) {
- p = pool[i];
- if (p != null) {
- pool[i] = null;
- if (DEBUG_RECYCLE) {
- p.mStack = new RuntimeException();
- }
- p.init(obj);
- return p;
- }
+ Parcel res = null;
+ synchronized (sPoolSync) {
+ if (sHolderPool != null) {
+ res = sHolderPool;
+ sHolderPool = res.mPoolNext;
+ res.mPoolNext = null;
+ sHolderPoolSize--;
+ }
+ }
+
+ // When no cache found above, create from scratch; otherwise prepare the
+ // cached object to be used
+ if (res == null) {
+ res = new Parcel(obj);
+ } else {
+ if (DEBUG_RECYCLE) {
+ res.mStack = new RuntimeException();
}
+ res.init(obj);
}
- return new Parcel(obj);
+ return res;
}
private Parcel(long nativePtr) {
@@ -3535,7 +3553,7 @@ public final class Parcel {
private void freeBuffer() {
resetSqaushingState();
if (mOwnsNativeParcelObject) {
- updateNativeSize(nativeFreeBuffer(mNativePtr));
+ nativeFreeBuffer(mNativePtr);
}
mReadWriteHelper = ReadWriteHelper.DEFAULT;
}
@@ -3545,7 +3563,6 @@ public final class Parcel {
if (mNativePtr != 0) {
if (mOwnsNativeParcelObject) {
nativeDestroy(mNativePtr);
- updateNativeSize(0);
}
mNativePtr = 0;
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index efea9537c4cf..d7393cadb121 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -32,6 +32,7 @@ import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeoutException;
@@ -1317,33 +1318,16 @@ public class Process {
*/
public static void waitForProcessDeath(int pid, int timeout)
throws InterruptedException, TimeoutException {
- FileDescriptor pidfd = null;
- if (sPidFdSupported == PIDFD_UNKNOWN) {
- int fd = -1;
+ boolean fallback = supportsPidFd();
+ if (!fallback) {
+ FileDescriptor pidfd = null;
try {
- fd = nativePidFdOpen(pid, 0);
- sPidFdSupported = PIDFD_SUPPORTED;
- } catch (ErrnoException e) {
- sPidFdSupported = e.errno != OsConstants.ENOSYS
- ? PIDFD_SUPPORTED : PIDFD_UNSUPPORTED;
- } finally {
+ final int fd = nativePidFdOpen(pid, 0);
if (fd >= 0) {
pidfd = new FileDescriptor();
pidfd.setInt$(fd);
- }
- }
- }
- boolean fallback = sPidFdSupported == PIDFD_UNSUPPORTED;
- if (!fallback) {
- try {
- if (pidfd == null) {
- int fd = nativePidFdOpen(pid, 0);
- if (fd >= 0) {
- pidfd = new FileDescriptor();
- pidfd.setInt$(fd);
- } else {
- fallback = true;
- }
+ } else {
+ fallback = true;
}
if (pidfd != null) {
StructPollfd[] fds = new StructPollfd[] {
@@ -1392,5 +1376,59 @@ public class Process {
throw new TimeoutException();
}
+ /**
+ * Determine whether the system supports pidfd APIs
+ *
+ * @return Returns true if the system supports pidfd APIs
+ * @hide
+ */
+ public static boolean supportsPidFd() {
+ if (sPidFdSupported == PIDFD_UNKNOWN) {
+ int fd = -1;
+ try {
+ fd = nativePidFdOpen(myPid(), 0);
+ sPidFdSupported = PIDFD_SUPPORTED;
+ } catch (ErrnoException e) {
+ sPidFdSupported = e.errno != OsConstants.ENOSYS
+ ? PIDFD_SUPPORTED : PIDFD_UNSUPPORTED;
+ } finally {
+ if (fd >= 0) {
+ final FileDescriptor f = new FileDescriptor();
+ f.setInt$(fd);
+ IoUtils.closeQuietly(f);
+ }
+ }
+ }
+ return sPidFdSupported == PIDFD_SUPPORTED;
+ }
+
+ /**
+ * Open process file descriptor for given pid.
+ *
+ * @param pid The process ID to open for
+ * @param flags Reserved, unused now, must be 0
+ * @return The process file descriptor for given pid
+ * @throws IOException if it can't be opened
+ *
+ * @hide
+ */
+ public static @Nullable FileDescriptor openPidFd(int pid, int flags) throws IOException {
+ if (!supportsPidFd()) {
+ return null;
+ }
+ if (flags != 0) {
+ throw new IllegalArgumentException();
+ }
+ try {
+ FileDescriptor pidfd = new FileDescriptor();
+ pidfd.setInt$(nativePidFdOpen(pid, flags));
+ return pidfd;
+ } catch (ErrnoException e) {
+ IOException ex = new IOException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 09736085954c..9cc6b9f83ede 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -66,6 +66,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
DEFAULT_FLAGS.put("settings_silky_home", "false");
+ DEFAULT_FLAGS.put("settings_contextual_home", "false");
}
/**
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 5f963b019335..4d1402a0d6d6 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -25,6 +25,7 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyA
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+import static android.util.apk.ApkSigningBlockUtils.verifyProofOfRotationStruct;
import android.os.Build;
import android.util.ArrayMap;
@@ -53,7 +54,6 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -90,9 +90,10 @@ public class ApkSignatureSchemeV3Verifier {
* associated with each signer.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws SecurityException if the APK Signature Scheme v3 signature of this APK does not
- * verify.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws SecurityException if the APK Signature Scheme v3 signature of this APK does
+ * not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static VerifiedSigner verify(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -106,7 +107,7 @@ public class ApkSignatureSchemeV3Verifier {
* Block while gathering signer information. The APK contents are not verified.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static VerifiedSigner unsafeGetCertsWithoutVerification(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -125,9 +126,10 @@ public class ApkSignatureSchemeV3Verifier {
* associated with each signer.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws SecurityException if an APK Signature Scheme v3 signature of this APK does not
- * verify.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws SecurityException if an APK Signature Scheme v3 signature of this APK does
+ * not
+ * verify.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
throws SignatureNotFoundException, SecurityException, IOException {
@@ -140,7 +142,7 @@ public class ApkSignatureSchemeV3Verifier {
* additional information relevant for verifying the block against the file.
*
* @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
public static SignatureInfo findSignature(RandomAccessFile apk)
throws IOException, SignatureNotFoundException {
@@ -152,7 +154,7 @@ public class ApkSignatureSchemeV3Verifier {
* Block.
*
* @param signatureInfo APK Signature Scheme v3 Block and information relevant for verifying it
- * against the APK file.
+ * against the APK file.
*/
private static VerifiedSigner verify(
RandomAccessFile apk,
@@ -160,7 +162,7 @@ public class ApkSignatureSchemeV3Verifier {
boolean doVerifyIntegrity) throws SecurityException, IOException {
int signerCount = 0;
Map<Integer, byte[]> contentDigests = new ArrayMap<>();
- Pair<X509Certificate[], VerifiedProofOfRotation> result = null;
+ Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation> result = null;
CertificateFactory certFactory;
try {
certFactory = CertificateFactory.getInstance("X.509");
@@ -215,10 +217,11 @@ public class ApkSignatureSchemeV3Verifier {
return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
}
- private static Pair<X509Certificate[], VerifiedProofOfRotation> verifySigner(
- ByteBuffer signerBlock,
- Map<Integer, byte[]> contentDigests,
- CertificateFactory certFactory)
+ private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+ verifySigner(
+ ByteBuffer signerBlock,
+ Map<Integer, byte[]> contentDigests,
+ CertificateFactory certFactory)
throws SecurityException, IOException, PlatformNotSupportedException {
ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
int minSdkVersion = signerBlock.getInt();
@@ -228,9 +231,9 @@ public class ApkSignatureSchemeV3Verifier {
// this signature isn't meant to be used with this platform, skip it.
throw new PlatformNotSupportedException(
"Signer not supported by this platform "
- + "version. This platform: " + Build.VERSION.SDK_INT
- + ", signer minSdkVersion: " + minSdkVersion
- + ", maxSdkVersion: " + maxSdkVersion);
+ + "version. This platform: " + Build.VERSION.SDK_INT
+ + ", signer minSdkVersion: " + minSdkVersion
+ + ", maxSdkVersion: " + maxSdkVersion);
}
ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
@@ -331,7 +334,8 @@ public class ApkSignatureSchemeV3Verifier {
&& (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
throw new SecurityException(
getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
- + " contents digest does not match the digest specified by a preceding signer");
+ + " contents digest does not match the digest specified by a "
+ + "preceding signer");
}
ByteBuffer certificates = getLengthPrefixedSlice(signedData);
@@ -379,11 +383,11 @@ public class ApkSignatureSchemeV3Verifier {
private static final int PROOF_OF_ROTATION_ATTR_ID = 0x3ba06f8c;
- private static Pair<X509Certificate[], VerifiedProofOfRotation> verifyAdditionalAttributes(
- ByteBuffer attrs, List<X509Certificate> certs, CertificateFactory certFactory)
- throws IOException {
+ private static Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation>
+ verifyAdditionalAttributes(ByteBuffer attrs, List<X509Certificate> certs,
+ CertificateFactory certFactory) throws IOException {
X509Certificate[] certChain = certs.toArray(new X509Certificate[certs.size()]);
- VerifiedProofOfRotation por = null;
+ ApkSigningBlockUtils.VerifiedProofOfRotation por = null;
while (attrs.hasRemaining()) {
ByteBuffer attr = getLengthPrefixedSlice(attrs);
@@ -392,7 +396,7 @@ public class ApkSignatureSchemeV3Verifier {
+ "ID. Remaining: " + attr.remaining());
}
int id = attr.getInt();
- switch(id) {
+ switch (id) {
case PROOF_OF_ROTATION_ATTR_ID:
if (por != null) {
throw new SecurityException("Encountered multiple Proof-of-rotation records"
@@ -404,7 +408,7 @@ public class ApkSignatureSchemeV3Verifier {
try {
if (por.certs.size() > 0
&& !Arrays.equals(por.certs.get(por.certs.size() - 1).getEncoded(),
- certChain[0].getEncoded())) {
+ certChain[0].getEncoded())) {
throw new SecurityException("Terminal certificate in Proof-of-rotation"
+ " record does not match APK signing certificate");
}
@@ -422,96 +426,6 @@ public class ApkSignatureSchemeV3Verifier {
return Pair.create(certChain, por);
}
- private static VerifiedProofOfRotation verifyProofOfRotationStruct(
- ByteBuffer porBuf,
- CertificateFactory certFactory)
- throws SecurityException, IOException {
- int levelCount = 0;
- int lastSigAlgorithm = -1;
- X509Certificate lastCert = null;
- List<X509Certificate> certs = new ArrayList<>();
- List<Integer> flagsList = new ArrayList<>();
-
- // Proof-of-rotation struct:
- // A uint32 version code followed by basically a singly linked list of nodes, called levels
- // here, each of which have the following structure:
- // * length-prefix for the entire level
- // - length-prefixed signed data (if previous level exists)
- // * length-prefixed X509 Certificate
- // * uint32 signature algorithm ID describing how this signed data was signed
- // - uint32 flags describing how to treat the cert contained in this level
- // - uint32 signature algorithm ID to use to verify the signature of the next level. The
- // algorithm here must match the one in the signed data section of the next level.
- // - length-prefixed signature over the signed data in this level. The signature here
- // is verified using the certificate from the previous level.
- // The linking is provided by the certificate of each level signing the one of the next.
-
- try {
-
- // get the version code, but don't do anything with it: creator knew about all our flags
- porBuf.getInt();
- HashSet<X509Certificate> certHistorySet = new HashSet<>();
- while (porBuf.hasRemaining()) {
- levelCount++;
- ByteBuffer level = getLengthPrefixedSlice(porBuf);
- ByteBuffer signedData = getLengthPrefixedSlice(level);
- int flags = level.getInt();
- int sigAlgorithm = level.getInt();
- byte[] signature = readLengthPrefixedByteArray(level);
-
- if (lastCert != null) {
- // Use previous level cert to verify current level
- Pair<String, ? extends AlgorithmParameterSpec> sigAlgParams =
- getSignatureAlgorithmJcaSignatureAlgorithm(lastSigAlgorithm);
- PublicKey publicKey = lastCert.getPublicKey();
- Signature sig = Signature.getInstance(sigAlgParams.first);
- sig.initVerify(publicKey);
- if (sigAlgParams.second != null) {
- sig.setParameter(sigAlgParams.second);
- }
- sig.update(signedData);
- if (!sig.verify(signature)) {
- throw new SecurityException("Unable to verify signature of certificate #"
- + levelCount + " using " + sigAlgParams.first + " when verifying"
- + " Proof-of-rotation record");
- }
- }
-
- signedData.rewind();
- byte[] encodedCert = readLengthPrefixedByteArray(signedData);
- int signedSigAlgorithm = signedData.getInt();
- if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) {
- throw new SecurityException("Signing algorithm ID mismatch for certificate #"
- + levelCount + " when verifying Proof-of-rotation record");
- }
- lastCert = (X509Certificate)
- certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
- lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
-
- lastSigAlgorithm = sigAlgorithm;
- if (certHistorySet.contains(lastCert)) {
- throw new SecurityException("Encountered duplicate entries in "
- + "Proof-of-rotation record at certificate #" + levelCount + ". All "
- + "signing certificates should be unique");
- }
- certHistorySet.add(lastCert);
- certs.add(lastCert);
- flagsList.add(flags);
- }
- } catch (IOException | BufferUnderflowException e) {
- throw new IOException("Failed to parse Proof-of-rotation record", e);
- } catch (NoSuchAlgorithmException | InvalidKeyException
- | InvalidAlgorithmParameterException | SignatureException e) {
- throw new SecurityException(
- "Failed to verify signature over signed data for certificate #"
- + levelCount + " when verifying Proof-of-rotation record", e);
- } catch (CertificateException e) {
- throw new SecurityException("Failed to decode certificate #" + levelCount
- + " when verifying Proof-of-rotation record", e);
- }
- return new VerifiedProofOfRotation(certs, flagsList);
- }
-
static byte[] getVerityRootHash(String apkPath)
throws IOException, SignatureNotFoundException, SecurityException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -523,7 +437,7 @@ public class ApkSignatureSchemeV3Verifier {
static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
- NoSuchAlgorithmException {
+ NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
@@ -532,7 +446,7 @@ public class ApkSignatureSchemeV3Verifier {
static byte[] generateApkVerityRootHash(String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException,
- SignatureNotFoundException {
+ SignatureNotFoundException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
VerifiedSigner vSigner = verify(apk, false);
@@ -545,35 +459,21 @@ public class ApkSignatureSchemeV3Verifier {
}
/**
- * Verified processed proof of rotation.
- *
- * @hide for internal use only.
- */
- public static class VerifiedProofOfRotation {
- public final List<X509Certificate> certs;
- public final List<Integer> flagsList;
-
- public VerifiedProofOfRotation(List<X509Certificate> certs, List<Integer> flagsList) {
- this.certs = certs;
- this.flagsList = flagsList;
- }
- }
-
- /**
* Verified APK Signature Scheme v3 signer, including the proof of rotation structure.
*
* @hide for internal use only.
*/
public static class VerifiedSigner {
public final X509Certificate[] certs;
- public final VerifiedProofOfRotation por;
+ public final ApkSigningBlockUtils.VerifiedProofOfRotation por;
public final byte[] verityRootHash;
// Algorithm -> digest map of signed digests in the signature.
// All these are verified if requested.
public final Map<Integer, byte[]> contentDigests;
- public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por,
+ public VerifiedSigner(X509Certificate[] certs,
+ ApkSigningBlockUtils.VerifiedProofOfRotation por,
byte[] verityRootHash, Map<Integer, byte[]> contentDigests) {
this.certs = certs;
this.por = por;
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 021f232979ef..c97c995641d1 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -19,6 +19,7 @@ package android.util.apk;
import android.util.ArrayMap;
import android.util.Pair;
+import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -26,12 +27,23 @@ import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
/**
@@ -51,9 +63,8 @@ public final class ApkSigningBlockUtils {
* @param blockId the ID value in the APK Signing Block's sequence of ID-value pairs
* identifying the appropriate block to find, e.g. the APK Signature Scheme v2
* block ID.
- *
* @throws SignatureNotFoundException if the APK is not signed using this scheme.
- * @throws IOException if an I/O error occurs while reading the APK file.
+ * @throws IOException if an I/O error occurs while reading the APK file.
*/
static SignatureInfo findSignature(RandomAccessFile apk, int blockId)
throws IOException, SignatureNotFoundException {
@@ -377,7 +388,7 @@ public final class ApkSigningBlockUtils {
/**
* Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
*
- * @throws IOException if an I/O error occurs while reading the file.
+ * @throws IOException if an I/O error occurs while reading the file.
* @throws SignatureNotFoundException if the EoCD could not be found.
*/
static Pair<ByteBuffer, Long> getEocd(RandomAccessFile apk)
@@ -398,13 +409,13 @@ public final class ApkSigningBlockUtils {
if (centralDirOffset > eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory offset out of range: " + centralDirOffset
- + ". ZIP End of Central Directory offset: " + eocdOffset);
+ + ". ZIP End of Central Directory offset: " + eocdOffset);
}
long centralDirSize = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
if (centralDirOffset + centralDirSize != eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory is not immediately followed by End of Central"
- + " Directory");
+ + " Directory");
}
return centralDirOffset;
}
@@ -687,7 +698,7 @@ public final class ApkSigningBlockUtils {
static Pair<ByteBuffer, Long> findApkSigningBlock(
RandomAccessFile apk, long centralDirOffset)
- throws IOException, SignatureNotFoundException {
+ throws IOException, SignatureNotFoundException {
// FORMAT:
// OFFSET DATA TYPE DESCRIPTION
// * @+0 bytes uint64: size in bytes (excluding this field)
@@ -806,4 +817,108 @@ public final class ApkSigningBlockUtils {
}
}
+ static VerifiedProofOfRotation verifyProofOfRotationStruct(
+ ByteBuffer porBuf,
+ CertificateFactory certFactory)
+ throws SecurityException, IOException {
+ int levelCount = 0;
+ int lastSigAlgorithm = -1;
+ X509Certificate lastCert = null;
+ List<X509Certificate> certs = new ArrayList<>();
+ List<Integer> flagsList = new ArrayList<>();
+
+ // Proof-of-rotation struct:
+ // A uint32 version code followed by basically a singly linked list of nodes, called levels
+ // here, each of which have the following structure:
+ // * length-prefix for the entire level
+ // - length-prefixed signed data (if previous level exists)
+ // * length-prefixed X509 Certificate
+ // * uint32 signature algorithm ID describing how this signed data was signed
+ // - uint32 flags describing how to treat the cert contained in this level
+ // - uint32 signature algorithm ID to use to verify the signature of the next level. The
+ // algorithm here must match the one in the signed data section of the next level.
+ // - length-prefixed signature over the signed data in this level. The signature here
+ // is verified using the certificate from the previous level.
+ // The linking is provided by the certificate of each level signing the one of the next.
+
+ try {
+
+ // get the version code, but don't do anything with it: creator knew about all our flags
+ porBuf.getInt();
+ HashSet<X509Certificate> certHistorySet = new HashSet<>();
+ while (porBuf.hasRemaining()) {
+ levelCount++;
+ ByteBuffer level = getLengthPrefixedSlice(porBuf);
+ ByteBuffer signedData = getLengthPrefixedSlice(level);
+ int flags = level.getInt();
+ int sigAlgorithm = level.getInt();
+ byte[] signature = readLengthPrefixedByteArray(level);
+
+ if (lastCert != null) {
+ // Use previous level cert to verify current level
+ Pair<String, ? extends AlgorithmParameterSpec> sigAlgParams =
+ getSignatureAlgorithmJcaSignatureAlgorithm(lastSigAlgorithm);
+ PublicKey publicKey = lastCert.getPublicKey();
+ Signature sig = Signature.getInstance(sigAlgParams.first);
+ sig.initVerify(publicKey);
+ if (sigAlgParams.second != null) {
+ sig.setParameter(sigAlgParams.second);
+ }
+ sig.update(signedData);
+ if (!sig.verify(signature)) {
+ throw new SecurityException("Unable to verify signature of certificate #"
+ + levelCount + " using " + sigAlgParams.first + " when verifying"
+ + " Proof-of-rotation record");
+ }
+ }
+
+ signedData.rewind();
+ byte[] encodedCert = readLengthPrefixedByteArray(signedData);
+ int signedSigAlgorithm = signedData.getInt();
+ if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) {
+ throw new SecurityException("Signing algorithm ID mismatch for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record");
+ }
+ lastCert = (X509Certificate)
+ certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+ lastCert = new VerbatimX509Certificate(lastCert, encodedCert);
+
+ lastSigAlgorithm = sigAlgorithm;
+ if (certHistorySet.contains(lastCert)) {
+ throw new SecurityException("Encountered duplicate entries in "
+ + "Proof-of-rotation record at certificate #" + levelCount + ". All "
+ + "signing certificates should be unique");
+ }
+ certHistorySet.add(lastCert);
+ certs.add(lastCert);
+ flagsList.add(flags);
+ }
+ } catch (IOException | BufferUnderflowException e) {
+ throw new IOException("Failed to parse Proof-of-rotation record", e);
+ } catch (NoSuchAlgorithmException | InvalidKeyException
+ | InvalidAlgorithmParameterException | SignatureException e) {
+ throw new SecurityException(
+ "Failed to verify signature over signed data for certificate #"
+ + levelCount + " when verifying Proof-of-rotation record", e);
+ } catch (CertificateException e) {
+ throw new SecurityException("Failed to decode certificate #" + levelCount
+ + " when verifying Proof-of-rotation record", e);
+ }
+ return new VerifiedProofOfRotation(certs, flagsList);
+ }
+
+ /**
+ * Verified processed proof of rotation.
+ *
+ * @hide for internal use only.
+ */
+ public static class VerifiedProofOfRotation {
+ public final List<X509Certificate> certs;
+ public final List<Integer> flagsList;
+
+ public VerifiedProofOfRotation(List<X509Certificate> certs, List<Integer> flagsList) {
+ this.certs = certs;
+ this.flagsList = flagsList;
+ }
+ }
}
diff --git a/core/java/android/util/apk/SourceStampVerificationResult.java b/core/java/android/util/apk/SourceStampVerificationResult.java
index 2edaf623fb94..8b9eee2f796e 100644
--- a/core/java/android/util/apk/SourceStampVerificationResult.java
+++ b/core/java/android/util/apk/SourceStampVerificationResult.java
@@ -19,6 +19,8 @@ package android.util.apk;
import android.annotation.Nullable;
import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.List;
/**
* A class encapsulating the result from the source stamp verifier
@@ -32,12 +34,15 @@ public final class SourceStampVerificationResult {
private final boolean mPresent;
private final boolean mVerified;
private final Certificate mCertificate;
+ private final List<? extends Certificate> mCertificateLineage;
private SourceStampVerificationResult(
- boolean present, boolean verified, @Nullable Certificate certificate) {
+ boolean present, boolean verified, @Nullable Certificate certificate,
+ List<? extends Certificate> certificateLineage) {
this.mPresent = present;
this.mVerified = verified;
this.mCertificate = certificate;
+ this.mCertificateLineage = certificateLineage;
}
public boolean isPresent() {
@@ -52,6 +57,10 @@ public final class SourceStampVerificationResult {
return mCertificate;
}
+ public List<? extends Certificate> getCertificateLineage() {
+ return mCertificateLineage;
+ }
+
/**
* Create a non-present source stamp outcome.
*
@@ -59,18 +68,21 @@ public final class SourceStampVerificationResult {
*/
public static SourceStampVerificationResult notPresent() {
return new SourceStampVerificationResult(
- /* present= */ false, /* verified= */ false, /* certificate= */ null);
+ /* present= */ false, /* verified= */ false, /* certificate= */
+ null, /* certificateLineage= */ Collections.emptyList());
}
/**
* Create a verified source stamp outcome.
*
- * @param certificate The source stamp certificate.
+ * @param certificate The source stamp certificate.
+ * @param certificateLineage The proof-of-rotation lineage for the source stamp.
* @return A verified source stamp result, and the source stamp certificate.
*/
- public static SourceStampVerificationResult verified(Certificate certificate) {
+ public static SourceStampVerificationResult verified(Certificate certificate,
+ List<? extends Certificate> certificateLineage) {
return new SourceStampVerificationResult(
- /* present= */ true, /* verified= */ true, certificate);
+ /* present= */ true, /* verified= */ true, certificate, certificateLineage);
}
/**
@@ -80,6 +92,7 @@ public final class SourceStampVerificationResult {
*/
public static SourceStampVerificationResult notVerified() {
return new SourceStampVerificationResult(
- /* present= */ true, /* verified= */ false, /* certificate= */ null);
+ /* present= */ true, /* verified= */ false, /* certificate= */
+ null, /* certificateLineage= */ Collections.emptyList());
}
}
diff --git a/core/java/android/util/apk/SourceStampVerifier.java b/core/java/android/util/apk/SourceStampVerifier.java
index 5fc242353d51..f9e312146ccf 100644
--- a/core/java/android/util/apk/SourceStampVerifier.java
+++ b/core/java/android/util/apk/SourceStampVerifier.java
@@ -23,6 +23,7 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContent
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
+import static android.util.apk.ApkSigningBlockUtils.verifyProofOfRotationStruct;
import android.util.Pair;
import android.util.Slog;
@@ -44,12 +45,14 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -76,6 +79,7 @@ public abstract class SourceStampVerifier {
private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
private static final int SOURCE_STAMP_BLOCK_ID = 0x6dff800d;
+ private static final int PROOF_OF_ROTATION_ATTR_ID = 0x9d6303f7;
private static final int VERSION_JAR_SIGNATURE_SCHEME = 1;
private static final int VERSION_APK_SIGNATURE_SCHEME_V2 = 2;
@@ -85,11 +89,13 @@ public abstract class SourceStampVerifier {
private static final String SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME = "stamp-cert-sha256";
/** Hidden constructor to prevent instantiation. */
- private SourceStampVerifier() {}
+ private SourceStampVerifier() {
+ }
- /** Verifies SourceStamp present in a list of APKs. */
+ /** Verifies SourceStamp present in a list of (split) APKs for the same app. */
public static SourceStampVerificationResult verify(List<String> apkFiles) {
Certificate stampCertificate = null;
+ List<? extends Certificate> stampCertificateLineage = Collections.emptyList();
for (String apkFile : apkFiles) {
SourceStampVerificationResult sourceStampVerificationResult = verify(apkFile);
if (!sourceStampVerificationResult.isPresent()
@@ -97,12 +103,15 @@ public abstract class SourceStampVerifier {
return sourceStampVerificationResult;
}
if (stampCertificate != null
- && !stampCertificate.equals(sourceStampVerificationResult.getCertificate())) {
+ && (!stampCertificate.equals(sourceStampVerificationResult.getCertificate())
+ || !stampCertificateLineage.equals(
+ sourceStampVerificationResult.getCertificateLineage()))) {
return SourceStampVerificationResult.notVerified();
}
stampCertificate = sourceStampVerificationResult.getCertificate();
+ stampCertificateLineage = sourceStampVerificationResult.getCertificateLineage();
}
- return SourceStampVerificationResult.verified(stampCertificate);
+ return SourceStampVerificationResult.verified(stampCertificate, stampCertificateLineage);
}
/** Verifies SourceStamp present in the provided APK. */
@@ -177,21 +186,44 @@ public abstract class SourceStampVerifier {
"No signatures found for signature scheme %d",
signatureSchemeDigest.getKey()));
}
+ ByteBuffer signatures = ApkSigningBlockUtils.getLengthPrefixedSlice(
+ signedSignatureSchemeData.get(signatureSchemeDigest.getKey()));
verifySourceStampSignature(
- signedSignatureSchemeData.get(signatureSchemeDigest.getKey()),
+ signatureSchemeDigest.getValue(),
sourceStampCertificate,
- signatureSchemeDigest.getValue());
+ signatures);
}
- return SourceStampVerificationResult.verified(sourceStampCertificate);
+ List<? extends Certificate> sourceStampCertificateLineage = Collections.emptyList();
+ if (sourceStampBlockData.hasRemaining()) {
+ // The stamp block contains some additional attributes.
+ ByteBuffer stampAttributeData = getLengthPrefixedSlice(sourceStampBlockData);
+ ByteBuffer stampAttributeDataSignatures = getLengthPrefixedSlice(sourceStampBlockData);
+
+ byte[] stampAttributeBytes = new byte[stampAttributeData.remaining()];
+ stampAttributeData.get(stampAttributeBytes);
+ stampAttributeData.flip();
+
+ verifySourceStampSignature(stampAttributeBytes, sourceStampCertificate,
+ stampAttributeDataSignatures);
+ ApkSigningBlockUtils.VerifiedProofOfRotation verifiedProofOfRotation =
+ verifySourceStampAttributes(stampAttributeData, sourceStampCertificate);
+ if (verifiedProofOfRotation != null) {
+ sourceStampCertificateLineage = verifiedProofOfRotation.certs;
+ }
+ }
+
+ return SourceStampVerificationResult.verified(sourceStampCertificate,
+ sourceStampCertificateLineage);
}
/**
* Verify the SourceStamp certificate found in the signing block is the same as the SourceStamp
* certificate found in the APK. It returns the verified certificate.
*
- * @param sourceStampBlockData the source stamp block in the APK signing block which contains
- * the certificate used to sign the stamp digests.
+ * @param sourceStampBlockData the source stamp block in the APK signing block which
+ * contains
+ * the certificate used to sign the stamp digests.
* @param sourceStampCertificateDigest the source stamp certificate digest found in the APK.
*/
private static X509Certificate verifySourceStampCertificate(
@@ -230,16 +262,16 @@ public abstract class SourceStampVerifier {
* Verify the SourceStamp signature found in the signing block is signed by the SourceStamp
* certificate found in the APK.
*
- * @param signedBlockData the source stamp block in the APK signing block which contains the
- * stamp signed digests.
+ * @param data the digest to be verified being signed by the source stamp
+ * certificate.
* @param sourceStampCertificate the source stamp certificate used to sign the stamp digests.
- * @param digest the digest to be verified being signed by the source stamp certificate.
+ * @param signatures the source stamp block in the APK signing block which contains
+ * the stamp signed digests.
*/
- private static void verifySourceStampSignature(
- ByteBuffer signedBlockData, X509Certificate sourceStampCertificate, byte[] digest)
+ private static void verifySourceStampSignature(byte[] data,
+ X509Certificate sourceStampCertificate, ByteBuffer signatures)
throws IOException {
// Parse the signatures block and identify supported signatures
- ByteBuffer signatures = ApkSigningBlockUtils.getLengthPrefixedSlice(signedBlockData);
int signatureCount = 0;
int bestSigAlgorithm = -1;
byte[] bestSigAlgorithmSignatureBytes = null;
@@ -285,7 +317,7 @@ public abstract class SourceStampVerifier {
if (jcaSignatureAlgorithmParams != null) {
sig.setParameter(jcaSignatureAlgorithmParams);
}
- sig.update(digest);
+ sig.update(data);
sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
} catch (InvalidKeyException
| InvalidAlgorithmParameterException
@@ -414,6 +446,46 @@ public abstract class SourceStampVerifier {
return result.array();
}
+ private static ApkSigningBlockUtils.VerifiedProofOfRotation verifySourceStampAttributes(
+ ByteBuffer stampAttributeData,
+ X509Certificate sourceStampCertificate)
+ throws IOException {
+ CertificateFactory certFactory;
+ try {
+ certFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
+ }
+ ByteBuffer stampAttributes = getLengthPrefixedSlice(stampAttributeData);
+ ApkSigningBlockUtils.VerifiedProofOfRotation verifiedProofOfRotation = null;
+ while (stampAttributes.hasRemaining()) {
+ ByteBuffer attribute = getLengthPrefixedSlice(stampAttributes);
+ int id = attribute.getInt();
+ if (id == PROOF_OF_ROTATION_ATTR_ID) {
+ if (verifiedProofOfRotation != null) {
+ throw new SecurityException("Encountered multiple Proof-of-rotation records"
+ + " when verifying source stamp signature");
+ }
+ verifiedProofOfRotation = verifyProofOfRotationStruct(attribute, certFactory);
+ // Make sure that the last certificate in the Proof-of-rotation record matches
+ // the one used to sign this APK.
+ try {
+ if (verifiedProofOfRotation.certs.size() > 0
+ && !Arrays.equals(verifiedProofOfRotation.certs.get(
+ verifiedProofOfRotation.certs.size() - 1).getEncoded(),
+ sourceStampCertificate.getEncoded())) {
+ throw new SecurityException("Terminal certificate in Proof-of-rotation"
+ + " record does not match source stamp certificate");
+ }
+ } catch (CertificateEncodingException e) {
+ throw new SecurityException("Failed to encode certificate when comparing"
+ + " Proof-of-rotation record and source stamp certificate", e);
+ }
+ }
+ }
+ return verifiedProofOfRotation;
+ }
+
private static byte[] computeSha256Digest(byte[] input) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index e78e08e4f170..2944f72f7f4d 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -30,8 +30,9 @@
#include <binder/Parcel.h>
-#include <ui/GraphicBuffer.h>
#include <private/gui/ComposerService.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
#include <hardware/gralloc1.h>
#include <grallocusage/GrallocUsageConversion.h>
@@ -166,6 +167,20 @@ static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
return AHardwareBuffer_convertFromGrallocUsageBits(buffer->getUsage());
}
+static jlong android_hardware_HardwareBuffer_estimateSize(jlong nativeObject) {
+ GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+
+ uint32_t bpp = bytesPerPixel(buffer->getPixelFormat());
+ if (bpp == 0) {
+ // If the pixel format is not recognized, use 1 as default.
+ bpp = 1;
+ }
+
+ const uint32_t bufferStride =
+ buffer->getStride() > 0 ? buffer->getStride() : buffer->getWidth();
+ return static_cast<jlong>(buffer->getHeight() * bufferStride * bpp);
+}
+
// ----------------------------------------------------------------------------
// Serialization
// ----------------------------------------------------------------------------
@@ -247,6 +262,7 @@ uint64_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usag
const char* const kClassPathName = "android/hardware/HardwareBuffer";
+// clang-format off
static const JNINativeMethod gMethods[] = {
{ "nCreateHardwareBuffer", "(IIIIJ)J",
(void*) android_hardware_HardwareBuffer_create },
@@ -267,7 +283,11 @@ static const JNINativeMethod gMethods[] = {
{ "nGetFormat", "(J)I", (void*) android_hardware_HardwareBuffer_getFormat },
{ "nGetLayers", "(J)I", (void*) android_hardware_HardwareBuffer_getLayers },
{ "nGetUsage", "(J)J", (void*) android_hardware_HardwareBuffer_getUsage },
+
+ // --------------- @CriticalNative ----------------------
+ { "nEstimateSize", "(J)J", (void*) android_hardware_HardwareBuffer_estimateSize },
};
+// clang-format on
int register_android_hardware_HardwareBuffer(JNIEnv* env) {
int err = RegisterMethodsOrDie(env, kClassPathName, gMethods,
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 7cfe3bc1020a..0892b70b9651 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -114,7 +114,7 @@ static jint android_os_Parcel_dataCapacity(jlong nativePtr)
return parcel ? parcel->dataCapacity() : 0;
}
-static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
+static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -122,9 +122,7 @@ static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nati
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
- return parcel->getOpenAshmemSize();
}
- return 0;
}
static void android_os_Parcel_setDataPosition(jlong nativePtr, jint pos)
@@ -308,7 +306,7 @@ static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong
}
}
-static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
+static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -317,9 +315,7 @@ static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jl
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
- return parcel->getOpenAshmemSize();
}
- return 0;
}
static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -506,14 +502,12 @@ static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
return reinterpret_cast<jlong>(parcel);
}
-static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
+static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
parcel->freeData();
- return parcel->getOpenAshmemSize();
}
- return 0;
}
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -551,12 +545,12 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
return ret;
}
-static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
+static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
jbyteArray data, jint offset, jint length)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel == NULL || length < 0) {
- return 0;
+ return;
}
jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
@@ -570,7 +564,6 @@ static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativ
env->ReleasePrimitiveArrayCritical(data, array, 0);
}
- return parcel->getOpenAshmemSize();
}
static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisNativePtr,
@@ -588,23 +581,23 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN
return thisParcel->compareData(*otherParcel);
}
-static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
+static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
jlong otherNativePtr, jint offset, jint length)
{
Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
if (thisParcel == NULL) {
- return 0;
+ return;
}
Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
if (otherParcel == NULL) {
- return thisParcel->getOpenAshmemSize();
+ return;
}
status_t err = thisParcel->appendFrom(otherParcel, offset, length);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
- return thisParcel->getOpenAshmemSize();
+ return;
}
static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
@@ -720,7 +713,7 @@ static const JNINativeMethod gParcelMethods[] = {
// @CriticalNative
{"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
// @FastNative
- {"nativeSetDataSize", "(JI)J", (void*)android_os_Parcel_setDataSize},
+ {"nativeSetDataSize", "(JI)V", (void*)android_os_Parcel_setDataSize},
// @CriticalNative
{"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
// @FastNative
@@ -749,7 +742,7 @@ static const JNINativeMethod gParcelMethods[] = {
// @FastNative
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
// @FastNative
- {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
+ {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
{"nativeReadByteArray", "(J[BI)Z", (void*)android_os_Parcel_readByteArray},
@@ -772,13 +765,13 @@ static const JNINativeMethod gParcelMethods[] = {
{"nativeReadFileDescriptor", "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
- {"nativeFreeBuffer", "(J)J", (void*)android_os_Parcel_freeBuffer},
+ {"nativeFreeBuffer", "(J)V", (void*)android_os_Parcel_freeBuffer},
{"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
- {"nativeUnmarshall", "(J[BII)J", (void*)android_os_Parcel_unmarshall},
+ {"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
{"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData},
- {"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom},
+ {"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
// @CriticalNative
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 050c1c4b4df5..ac08d96ab303 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -239,9 +239,7 @@
<!-- Old synonym for "privileged". Deprecated in API level 23. -->
<flag name="system" value="0x10" />
<!-- Additional flag from base permission type: this permission can also
- (optionally) be granted to development applications. Although undocumented, the
- permission state used to be shared by all users (including future users), but it is
- managed per-user since API level 31. -->
+ (optionally) be granted to development applications. -->
<flag name="development" value="0x20" />
<!-- Additional flag from base permission type: this permission is closely
associated with an app op for controlling access. -->
diff --git a/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk
new file mode 100644
index 000000000000..f9777c3f5ca5
--- /dev/null
+++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-invalid.apk
Binary files differ
diff --git a/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk
new file mode 100644
index 000000000000..955652e387b8
--- /dev/null
+++ b/core/tests/coretests/assets/SourceStampVerifierTest/stamp-lineage-valid.apk
Binary files differ
diff --git a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
index 81d54b57486c..bc0bddba2f20 100644
--- a/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
+++ b/core/tests/coretests/src/android/util/apk/SourceStampVerifierTest.java
@@ -17,6 +17,7 @@
package android.util.apk;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -198,6 +199,38 @@ public class SourceStampVerifierTest {
assertNull(result.getCertificate());
}
+ @Test
+ public void testSourceStamp_validStampLineage() throws Exception {
+ mPrimaryApk = getApk("SourceStampVerifierTest/stamp-lineage-valid.apk");
+ byte[] expectedStampCertHash = getSourceStampCertificateHashFromApk(mPrimaryApk);
+
+ SourceStampVerificationResult result =
+ SourceStampVerifier.verify(mPrimaryApk.getAbsolutePath());
+
+ assertTrue(result.isPresent());
+ assertTrue(result.isVerified());
+ assertNotNull(result.getCertificate());
+ byte[] actualStampCertHash =
+ MessageDigest.getInstance("SHA-256").digest(result.getCertificate().getEncoded());
+ assertArrayEquals(expectedStampCertHash, actualStampCertHash);
+ assertEquals(2, result.getCertificateLineage().size());
+ assertEquals(result.getCertificate(),
+ result.getCertificateLineage().get(result.getCertificateLineage().size() - 1));
+ }
+
+ @Test
+ public void testSourceStamp_invalidStampLineage() throws Exception {
+ mPrimaryApk = getApk("SourceStampVerifierTest/stamp-lineage-invalid.apk");
+
+ SourceStampVerificationResult result =
+ SourceStampVerifier.verify(mPrimaryApk.getAbsolutePath());
+
+ assertTrue(result.isPresent());
+ assertFalse(result.isVerified());
+ assertNull(result.getCertificate());
+ assertTrue(result.getCertificateLineage().isEmpty());
+ }
+
private File getApk(String apkPath) throws IOException {
File apk = File.createTempFile("SourceStampApk", ".apk");
try (InputStream inputStream = mContext.getAssets().open(apkPath)) {
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index ca37917f437f..4cac7fbb023b 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -301,7 +301,7 @@ public final class ImageDecoder implements AutoCloseable {
ImageDecoder decoder = null;
try {
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, preferAnimation, source);
} finally {
if (decoder == null) {
IoUtils.closeQuietly(stream);
@@ -349,7 +349,7 @@ public final class ImageDecoder implements AutoCloseable {
try {
try {
Os.lseek(fd, offset, SEEK_SET);
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, assetFd.getDeclaredLength(), preferAnimation, source);
} catch (ErrnoException e) {
decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source);
}
@@ -2008,7 +2008,7 @@ public final class ImageDecoder implements AutoCloseable {
private static native ImageDecoder nCreate(InputStream is, byte[] storage,
boolean preferAnimation, Source src) throws IOException;
// The fd must be seekable.
- private static native ImageDecoder nCreate(FileDescriptor fd,
+ private static native ImageDecoder nCreate(FileDescriptor fd, long length,
boolean preferAnimation, Source src) throws IOException;
@NonNull
private static native Bitmap nDecodeBitmap(long nativePtr,
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 15d855e9560c..a7d3f7980d37 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -47,6 +47,7 @@ public class ImageFormat {
DEPTH16,
DEPTH_POINT_CLOUD,
RAW_DEPTH,
+ RAW_DEPTH10,
PRIVATE,
HEIC
})
@@ -725,6 +726,15 @@ public class ImageFormat {
public static final int RAW_DEPTH = 0x1002;
/**
+ * Unprocessed implementation-dependent raw
+ * depth measurements, opaque with 10 bit
+ * samples and device specific bit layout.
+ *
+ * @hide
+ */
+ public static final int RAW_DEPTH10 = 0x1003;
+
+ /**
* Android private opaque image format.
* <p>
* The choices of the actual format and pixel data layout are entirely up to
@@ -797,6 +807,7 @@ public class ImageFormat {
case RAW_DEPTH:
case RAW_SENSOR:
return 16;
+ case RAW_DEPTH10:
case RAW10:
return 10;
case RAW12:
@@ -838,6 +849,7 @@ public class ImageFormat {
case DEPTH_POINT_CLOUD:
case PRIVATE:
case RAW_DEPTH:
+ case RAW_DEPTH10:
case Y8:
case DEPTH_JPEG:
case HEIC:
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 1f4fd230e55e..da91d46b0738 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -152,7 +152,7 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
}
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
- jobject fileDescriptor, jboolean preferAnimation, jobject source) {
+ jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
#else
@@ -172,7 +172,14 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
nullptr, source);
}
- std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
+ std::unique_ptr<SkFILEStream> fileStream;
+ if (length == -1) {
+ // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
+ // so SkFILEStream will figure out the size of the file on its own.
+ fileStream.reset(new SkFILEStream(file));
+ } else {
+ fileStream.reset(new SkFILEStream(file, length));
+ }
return native_create(env, std::move(fileStream), source, preferAnimation);
#endif
}
@@ -493,7 +500,7 @@ static const JNINativeMethod gImageDecoderMethods[] = {
{ "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
{ "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
{ "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
- { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+ { "nCreate", "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
{ "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
(void*) ImageDecoder_nDecodeBitmap },
{ "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 0e7eaa21888e..c1a98eabb2b7 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -46,13 +46,13 @@ import com.android.internal.location.ProviderProperties;
*/
interface ILocationManager
{
- Location getLastLocation(in LocationRequest request, String packageName, String attributionTag);
- void getCurrentLocation(in LocationRequest request, in ICancellationSignal cancellationSignal, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
+ Location getLastLocation(String provider, String packageName, String attributionTag);
+ void getCurrentLocation(String provider, in LocationRequest request, in ICancellationSignal cancellationSignal, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
- void registerLocationListener(in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
+ void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
void unregisterLocationListener(in ILocationListener listener);
- void registerLocationPendingIntent(in LocationRequest request, in PendingIntent intent, String packageName, String attributionTag);
+ void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent intent, String packageName, String attributionTag);
void unregisterLocationPendingIntent(in PendingIntent intent);
void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 04bcbfc5f6b8..d7ef24170c24 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -670,11 +670,8 @@ public class LocationManager {
public Location getLastKnownLocation(@NonNull String provider) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
-
try {
- return mService.getLastLocation(request, mContext.getPackageName(),
+ return mService.getLastLocation(provider, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -682,23 +679,11 @@ public class LocationManager {
}
/**
- * Asynchronously returns a single current location fix. This may activate sensors in order to
- * compute a new location, unlike {@link #getLastKnownLocation(String)}, which will only return
- * a cached fix if available. The given callback will be invoked once and only once, either with
- * a valid location fix or with a null location fix if the provider was unable to generate a
- * valid location.
- *
- * <p>A client may supply an optional {@link CancellationSignal}. If this is used to cancel the
- * operation, no callback should be expected after the cancellation.
- *
- * <p>This method may return locations from the very recent past (on the order of several
- * seconds), but will never return older locations (for example, several minutes old or older).
- * Clients may rely upon the guarantee that if this method returns a location, it will represent
- * the best estimation of the location of the device in the present moment.
+ * Asynchronously returns a single current location fix from the given provider.
*
- * <p>Clients calling this method from the background may notice that the method fails to
- * determine a valid location fix more often than while in the foreground. Background
- * applications may be throttled in their location accesses to some degree.
+ * <p>See
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * for more information.
*
* @param provider a provider listed by {@link #getAllProviders()}
* @param cancellationSignal an optional signal that allows for cancelling this call
@@ -714,16 +699,19 @@ public class LocationManager {
public void getCurrentLocation(@NonNull String provider,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
- getCurrentLocation(LocationRequest.createFromDeprecatedProvider(provider, 0, 0, true),
+ getCurrentLocation(
+ provider,
+ new LocationRequest.Builder(0).build(),
cancellationSignal, executor, consumer);
}
/**
- * Asynchronously returns a single current location fix based on the given
- * {@link LocationRequest}.
+ * Asynchronously returns a single current location fix from the given provider based on the
+ * given {@link LocationRequest}.
*
- * <p>See {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)} for more
- * information.
+ * <p>See
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * for more information.
*
* @param locationRequest the location request containing location parameters
* @param cancellationSignal an optional signal that allows for cancelling this call
@@ -735,13 +723,66 @@ public class LocationManager {
* @throws IllegalArgumentException if consumer is null
* @throws SecurityException if no suitable permission is present
* @hide
+ * @deprecated Use
+ * {@link #getCurrentLocation(String, LocationRequest, CancellationSignal, Executor, Consumer)}
+ * instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void getCurrentLocation(@NonNull LocationRequest locationRequest,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ getCurrentLocation(locationRequest.getProvider(), locationRequest, cancellationSignal,
+ executor, consumer);
+ }
+
+ /**
+ * Asynchronously returns a single current location fix from the given provider based on the
+ * given {@link LocationRequest}. This may activate sensors in order to compute a new location,
+ * unlike {@link #getLastKnownLocation(String)}, which will only return a cached fix if
+ * available. The given callback will be invoked once and only once, either with a valid
+ * location or with a null location if the provider was unable to generate a valid location.
+ *
+ * <p>A client may supply an optional {@link CancellationSignal}. If this is used to cancel the
+ * operation, no callback should be expected after the cancellation.
+ *
+ * <p>This method may return locations from the very recent past (on the order of several
+ * seconds), but will never return older locations (for example, several minutes old or older).
+ * Clients may rely upon the guarantee that if this method returns a location, it will represent
+ * the best estimation of the location of the device in the present moment.
+ *
+ * <p>Clients calling this method from the background may notice that the method fails to
+ * determine a valid location fix more often than while in the foreground. Background
+ * applications may be throttled in their location accesses to some degree.
+ *
+ * The given location request may be used to provide hints on how a fresh location is computed
+ * if necessary. In particular {@link LocationRequest#getDurationMillis()} can be used to
+ * provide maximum duration allowed before failing. The system will always cap the maximum
+ * amount of time a request for current location may run to some reasonable value (less than a
+ * minute for example) before the request is failed.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param locationRequest the location request containing location parameters
+ * @param cancellationSignal an optional signal that allows for cancelling this call
+ * @param executor the callback will take place on this {@link Executor}
+ * @param consumer the callback invoked with either a {@link Location} or null
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if executor is null
+ * @throws IllegalArgumentException if consumer is null
+ * @throws SecurityException if no suitable permission is present
+ */
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void getCurrentLocation(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
+
ICancellationSignal remoteCancellationSignal = CancellationSignal.createTransport();
GetCurrentLocationTransport transport = new GetCurrentLocationTransport(executor, consumer,
remoteCancellationSignal);
@@ -752,7 +793,7 @@ public class LocationManager {
}
try {
- mService.getCurrentLocation(locationRequest, remoteCancellationSignal,
+ mService.getCurrentLocation(provider, locationRequest, remoteCancellationSignal,
transport, mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(consumer));
} catch (RemoteException e) {
@@ -782,12 +823,16 @@ public class LocationManager {
public void requestSingleUpdate(
@NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(0)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ new HandlerExecutor(handler),
+ listener);
}
/**
@@ -814,12 +859,17 @@ public class LocationManager {
@NonNull LocationListener listener,
@Nullable Looper looper) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- Preconditions.checkArgument(listener != null, "invalid null listener");
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setQuality(criteria)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ new HandlerExecutor(handler),
+ listener);
}
/**
@@ -843,10 +893,13 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(0)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ pendingIntent);
}
/**
@@ -871,61 +924,27 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, 0, 0, true);
- request.setExpireIn(MAX_SINGLE_LOCATION_TIMEOUT_MS);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setQuality(criteria)
+ .setMaxUpdates(1)
+ .setDurationMillis(MAX_SINGLE_LOCATION_TIMEOUT_MS)
+ .build(),
+ pendingIntent);
}
/**
- * Register for location updates from the given provider with the given arguments. {@link
- * LocationListener} callbacks will take place on the given {@link Looper} or {@link Executor}.
- * If a null {@link Looper} is supplied, the Looper of the calling thread will be used instead.
- * Only one request can be registered for each unique listener, so any subsequent requests with
- * the same listener will overwrite all associated arguments.
+ * Register for location updates from the given provider with the given arguments, and a
+ * callback on the {@link Looper} of the calling thread.
*
- * <p> It may take a while to receive the first location update. If an immediate location is
- * required, applications may use the {@link #getLastKnownLocation(String)} method.
- *
- * <p> The location update interval can be controlled using the minimum time parameter. The
- * elapsed time between location updates will never be less than this parameter, although it may
- * be more depending on location availability and other factors. Choosing a sensible value for
- * the minimum time parameter is important to conserve battery life. Every location update
- * requires power from a variety of sensors. Select a minimum time parameter as high as possible
- * while still providing a reasonable user experience. If your application is not in the
- * foreground and showing location to the user then your application should consider switching
- * to the {@link #PASSIVE_PROVIDER} instead.
- *
- * <p> The minimum distance parameter can also be used to control the frequency of location
- * updates. If it is greater than 0 then the location provider will only send your application
- * an update when the location has changed by at least minDistance meters, AND when the minimum
- * time has elapsed. However it is more difficult for location providers to save power using the
- * minimum distance parameter, so the minimum time parameter should be the primary tool for
- * conserving battery life.
- *
- * <p> If your application wants to passively observe location updates triggered by other
- * applications, but not consume any additional power otherwise, then use the {@link
- * #PASSIVE_PROVIDER}. This provider does not turn on or modify active location providers, so
- * you do not need to be as careful about minimum time and minimum distance parameters. However,
- * if your application performs heavy work on a location update (such as network activity) then
- * you should select non-zero values for the parameters to rate-limit your update frequency in
- * the case another application enables a location provider with extremely fast updates.
- *
- * <p>In case the provider you have selected is disabled, location updates will cease, and a
- * provider availability update will be sent. As soon as the provider is enabled again, another
- * provider availability update will be sent and location updates will immediately resume.
- *
- * <p> When location callbacks are invoked, the system will hold a wakelock on your
- * application's behalf for some period of time, but not indefinitely. If your application
- * requires a long running wakelock within the location callback, you should acquire it
- * yourself.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
+ * for more detail on how this method works.
*
* <p class="note"> Prior to Jellybean, the minTime parameter was only a hint, and some location
* provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
* Android compatible devices to observe both the minTime and minDistance parameters.
*
- * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
- *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -939,21 +958,20 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, null);
+ requestLocationUpdates(provider, minTimeMs, minDistanceM, listener, null);
}
/**
- * Register for location updates using the named provider, and a callback on
- * the specified {@link Looper}.
+ * Register for location updates from the given provider with the given arguments, and a
+ * callback on the specified {@link Looper}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
+ * <p class="note">Prior to Jellybean, the minTime parameter was only a hint, and some location
+ * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
+ * Android compatible devices to observe both the minTime and minDistance parameters.
+ *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -968,21 +986,22 @@ public class LocationManager {
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener, @Nullable Looper looper) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(provider, minTimeMs, minDistanceM, new HandlerExecutor(handler),
+ listener);
}
/**
* Register for location updates using the named provider, and a callback on
* the specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
+ * <p class="note">Prior to Jellybean, the minTime parameter was only a hint, and some location
+ * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
+ * Android compatible devices to observe both the minTime and minDistance parameters.
+ *
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
@@ -1001,16 +1020,22 @@ public class LocationManager {
float minDistanceM,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, executor, listener);
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(minTimeMs)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ executor,
+ listener);
}
/**
* Register for location updates using a provider selected through the given Criteria, and a
* callback on the specified {@link Looper}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1026,19 +1051,16 @@ public class LocationManager {
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull LocationListener listener,
@Nullable Looper looper) {
- Preconditions.checkArgument(criteria != null, "invalid null criteria");
- Preconditions.checkArgument(listener != null, "invalid null listener");
-
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, listener, looper);
+ Handler handler = looper == null ? new Handler() : new Handler(looper);
+ requestLocationUpdates(minTimeMs, minDistanceM, criteria, new HandlerExecutor(handler),
+ listener);
}
/**
* Register for location updates using a provider selected through the given Criteria, and a
* callback on the specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1059,23 +1081,24 @@ public class LocationManager {
@NonNull Criteria criteria,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, executor, listener);
+ Preconditions.checkArgument(criteria != null, "invalid null criteria");
+
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(minTimeMs)
+ .setQuality(criteria)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ executor,
+ listener);
}
/**
* Register for location updates using the named provider, and callbacks delivered via the
* provided {@link PendingIntent}.
*
- * <p>The delivered pending intents will contain extras with the callback information. The keys
- * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
- * the documentation for each respective extra key for information on the values.
- *
- * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
- *
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
- * for more detail on how this method works.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)} for more
+ * detail on how this method works.
*
* @param provider a provider listed by {@link #getAllProviders()}
* @param minTimeMs minimum time interval between location updates in milliseconds
@@ -1091,9 +1114,12 @@ public class LocationManager {
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ provider,
+ new LocationRequest.Builder(minTimeMs)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ pendingIntent);
}
/**
@@ -1116,10 +1142,13 @@ public class LocationManager {
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
-
- LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
- criteria, minTimeMs, minDistanceM, false);
- requestLocationUpdates(request, pendingIntent);
+ requestLocationUpdates(
+ FUSED_PROVIDER,
+ new LocationRequest.Builder(minTimeMs)
+ .setQuality(criteria)
+ .setMinUpdateDistanceMeters(minDistanceM)
+ .build(),
+ pendingIntent);
}
/**
@@ -1131,7 +1160,7 @@ public class LocationManager {
* choose default low power parameters for location updates, but this is heavily discouraged,
* and an explicit LocationRequest should always be provided.
*
- * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
* for more detail on how this method works.
*
* @param locationRequest the location request containing location parameters
@@ -1143,7 +1172,10 @@ public class LocationManager {
* @throws SecurityException if no suitable permission is present
*
* @hide
+ * @deprecated Use
+ * {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -1159,8 +1191,8 @@ public class LocationManager {
* Register for location updates using a {@link LocationRequest}, and a callback on the
* specified {@link Executor}.
*
- * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} for more
- * detail on how this method works.
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)}
+ * for more detail on how this method works.
*
* @param locationRequest the location request containing location parameters
* @param executor the executor handling listener callbacks
@@ -1171,7 +1203,10 @@ public class LocationManager {
* @throws SecurityException if no suitable permission is present
*
* @hide
+ * @deprecated Use
+ * {@link #requestLocationUpdates(String, LocationRequest, Executor, LocationListener)} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -1180,8 +1215,93 @@ public class LocationManager {
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
if (locationRequest == null) {
- locationRequest = new LocationRequest();
+ locationRequest = LocationRequest.create();
}
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ requestLocationUpdates(locationRequest.getProvider(), locationRequest, executor, listener);
+ }
+
+ /**
+ * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
+ * the provided {@link PendingIntent}.
+ *
+ * <p>See {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)} for more
+ * detail on how this method works.
+ *
+ * @param locationRequest the location request containing location parameters
+ * @param pendingIntent the pending intent to send location updates
+ *
+ * @throws IllegalArgumentException if pendingIntent is null
+ * @throws SecurityException if no suitable permission is present
+ *
+ * @hide
+ * @deprecated Use {@link #requestLocationUpdates(String, LocationRequest, PendingIntent)}
+ * instead.
+ */
+ @Deprecated
+ @SystemApi
+ @TestApi
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void requestLocationUpdates(
+ @Nullable LocationRequest locationRequest,
+ @NonNull PendingIntent pendingIntent) {
+ if (locationRequest == null) {
+ locationRequest = LocationRequest.create();
+ }
+ Preconditions.checkArgument(locationRequest.getProvider() != null);
+ requestLocationUpdates(locationRequest.getProvider(), locationRequest, pendingIntent);
+ }
+
+ /**
+ * Register for location updates from the specified provider, using a {@link LocationRequest},
+ * and a callback on the specified {@link Executor}.
+ *
+ * <p>Only one request can be registered for each unique listener/provider pair, so any
+ * subsequent requests with the same provider and listener will overwrite all associated
+ * arguments. The same listener may be used across multiple providers with different requests
+ * for each provider.
+ *
+ * <p>It may take a while to receive the first location update. If an immediate location is
+ * required, applications may use the {@link #getLastKnownLocation(String)} method.
+ *
+ * <p>See {@link LocationRequest} documentation for an explanation of various request parameters
+ * and how they can affect the received locations.
+ *
+ * <p> If your application wants to passively observe location updates from any provider, then
+ * use the {@link #PASSIVE_PROVIDER}. This provider does not turn on or modify active location
+ * providers, so you do not need to be as careful about minimum time and minimum distance
+ * parameters. However, if your application performs heavy work on a location update (such as
+ * network activity) then you should set an explicit fastest interval on your location request
+ * in case another application enables a location provider with extremely fast updates.
+ *
+ * <p>In case the provider you have selected is disabled, location updates will cease, and a
+ * provider availability update will be sent. As soon as the provider is enabled again, another
+ * provider availability update will be sent and location updates will immediately resume.
+ *
+ * <p> When location callbacks are invoked, the system will hold a wakelock on your
+ * application's behalf for some period of time, but not indefinitely. If your application
+ * requires a long running wakelock within the location callback, you should acquire it
+ * yourself.
+ *
+ * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param locationRequest the location request containing location parameters
+ * @param executor the executor handling listener callbacks
+ * @param listener the listener to receive location updates
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if locationRequest is null
+ * @throws IllegalArgumentException if listener is null
+ * @throws SecurityException if no suitable permission is present
+ */
+ @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+ public void requestLocationUpdates(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull LocationListener listener) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
synchronized (sLocationListeners) {
WeakReference<LocationListenerTransport> reference = sLocationListeners.get(listener);
@@ -1198,7 +1318,7 @@ public class LocationManager {
// make sure that callbacks are not made on the same thread - however it is the
// easiest way to guarantee that clients will not receive callbacks after
// unregistration is complete.
- mService.registerLocationListener(locationRequest, transport,
+ mService.registerLocationListener(provider, locationRequest, transport,
mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(listener));
} catch (RemoteException e) {
@@ -1208,39 +1328,39 @@ public class LocationManager {
}
/**
- * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
- * the provided {@link PendingIntent}.
+ * Register for location updates from the specified provider, using a {@link LocationRequest},
+ * and callbacks delivered via the provided {@link PendingIntent}.
*
- * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} and
- * {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on how
- * this method works.
+ * <p>The delivered pending intents will contain extras with the callback information. The keys
+ * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
+ * the documentation for each respective extra key for information on the values.
+ *
+ * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
*
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param locationRequest the location request containing location parameters
* @param pendingIntent the pending intent to send location updates
*
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if locationRequest is null
* @throws IllegalArgumentException if pendingIntent is null
* @throws SecurityException if no suitable permission is present
- *
- * @hide
*/
- @SystemApi
- @TestApi
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
- public void requestLocationUpdates(
- @Nullable LocationRequest locationRequest,
+ public void requestLocationUpdates(@NonNull String provider,
+ @NonNull LocationRequest locationRequest,
@NonNull PendingIntent pendingIntent) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
- if (locationRequest == null) {
- locationRequest = new LocationRequest();
- }
-
try {
- mService.registerLocationPendingIntent(locationRequest, pendingIntent,
+ mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
mContext.getPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 280bd058ef0f..c53d08bdcd16 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -16,7 +16,12 @@
package android.location;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
import android.Manifest;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -26,7 +31,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemClock;
import android.os.WorkSource;
import android.util.TimeUtils;
@@ -36,73 +40,25 @@ import java.util.Objects;
/**
- * A data object that contains quality of service parameters for requests
- * to the {@link LocationManager}.
- *
- * <p>LocationRequest objects are used to request a quality of service
- * for location updates from the Location Manager.
- *
- * <p>For example, if your application wants high accuracy location
- * it should create a location request with {@link #setQuality} set to
- * {@link #ACCURACY_FINE} or {@link #POWER_HIGH}, and it should set
- * {@link #setInterval} to less than one second. This would be
- * appropriate for mapping applications that are showing your location
- * in real-time.
- *
- * <p>At the other extreme, if you want negligible power
- * impact, but to still receive location updates when available, then use
- * {@link #setQuality} with {@link #POWER_NONE}. With this request your
- * application will not trigger (and therefore will not receive any
- * power blame) any location updates, but will receive locations
- * triggered by other applications. This would be appropriate for
- * applications that have no firm requirement for location, but can
- * take advantage when available.
- *
- * <p>In between these two extremes is a very common use-case, where
- * applications definitely want to receive
- * updates at a specified interval, and can receive them faster when
- * available, but still want a low power impact. These applications
- * should consider {@link #POWER_LOW} combined with a faster
- * {@link #setFastestInterval} (such as 1 minute) and a slower
- * {@link #setInterval} (such as 60 minutes). They will only be assigned
- * power blame for the interval set by {@link #setInterval}, but can
- * still receive locations triggered by other applications at a rate up
- * to {@link #setFastestInterval}. This style of request is appropriate for
- * many location aware applications, including background usage. Do be
- * careful to also throttle {@link #setFastestInterval} if you perform
- * heavy-weight work after receiving an update - such as using the network.
- *
- * <p>Activities should strongly consider removing all location
- * request when entering the background, or
- * at least swap the request to a larger interval and lower quality.
- * Future version of the location manager may automatically perform background
- * throttling on behalf of applications.
- *
- * <p>Applications cannot specify the exact location sources that are
- * used by Android's <em>Fusion Engine</em>. In fact, the system
- * may have multiple location sources (providers) running and may
- * fuse the results from several sources into a single Location object.
- *
- * <p>Location requests from applications with
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will
- * be automatically throttled to a slower interval, and the location
- * object will be obfuscated to only show a coarse level of accuracy.
- *
- * <p>All location requests are considered hints, and you may receive
- * locations that are more accurate, less accurate, and slower
- * than requested.
- *
- * @hide
+ * An encapsulation of various parameters for requesting location via {@link LocationManager}.
*/
-@SystemApi
-@TestApi
public final class LocationRequest implements Parcelable {
+
+ /**
+ * Represents a passive only request. Such a request will not trigger any active locations or
+ * power usage itself, but may receive locations generated in response to other requests.
+ */
+ public static final long PASSIVE_INTERVAL = Long.MAX_VALUE;
+
/**
* Used with {@link #setQuality} to request the most accurate locations available.
*
* <p>This may be up to 1 meter accuracy, although this is implementation dependent.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_FINE = 100;
/**
@@ -111,7 +67,11 @@ public final class LocationRequest implements Parcelable {
* <p>Block level accuracy is considered to be about 100 meter accuracy,
* although this is implementation dependent. Using a coarse accuracy
* such as this often consumes less power.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_BLOCK = 102;
/**
@@ -120,7 +80,11 @@ public final class LocationRequest implements Parcelable {
* <p>City level accuracy is considered to be about 10km accuracy,
* although this is implementation dependent. Using a coarse accuracy
* such as this often consumes less power.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int ACCURACY_CITY = 104;
/**
@@ -129,7 +93,12 @@ public final class LocationRequest implements Parcelable {
* <p>This location request will not trigger any active location requests,
* but will receive locations triggered by other applications. Your application
* will not receive any direct power blame for location work.
+ *
+ * @hide
+ * @deprecated Use {@link #PASSIVE_INTERVAL} instead.
*/
+ @SystemApi
+ @Deprecated
public static final int POWER_NONE = 200;
/**
@@ -137,66 +106,76 @@ public final class LocationRequest implements Parcelable {
*
* <p>This location request will avoid high power location work where
* possible.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int POWER_LOW = 201;
/**
* Used with {@link #setQuality} to allow high power consumption for location.
*
* <p>This location request will allow high power location work.
+ *
+ * @hide
*/
+ @SystemApi
+ @TestApi
public static final int POWER_HIGH = 203;
- private static final long DEFAULT_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
- private static final double FASTEST_INTERVAL_FACTOR = 6.0; // 6x
+ private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
- @UnsupportedAppUsage
- private String mProvider;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ + "LocationManager} methods to provide the provider explicitly.")
+ @Nullable private String mProvider;
private int mQuality;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ + "LocationRequest} instead.")
private long mInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private long mFastestInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private boolean mExplicitFastestInterval;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private long mExpireAt;
- private long mExpireIn;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private int mNumUpdates;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private float mSmallestDisplacement;
- @UnsupportedAppUsage
+ private long mMinUpdateIntervalMillis;
+ private long mExpireAtRealtimeMillis;
+ private long mDurationMillis;
+ private int mMaxUpdates;
+ private float mMinUpdateDistanceMeters;
private boolean mHideFromAppOps;
private boolean mLocationSettingsIgnored;
- private boolean mLowPowerMode;
- @UnsupportedAppUsage
+ private boolean mLowPower;
private @Nullable WorkSource mWorkSource;
/**
- * Create a location request with default parameters.
- *
- * <p>Default parameters are for a low power, slowly updated location.
- * It can then be adjusted as required by the applications before passing
- * to the {@link LocationManager}
- *
- * @return a new location request
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
*/
+ @SystemApi
+ @Deprecated
@NonNull
public static LocationRequest create() {
- return new LocationRequest();
+ // 60 minutes is the default legacy interval
+ return new LocationRequest.Builder(60 * 60 * 1000)
+ .setQuality(POWER_LOW)
+ .build();
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
+ */
@SystemApi
+ @Deprecated
@NonNull
- public static LocationRequest createFromDeprecatedProvider(
- @NonNull String provider, long minTime, float minDistance, boolean singleShot) {
+ public static LocationRequest createFromDeprecatedProvider(@NonNull String provider,
+ long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
Preconditions.checkArgument(provider != null, "invalid null provider");
- if (minTime < 0) minTime = 0;
- if (minDistance < 0) minDistance = 0;
+ if (intervalMillis < 0) {
+ intervalMillis = 0;
+ } else if (intervalMillis == PASSIVE_INTERVAL) {
+ intervalMillis = Long.MAX_VALUE - 1;
+ }
+ if (minUpdateDistanceMeters < 0) {
+ minUpdateDistanceMeters = 0;
+ }
int quality;
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
@@ -207,512 +186,484 @@ public final class LocationRequest implements Parcelable {
quality = POWER_LOW;
}
- LocationRequest request = new LocationRequest()
+ return new LocationRequest.Builder(intervalMillis)
+ .setMinUpdateIntervalMillis(intervalMillis)
+ .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
+ .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
+ .build()
.setProvider(provider)
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
- if (singleShot) request.setNumUpdates(1);
- return request;
+ .setQuality(quality);
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use the Builder to construct new LocationRequests.
+ */
@SystemApi
+ @Deprecated
@NonNull
- public static LocationRequest createFromDeprecatedCriteria(
- @NonNull Criteria criteria, long minTime, float minDistance, boolean singleShot) {
+ public static LocationRequest createFromDeprecatedCriteria(@NonNull Criteria criteria,
+ long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
Preconditions.checkArgument(criteria != null, "invalid null criteria");
- if (minTime < 0) minTime = 0;
- if (minDistance < 0) minDistance = 0;
-
- int quality;
- switch (criteria.getAccuracy()) {
- case Criteria.ACCURACY_COARSE:
- quality = ACCURACY_BLOCK;
- break;
- case Criteria.ACCURACY_FINE:
- quality = ACCURACY_FINE;
- break;
- default: {
- if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
- quality = POWER_HIGH;
- } else {
- quality = POWER_LOW;
- }
- }
+ if (intervalMillis < 0) {
+ intervalMillis = 0;
+ } else if (intervalMillis == PASSIVE_INTERVAL) {
+ intervalMillis = Long.MAX_VALUE - 1;
+ }
+ if (minUpdateDistanceMeters < 0) {
+ minUpdateDistanceMeters = 0;
}
- LocationRequest request = new LocationRequest()
- .setQuality(quality)
- .setInterval(minTime)
- .setFastestInterval(minTime)
- .setSmallestDisplacement(minDistance);
- if (singleShot) request.setNumUpdates(1);
- return request;
- }
-
- /** @hide */
- public LocationRequest() {
- this(
- /* provider= */ LocationManager.FUSED_PROVIDER,
- /* quality= */ POWER_LOW,
- /* interval= */ DEFAULT_INTERVAL_MS,
- /* fastestInterval= */ (long) (DEFAULT_INTERVAL_MS / FASTEST_INTERVAL_FACTOR),
- /* explicitFastestInterval= */ false,
- /* expireAt= */ Long.MAX_VALUE,
- /* expireIn= */ Long.MAX_VALUE,
- /* numUpdates= */ Integer.MAX_VALUE,
- /* smallestDisplacement= */ 0,
- /* hideFromAppOps= */ false,
- /* locationSettingsIgnored= */ false,
- /* lowPowerMode= */ false,
- /* workSource= */ null);
- }
-
- /** @hide */
- public LocationRequest(LocationRequest src) {
- this(
- src.mProvider,
- src.mQuality,
- src.mInterval,
- src.mFastestInterval,
- src.mExplicitFastestInterval,
- src.mExpireAt,
- src.mExpireIn,
- src.mNumUpdates,
- src.mSmallestDisplacement,
- src.mHideFromAppOps,
- src.mLocationSettingsIgnored,
- src.mLowPowerMode,
- src.mWorkSource);
+ return new LocationRequest.Builder(intervalMillis)
+ .setQuality(criteria)
+ .setMinUpdateIntervalMillis(intervalMillis)
+ .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
+ .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
+ .build();
}
private LocationRequest(
- @NonNull String provider,
+ @Nullable String provider,
+ long intervalMillis,
int quality,
- long intervalMs,
- long fastestIntervalMs,
- boolean explicitFastestInterval,
- long expireAt,
- long expireInMs,
- int numUpdates,
- float smallestDisplacementM,
- boolean hideFromAppOps,
+ long expireAtRealtimeMillis,
+ long durationMillis,
+ int maxUpdates,
+ long minUpdateIntervalMillis,
+ float minUpdateDistanceMeters,
+ boolean hiddenFromAppOps,
boolean locationSettingsIgnored,
- boolean lowPowerMode,
- WorkSource workSource) {
- Preconditions.checkArgument(provider != null, "invalid provider: null");
- checkQuality(quality);
+ boolean lowPower,
+ @Nullable WorkSource workSource) {
+ Preconditions.checkArgument(intervalMillis != PASSIVE_INTERVAL || quality == POWER_NONE);
+ Preconditions.checkArgument(minUpdateIntervalMillis <= intervalMillis);
mProvider = provider;
+ mInterval = intervalMillis;
mQuality = quality;
- mInterval = intervalMs;
- mFastestInterval = fastestIntervalMs;
- mExplicitFastestInterval = explicitFastestInterval;
- mExpireAt = expireAt;
- mExpireIn = expireInMs;
- mNumUpdates = numUpdates;
- mSmallestDisplacement = Preconditions.checkArgumentInRange(smallestDisplacementM, 0,
- Float.MAX_VALUE, "smallestDisplacementM");
- mHideFromAppOps = hideFromAppOps;
- mLowPowerMode = lowPowerMode;
+ mMinUpdateIntervalMillis = minUpdateIntervalMillis;
+ mExpireAtRealtimeMillis = expireAtRealtimeMillis;
+ mDurationMillis = durationMillis;
+ mMaxUpdates = maxUpdates;
+ mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+ mHideFromAppOps = hiddenFromAppOps;
+ mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
mWorkSource = workSource;
}
/**
- * Set the quality of the request.
- *
- * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
- * constant such as {@link #POWER_LOW}. You cannot request both accuracy and
- * power, only one or the other can be specified. The system will then
- * maximize accuracy or minimize power as appropriate.
- *
- * <p>The quality of the request is a strong hint to the system for which
- * location sources to use. For example, {@link #ACCURACY_FINE} is more likely
- * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower
- * positioning, but it also depends on many other factors (such as which sources
- * are available) and is implementation dependent.
- *
- * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
- * on a location request.
- *
- * @param quality an accuracy or power constant
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the quality constant is not valid
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setQuality(int quality) {
- checkQuality(quality);
- mQuality = quality;
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setProvider(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null);
+ mProvider = provider;
return this;
}
/**
- * Get the quality of the request.
- *
- * @return an accuracy or power constant
+ * @hide
+ * @deprecated Providers are no longer an explicit part of a location request.
*/
- public int getQuality() {
- return mQuality;
+ @SystemApi
+ @Deprecated
+ public @NonNull String getProvider() {
+ return mProvider != null ? mProvider : LocationManager.FUSED_PROVIDER;
}
/**
- * Set the desired interval for active location updates, in milliseconds.
- *
- * <p>The location manager will actively try to obtain location updates
- * for your application at this interval, so it has a
- * direct influence on the amount of power used by your application.
- * Choose your interval wisely.
- *
- * <p>This interval is inexact. You may not receive updates at all (if
- * no location sources are available), or you may receive them
- * slower than requested. You may also receive them faster than
- * requested (if other applications are requesting location at a
- * faster interval). The fastest rate that you will receive
- * updates can be controlled with {@link #setFastestInterval}.
- *
- * <p>Applications with only the coarse location permission may have their
- * interval silently throttled.
- *
- * <p>An interval of 0 is allowed, but not recommended, since
- * location updates may be extremely fast on future implementations.
- *
- * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
- * on a location request.
- *
- * @param millis desired interval in millisecond, inexact
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the interval is less than zero
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setInterval(long millis) {
- Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
- mInterval = millis;
- if (!mExplicitFastestInterval) {
- mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
- }
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setQuality(int quality) {
+ mQuality = Builder.checkQuality(quality, true);
return this;
}
/**
- * Get the desired interval of this request, in milliseconds.
+ * Returns the quality of the location request.
+ *
+ * @return the quality of the location request
*
- * @return desired interval in milliseconds, inexact
+ * @hide
*/
- public long getInterval() {
- return mInterval;
+ @SystemApi
+ public int getQuality() {
+ if (mInterval == PASSIVE_INTERVAL) {
+ return POWER_NONE;
+ } else {
+ return mQuality;
+ }
}
-
/**
- * Requests the GNSS chipset to run in a low power mode and make strong tradeoffs to
- * substantially restrict power.
- *
- * <p>In this mode, the GNSS chipset will not, on average, run power hungry operations like RF &
- * signal searches for more than one second per interval (specified by
- * {@link #setInterval(long)}).
- *
- * @param enabled Enable or disable low power mode
- * @return the same object, so that setters can be chained
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
- public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
- mLowPowerMode = enabled;
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setInterval(long millis) {
+ Preconditions.checkArgument(millis >= 0);
+
+ // legacy clients don't know about the passive interval
+ if (millis == PASSIVE_INTERVAL) {
+ millis = Long.MAX_VALUE - 1;
+ }
+
+ mInterval = millis;
+ if (mMinUpdateIntervalMillis > mInterval) {
+ mMinUpdateIntervalMillis = mInterval;
+ }
return this;
}
/**
- * Returns true if low power mode is enabled.
+ * @hide
+ * @deprecated Use {@link #getIntervalMillis()} instead.
*/
- public boolean isLowPowerMode() {
- return mLowPowerMode;
+ @SystemApi
+ @Deprecated
+ public long getInterval() {
+ return getIntervalMillis();
}
/**
- * Requests that user location settings be ignored in order to satisfy this request. This API
- * is only for use in extremely rare scenarios where it is appropriate to ignore user location
- * settings, such as a user initiated emergency (dialing 911 for instance).
+ * Returns the desired interval of location updates, or {@link #PASSIVE_INTERVAL} if this is a
+ * passive, no power request. A passive request will not actively generate location updates
+ * (and thus will not be power blamed for location), but may receive location updates generated
+ * as a result of other location requests. A passive request must always have an explicit
+ * minimum update interval set.
*
- * @param locationSettingsIgnored Whether to ignore location settings
- * @return the same object, so that setters can be chained
- */
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
- mLocationSettingsIgnored = locationSettingsIgnored;
- return this;
- }
-
- /**
- * Returns true if location settings will be ignored in order to satisfy this request.
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #getMinUpdateIntervalMillis()} for the behavior in that case.
+ *
+ * @return the desired interval of location updates
*/
- public boolean isLocationSettingsIgnored() {
- return mLocationSettingsIgnored;
+ public long getIntervalMillis() {
+ return mInterval;
}
/**
- * Explicitly set the fastest interval for location updates, in
- * milliseconds.
- *
- * <p>This controls the fastest rate at which your application will
- * receive location updates, which might be faster than
- * {@link #setInterval} in some situations (for example, if other
- * applications are triggering location updates).
- *
- * <p>This allows your application to passively acquire locations
- * at a rate faster than it actively acquires locations, saving power.
- *
- * <p>Unlike {@link #setInterval}, this parameter is exact. Your
- * application will never receive updates faster than this value.
- *
- * <p>If you don't call this method, a fastest interval
- * will be selected for you. It will be a value faster than your
- * active interval ({@link #setInterval}).
- *
- * <p>An interval of 0 is allowed, but not recommended, since
- * location updates may be extremely fast on future implementations.
- *
- * <p>If the fastest interval set is slower than {@link #setInterval},
- * then your effective fastest interval is {@link #setInterval}.
- *
- * @param millis fastest interval for updates in milliseconds
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if the interval is less than zero
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setFastestInterval(long millis) {
- Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
- mExplicitFastestInterval = true;
- mFastestInterval = millis;
+ Preconditions.checkArgument(millis >= 0);
+ mMinUpdateIntervalMillis = millis;
return this;
}
/**
- * Get the fastest interval of this request in milliseconds. The system will never provide
- * location updates faster than the minimum of the fastest interval and {@link #getInterval}.
- *
- * @return fastest interval in milliseconds
+ * @hide
+ * @deprecated Use {@link #getMinUpdateIntervalMillis()} instead.
*/
+ @SystemApi
+ @Deprecated
public long getFastestInterval() {
- return mFastestInterval;
+ return getMinUpdateIntervalMillis();
}
/**
- * Set the expiration time of this request in milliseconds of realtime since boot. Values in the
- * past are allowed, but indicate that the request has already expired. The location manager
- * will automatically stop updates after the request expires.
- *
- * @param millis expiration time of request in milliseconds since boot
- * @return the same object, so that setters can be chained
- * @see SystemClock#elapsedRealtime()
- * @deprecated Prefer {@link #setExpireIn(long)}.
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
@Deprecated
public @NonNull LocationRequest setExpireAt(long millis) {
- mExpireAt = Math.max(millis, 0);
+ mExpireAtRealtimeMillis = max(millis, 0);
return this;
}
/**
- * Get the request expiration time in milliseconds of realtime since boot.
- *
- * @return request expiration time in milliseconds since boot
- * @see SystemClock#elapsedRealtime()
- * @deprecated Prefer {@link #getExpireIn()}.
+ * @hide
+ * @deprecated Prefer {@link #getDurationMillis()} where possible.
*/
+ @SystemApi
@Deprecated
public long getExpireAt() {
- return mExpireAt;
+ return mExpireAtRealtimeMillis;
}
/**
- * Set the duration of this request in milliseconds of realtime. Values less than 0 are allowed,
- * but indicate that the request has already expired. The location manager will automatically
- * stop updates after the request expires.
- *
- * @param millis duration of request in milliseconds
- * @return the same object, so that setters can be chained
- * @see SystemClock#elapsedRealtime()
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setExpireIn(long millis) {
- mExpireIn = millis;
+ mDurationMillis = millis;
return this;
}
/**
- * Get the request expiration duration in milliseconds of realtime.
- *
- * @return request expiration duration in milliseconds
- * @see SystemClock#elapsedRealtime()
+ * @hide
+ * @deprecated Use {@link #getDurationMillis()} instead.
*/
+ @SystemApi
+ @Deprecated
public long getExpireIn() {
- return mExpireIn;
+ return getDurationMillis();
}
/**
- * Returns the realtime at which this request expires, taking into account both
- * {@link #setExpireAt(long)} and {@link #setExpireIn(long)} relative to the given realtime.
+ * Returns the duration for which location will be provided before the request is automatically
+ * removed. A duration of <code>Long.MAX_VALUE</code> represents an unlimited duration.
*
+ * @return the duration for which location will be provided
+ */
+ public long getDurationMillis() {
+ return mDurationMillis;
+ }
+
+ /**
* @hide
*/
public long getExpirationRealtimeMs(long startRealtimeMs) {
long expirationRealtimeMs;
// Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
- if (mExpireIn > Long.MAX_VALUE - startRealtimeMs) {
+ if (mDurationMillis > Long.MAX_VALUE - startRealtimeMs) {
expirationRealtimeMs = Long.MAX_VALUE;
} else {
- expirationRealtimeMs = startRealtimeMs + mExpireIn;
+ expirationRealtimeMs = startRealtimeMs + mDurationMillis;
}
- return Math.min(expirationRealtimeMs, mExpireAt);
+ return min(expirationRealtimeMs, mExpireAtRealtimeMillis);
}
/**
- * Set the number of location updates.
- *
- * <p>By default locations are continuously updated until the request is explicitly
- * removed, however you can optionally request a set number of updates.
- * For example, if your application only needs a single fresh location,
- * then call this method with a value of 1 before passing the request
- * to the location manager.
- *
- * @param numUpdates the number of location updates requested
- * @return the same object, so that setters can be chained
- * @throws IllegalArgumentException if numUpdates is 0 or less
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
*/
+ @SystemApi
+ @Deprecated
public @NonNull LocationRequest setNumUpdates(int numUpdates) {
if (numUpdates <= 0) {
throw new IllegalArgumentException(
"invalid numUpdates: " + numUpdates);
}
- mNumUpdates = numUpdates;
+ mMaxUpdates = numUpdates;
return this;
}
/**
- * Get the number of updates requested.
- *
- * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
- * locations are updated until the request is explicitly removed.
- *
- * @return number of updates
+ * @hide
+ * @deprecated Use {@link #getMaxUpdates()} instead.
*/
+ @SystemApi
+ @Deprecated
public int getNumUpdates() {
- return mNumUpdates;
+ return getMaxUpdates();
}
- /** @hide */
- public void decrementNumUpdates() {
- if (mNumUpdates != Integer.MAX_VALUE) {
- mNumUpdates--;
- }
- if (mNumUpdates < 0) {
- mNumUpdates = 0;
+ /**
+ * Returns the maximum number of location updates for this request before the request is
+ * automatically removed. A max updates value of <code>Integer.MAX_VALUE</code> represents an
+ * unlimited number of updates.
+ */
+ public int getMaxUpdates() {
+ return mMaxUpdates;
+ }
+
+ /**
+ * Returns the minimum update interval. If location updates are available faster than the
+ * request interval then locations will only be delivered if the minimum update interval has
+ * expired since the last location update.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * @return the minimum update interval
+ */
+ public long getMinUpdateIntervalMillis() {
+ if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
+ return mInterval;
+ } else {
+ // the min is only necessary in case someone use a deprecated function to mess with the
+ // interval or min update interval
+ return min(mMinUpdateIntervalMillis, mInterval);
}
}
- /** Sets the provider to use for this location request. */
- public @NonNull LocationRequest setProvider(@NonNull String provider) {
- Preconditions.checkArgument(provider != null, "invalid provider: null");
- mProvider = provider;
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setSmallestDisplacement(float minDisplacementMeters) {
+ mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minDisplacementMeters, 0,
+ Float.MAX_VALUE, "minDisplacementMeters");
return this;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use {@link #getMinUpdateDistanceMeters()} instead.
+ */
@SystemApi
- public @NonNull String getProvider() {
- return mProvider;
+ @Deprecated
+ public float getSmallestDisplacement() {
+ return getMinUpdateDistanceMeters();
+ }
+
+ /**
+ * Returns the minimum distance between location updates. If a potential location update is
+ * closer to the last location update than the minimum update distance, then the potential
+ * location update will not occur. A value of 0 meters implies that no location update will ever
+ * be rejected due to failing this constraint.
+ *
+ * @return the minimum distance between location updates
+ */
+ public float getMinUpdateDistanceMeters() {
+ return mMinUpdateDistanceMeters;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public @NonNull LocationRequest setSmallestDisplacement(float smallestDisplacementM) {
- mSmallestDisplacement = Preconditions.checkArgumentInRange(smallestDisplacementM, 0,
- Float.MAX_VALUE, "smallestDisplacementM");
- return this;
+ @Deprecated
+ public void setHideFromAppOps(boolean hiddenFromAppOps) {
+ mHideFromAppOps = hiddenFromAppOps;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated Use {@link #isHiddenFromAppOps()} instead.
+ */
@SystemApi
- public float getSmallestDisplacement() {
- return mSmallestDisplacement;
+ @Deprecated
+ public boolean getHideFromAppOps() {
+ return isHiddenFromAppOps();
}
/**
- * Sets the WorkSource to use for power blaming of this location request.
+ * Returns true if this request should be ignored while updating app ops with location usage.
+ * This implies that someone else (usually the creator of the location request) is responsible
+ * for updating app ops.
*
- * <p>No permissions are required to make this call, however the LocationManager
- * will throw a SecurityException when requesting location updates if the caller
- * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
+ * @return true if this request should be ignored while updating app ops with location usage
*
- * @param workSource WorkSource defining power blame for this location request.
* @hide
*/
+ @TestApi
@SystemApi
- public void setWorkSource(@Nullable WorkSource workSource) {
- mWorkSource = workSource;
+ public boolean isHiddenFromAppOps() {
+ return mHideFromAppOps;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public @Nullable WorkSource getWorkSource() {
- return mWorkSource;
+ @Deprecated
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+ mLocationSettingsIgnored = locationSettingsIgnored;
+ return this;
}
/**
- * Sets whether or not this location request should be hidden from AppOps.
+ * Returns true if location settings, throttling, background location limits, and any other
+ * possible limiting factors will be ignored in order to satisfy this request.
+ *
+ * @return true if all limiting factors will be ignored to satisfy this request
*
- * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
- * request's existence. It does not affect power blaming in the Battery page.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public boolean isLocationSettingsIgnored() {
+ return mLocationSettingsIgnored;
+ }
+
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
+ mLowPower = enabled;
+ return this;
+ }
+
+ /**
+ * @hide
+ * @deprecated Use {@link #isLowPower()} instead.
+ */
+ @Deprecated
+ @SystemApi
+ public boolean isLowPowerMode() {
+ return isLowPower();
+ }
+
+ /**
+ * Returns true if extreme trade-offs should be made to save power for this request. This
+ * usually involves specialized hardware modes which can greatly affect the quality of
+ * locations.
*
- * <p>No permissions are required to make this call, however the LocationManager
- * will throw a SecurityException when requesting location updates if the caller
- * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
+ * @return true if extreme trade-offs should be made to save power for this request
*
- * @param hideFromAppOps If true AppOps won't keep track of this location request.
* @hide
- * @see android.app.AppOpsManager
*/
+ @TestApi
@SystemApi
- public void setHideFromAppOps(boolean hideFromAppOps) {
- mHideFromAppOps = hideFromAppOps;
+ public boolean isLowPower() {
+ return mLowPower;
}
- /** @hide */
+ /**
+ * @hide
+ * @deprecated LocationRequests should be treated as immutable.
+ */
@SystemApi
- public boolean getHideFromAppOps() {
- return mHideFromAppOps;
+ @Deprecated
+ public void setWorkSource(@Nullable WorkSource workSource) {
+ mWorkSource = workSource;
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private static void checkQuality(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- case ACCURACY_BLOCK:
- case ACCURACY_CITY:
- case POWER_NONE:
- case POWER_LOW:
- case POWER_HIGH:
- break;
- default:
- throw new IllegalArgumentException("invalid quality: " + quality);
- }
+ /**
+ * Returns the work source used for power blame for this request. If null, the system is free to
+ * assign power blame as it deems most appropriate.
+ *
+ * @return the work source used for power blame for this request
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public @Nullable WorkSource getWorkSource() {
+ return mWorkSource;
}
+
public static final @NonNull Parcelable.Creator<LocationRequest> CREATOR =
new Parcelable.Creator<LocationRequest>() {
@Override
public LocationRequest createFromParcel(Parcel in) {
return new LocationRequest(
/* provider= */ in.readString(),
+ /* intervalMillis= */ in.readLong(),
/* quality= */ in.readInt(),
- /* interval= */ in.readLong(),
- /* fastestInterval= */ in.readLong(),
- /* explicitFastestInterval= */ in.readBoolean(),
- /* expireAt= */ in.readLong(),
- /* expireIn= */ in.readLong(),
- /* numUpdates= */ in.readInt(),
- /* smallestDisplacement= */ in.readFloat(),
- /* hideFromAppOps= */ in.readBoolean(),
+ /* expireAtRealtimeMillis= */ in.readLong(),
+ /* durationMillis= */ in.readLong(),
+ /* maxUpdates= */ in.readInt(),
+ /* minUpdateIntervalMillis= */ in.readLong(),
+ /* minUpdateDistanceMeters= */ in.readFloat(),
+ /* hiddenFromAppOps= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
- /* lowPowerMode= */ in.readBoolean(),
+ /* lowPower= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
}
@@ -728,42 +679,21 @@ public final class LocationRequest implements Parcelable {
}
@Override
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeString(mProvider);
- parcel.writeInt(mQuality);
parcel.writeLong(mInterval);
- parcel.writeLong(mFastestInterval);
- parcel.writeBoolean(mExplicitFastestInterval);
- parcel.writeLong(mExpireAt);
- parcel.writeLong(mExpireIn);
- parcel.writeInt(mNumUpdates);
- parcel.writeFloat(mSmallestDisplacement);
+ parcel.writeInt(mQuality);
+ parcel.writeLong(mExpireAtRealtimeMillis);
+ parcel.writeLong(mDurationMillis);
+ parcel.writeInt(mMaxUpdates);
+ parcel.writeLong(mMinUpdateIntervalMillis);
+ parcel.writeFloat(mMinUpdateDistanceMeters);
parcel.writeBoolean(mHideFromAppOps);
parcel.writeBoolean(mLocationSettingsIgnored);
- parcel.writeBoolean(mLowPowerMode);
+ parcel.writeBoolean(mLowPower);
parcel.writeTypedObject(mWorkSource, 0);
}
- /** @hide */
- public static String qualityToString(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- return "ACCURACY_FINE";
- case ACCURACY_BLOCK:
- return "ACCURACY_BLOCK";
- case ACCURACY_CITY:
- return "ACCURACY_CITY";
- case POWER_NONE:
- return "POWER_NONE";
- case POWER_LOW:
- return "POWER_LOW";
- case POWER_HIGH:
- return "POWER_HIGH";
- default:
- return "???";
- }
- }
-
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -774,18 +704,17 @@ public final class LocationRequest implements Parcelable {
}
LocationRequest that = (LocationRequest) o;
- return mQuality == that.mQuality
- && mInterval == that.mInterval
- && mFastestInterval == that.mFastestInterval
- && mExplicitFastestInterval == that.mExplicitFastestInterval
- && mExpireAt == that.mExpireAt
- && mExpireIn == that.mExpireIn
- && mNumUpdates == that.mNumUpdates
- && Float.compare(that.mSmallestDisplacement, mSmallestDisplacement) == 0
+ return mInterval == that.mInterval
+ && mQuality == that.mQuality
+ && mExpireAtRealtimeMillis == that.mExpireAtRealtimeMillis
+ && mDurationMillis == that.mDurationMillis
+ && mMaxUpdates == that.mMaxUpdates
+ && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
+ && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
&& mHideFromAppOps == that.mHideFromAppOps
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
- && mLowPowerMode == that.mLowPowerMode
- && mProvider.equals(that.mProvider)
+ && mLowPower == that.mLowPower
+ && Objects.equals(mProvider, that.mProvider)
&& Objects.equals(mWorkSource, that.mWorkSource);
}
@@ -799,33 +728,371 @@ public final class LocationRequest implements Parcelable {
public String toString() {
StringBuilder s = new StringBuilder();
s.append("Request[");
- s.append(qualityToString(mQuality));
- s.append(" ").append(mProvider);
- if (mQuality != POWER_NONE) {
- s.append(" interval=");
+ if (mProvider != null) {
+ s.append(mProvider).append(" ");
+ }
+ if (mQuality != POWER_NONE && mQuality != ACCURACY_BLOCK) {
+ s.append(qualityToString(mQuality)).append(" ");
+ }
+ if (mInterval != PASSIVE_INTERVAL) {
+ s.append("interval=");
TimeUtils.formatDuration(mInterval, s);
- if (mExplicitFastestInterval && mFastestInterval != mInterval) {
- s.append(" fastestInterval=");
- TimeUtils.formatDuration(mFastestInterval, s);
- }
+ } else {
+ s.append("PASSIVE");
+ }
+ if (mExpireAtRealtimeMillis != Long.MAX_VALUE) {
+ s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
}
- if (mExpireAt != Long.MAX_VALUE) {
- s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAt));
+ if (mDurationMillis != Long.MAX_VALUE) {
+ s.append(" duration=");
+ TimeUtils.formatDuration(mDurationMillis, s);
}
- if (mExpireIn != Long.MAX_VALUE) {
- s.append(" expireIn=");
- TimeUtils.formatDuration(mExpireIn, s);
+ if (mMaxUpdates != Integer.MAX_VALUE) {
+ s.append(" maxUpdates=").append(mMaxUpdates);
}
- if (mNumUpdates != Integer.MAX_VALUE) {
- s.append(" num=").append(mNumUpdates);
+ if (mMinUpdateIntervalMillis < mInterval) {
+ s.append(" minUpdateInterval=");
+ TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
}
- if (mLowPowerMode) {
- s.append(" lowPowerMode");
+ if (mMinUpdateDistanceMeters > 0.0) {
+ s.append(" minUpdateDistance=").append(mMinUpdateDistanceMeters);
+ }
+ if (mLowPower) {
+ s.append(" lowPower");
+ }
+ if (mHideFromAppOps) {
+ s.append(" hiddenFromAppOps");
}
if (mLocationSettingsIgnored) {
s.append(" locationSettingsIgnored");
}
+ if (mWorkSource != null) {
+ s.append(" ").append(mWorkSource);
+ }
s.append(']');
return s.toString();
}
+
+ private static String qualityToString(int quality) {
+ switch (quality) {
+ case ACCURACY_FINE:
+ return "ACCURACY_FINE";
+ case ACCURACY_BLOCK:
+ return "ACCURACY_BLOCK";
+ case ACCURACY_CITY:
+ return "ACCURACY_CITY";
+ case POWER_NONE:
+ return "POWER_NONE";
+ case POWER_LOW:
+ return "POWER_LOW";
+ case POWER_HIGH:
+ return "POWER_HIGH";
+ default:
+ return "???";
+ }
+ }
+
+ /**
+ * A builder class for {@link LocationRequest}.
+ */
+ public static final class Builder {
+
+ private static int checkQuality(int quality, boolean allowDeprecated) {
+ switch (quality) {
+ case ACCURACY_FINE:
+ // fall through
+ case ACCURACY_BLOCK:
+ // fall through
+ case ACCURACY_CITY:
+ // fall through
+ case POWER_LOW:
+ // fall through
+ case POWER_HIGH:
+ return quality;
+ case POWER_NONE:
+ if (allowDeprecated) {
+ return quality;
+ }
+ // fall through
+ default:
+ throw new IllegalArgumentException("invalid quality: " + quality);
+ }
+ }
+
+ private long mIntervalMillis;
+ private int mQuality;
+ private long mDurationMillis;
+ private int mMaxUpdates;
+ private long mMinUpdateIntervalMillis;
+ private float mMinUpdateDistanceMeters;
+ private boolean mHiddenFromAppOps;
+ private boolean mLocationSettingsIgnored;
+ private boolean mLowPower;
+ @Nullable private WorkSource mWorkSource;
+
+ /**
+ * Creates a new Builder with the given interval. See {@link #setIntervalMillis(long)} for
+ * more information on the interval.
+ */
+ public Builder(long intervalMillis) {
+ // gives us a range check
+ setIntervalMillis(intervalMillis);
+
+ mQuality = ACCURACY_BLOCK;
+ mDurationMillis = Long.MAX_VALUE;
+ mMaxUpdates = Integer.MAX_VALUE;
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ mMinUpdateDistanceMeters = 0;
+ mHiddenFromAppOps = false;
+ mLocationSettingsIgnored = false;
+ mLowPower = false;
+ mWorkSource = null;
+ }
+
+ /**
+ * Creates a new Builder with all parameters copied from the given location request.
+ */
+ public Builder(@NonNull LocationRequest locationRequest) {
+ mIntervalMillis = locationRequest.mInterval;
+ mQuality = locationRequest.mQuality;
+ mDurationMillis = locationRequest.mDurationMillis;
+ mMaxUpdates = locationRequest.mMaxUpdates;
+ mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
+ mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
+ mHiddenFromAppOps = locationRequest.mHideFromAppOps;
+ mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
+ mLowPower = locationRequest.mLowPower;
+ mWorkSource = locationRequest.mWorkSource;
+
+ // handle edge cases that can only happen with location request that has been modified
+ // by deprecated SystemApi methods
+ if (mQuality == POWER_NONE) {
+ mIntervalMillis = PASSIVE_INTERVAL;
+ }
+ if (mIntervalMillis == PASSIVE_INTERVAL
+ && mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
+ // this is the legacy default minimum update interval, so if we're forced to
+ // change the value, at least this should be unsuprising to legacy clients (which
+ // should be the only clients capable of getting in this weird state).
+ mMinUpdateIntervalMillis = 10 * 60 * 1000;
+ }
+ }
+
+ /**
+ * Sets the request interval. The request interval may be set to {@link #PASSIVE_INTERVAL}
+ * which indicates this request will not actively generate location updates (and thus will
+ * not be power blamed for location), but may receive location updates generated as a result
+ * of other location requests. A passive request must always have an explicit minimum
+ * update interval set.
+ *
+ * <p>Locations may be available at a faster interval than specified here, see
+ * {@link #setMinUpdateIntervalMillis(long)} for the behavior in that case.
+ */
+ public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) {
+ mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long.MAX_VALUE,
+ "intervalMillis");
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setQuality(int quality) {
+ mQuality = checkQuality(quality, false);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public @NonNull Builder setQuality(@NonNull Criteria criteria) {
+ switch (criteria.getAccuracy()) {
+ case Criteria.ACCURACY_COARSE:
+ mQuality = ACCURACY_BLOCK;
+ break;
+ case Criteria.ACCURACY_FINE:
+ mQuality = ACCURACY_FINE;
+ break;
+ default: {
+ if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
+ mQuality = POWER_HIGH;
+ } else {
+ mQuality = POWER_LOW;
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Sets the duration this request will continue before being automatically removed. Defaults
+ * to <code>Long.MAX_VALUE</code>, which represents an unlimited duration.
+ */
+ public @NonNull Builder setDurationMillis(@IntRange(from = 1) long durationMillis) {
+ mDurationMillis = Preconditions.checkArgumentInRange(durationMillis, 1, Long.MAX_VALUE,
+ "durationMillis");
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of location updates for this request before this request is
+ * automatically removed. Defaults to <code>Integer.MAX_VALUE</code>, which represents an
+ * unlimited number of updates.
+ */
+ public @NonNull Builder setMaxUpdates(
+ @IntRange(from = 1, to = Integer.MAX_VALUE) int maxUpdates) {
+ mMaxUpdates = Preconditions.checkArgumentInRange(maxUpdates, 1, Integer.MAX_VALUE,
+ "maxUpdates");
+ return this;
+ }
+
+ /**
+ * Sets an explicit minimum update interval. If location updates are available faster than
+ * the request interval then locations will only be delivered if the minimum update interval
+ * has expired since the last location update. Defaults to no explicit minimum update
+ * interval set, which means the minimum update interval is the same as the interval.
+ *
+ * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
+ * minimum update interval, so you need not worry about updates blocked simply because they
+ * arrived a fraction of a second earlier than expected.
+ *
+ * <p class="note"><strong>Note:</strong> When {@link #build()} is invoked, the minimum of
+ * the interval and the minimum update interval will be used as the minimum update interval
+ * of the built request.
+ */
+ public @NonNull Builder setMinUpdateIntervalMillis(
+ @IntRange(from = 0) long minUpdateIntervalMillis) {
+ mMinUpdateIntervalMillis = Preconditions.checkArgumentInRange(minUpdateIntervalMillis,
+ 0, Long.MAX_VALUE, "minUpdateIntervalMillis");
+ return this;
+ }
+
+ /**
+ * Clears an explicitly set minimum update interval and reverts to an implicit minimum
+ * update interval which is the same as the interval.
+ */
+ public @NonNull Builder clearMinUpdateIntervalMillis() {
+ mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
+ return this;
+ }
+
+ /**
+ * Sets the minimum update distance between delivered locations. If a potential location
+ * update is closer to the last delivered location than the minimum update distance, then
+ * the potential location update will not occur. Defaults to 0, which represents no minimum
+ * update distance.
+ */
+ public @NonNull Builder setMinUpdateDistanceMeters(
+ @FloatRange(from = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters) {
+ mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minUpdateDistanceMeters,
+ 0, Float.MAX_VALUE, "minUpdateDistanceMeters");
+ return this;
+ }
+
+ /**
+ * If set to true, indicates that app ops should not be updated with location usage due to
+ * this request. This implies that someone else (usually the creator of the location
+ * request) is responsible for updating app ops as appropriate. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS)
+ public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) {
+ mHiddenFromAppOps = hiddenFromAppOps;
+ return this;
+ }
+
+ /**
+ * If set to true, indicates that location settings, throttling, background location limits,
+ * and any other possible limiting factors should be ignored in order to satisfy this
+ * request. This is only intended for use in user initiated emergency situations, and
+ * should be used extremely cautiously. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+ mLocationSettingsIgnored = locationSettingsIgnored;
+ return this;
+ }
+
+ /**
+ * It set to true, indicates that extreme trade-offs should be made if possible to save
+ * power for this request. This usually involves specialized hardware modes which can
+ * greatly affect the quality of locations. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public @NonNull Builder setLowPower(boolean lowPower) {
+ mLowPower = lowPower;
+ return this;
+ }
+
+ /**
+ * Sets the work source to use for power blame for this location request. Defaults to null,
+ * which implies the system is free to assign power blame as it determines best for this
+ * request (which usually means blaming the owner of the location listener).
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
+ public @NonNull Builder setWorkSource(@Nullable WorkSource workSource) {
+ mWorkSource = workSource;
+ return this;
+ }
+
+ /**
+ * Builds a location request from this builder. If an explicit minimum update interval is
+ * set, the minimum update interval of the location request will be the minimum of the
+ * interval and minimum update interval.
+ *
+ * <p>If building a passive request then you must have set an explicit minimum update
+ * interval.
+ *
+ * @throws IllegalStateException if building a passive request with no explicit minimum
+ * update interval set
+ * @return a new location request
+ */
+ public @NonNull LocationRequest build() {
+ Preconditions.checkState(mIntervalMillis != PASSIVE_INTERVAL
+ || mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL,
+ "passive location requests must have an explicit minimum update interval");
+
+ return new LocationRequest(
+ null,
+ mIntervalMillis,
+ mIntervalMillis != PASSIVE_INTERVAL ? mQuality : POWER_NONE,
+ Long.MAX_VALUE,
+ mDurationMillis,
+ mMaxUpdates,
+ min(mMinUpdateIntervalMillis, mIntervalMillis),
+ mMinUpdateDistanceMeters,
+ mHiddenFromAppOps,
+ mLocationSettingsIgnored,
+ mLowPower,
+ mWorkSource);
+ }
+ }
}
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
index 2511c39caf5c..92e05ef68e3b 100644
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
@@ -82,25 +82,21 @@ public final class LocationRequestUnbundled {
}
/**
- * Get the desired interval of this request, in milliseconds.
+ * Get the location update interval.
*
- * @return desired interval in milliseconds, inexact
+ * @return location update interval
*/
public long getInterval() {
- return delegate.getInterval();
+ return delegate.getIntervalMillis();
}
/**
- * Get the fastest interval of this request, in milliseconds.
+ * Get the minimum delivery interval.
*
- * <p>The system will never provide location updates faster
- * than the minimum of {@link #getFastestInterval} and
- * {@link #getInterval}.
- *
- * @return fastest interval in milliseconds, exact
+ * @return minimum delivery interval
*/
public long getFastestInterval() {
- return delegate.getFastestInterval();
+ return delegate.getMinUpdateIntervalMillis();
}
/**
@@ -118,7 +114,7 @@ public final class LocationRequestUnbundled {
* @return minimum distance between location updates in meters
*/
public float getSmallestDisplacement() {
- return delegate.getSmallestDisplacement();
+ return delegate.getMinUpdateDistanceMeters();
}
/**
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index d8a0bb334c53..d248f61f03ca 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -63,6 +63,7 @@ class ImageUtils {
case ImageFormat.DEPTH16:
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.RAW_DEPTH:
+ case ImageFormat.RAW_DEPTH10:
case ImageFormat.DEPTH_JPEG:
case ImageFormat.HEIC:
return 1;
@@ -110,6 +111,10 @@ class ImageUtils {
throw new IllegalArgumentException(
"Copy of RAW_DEPTH format has not been implemented");
}
+ if (src.getFormat() == ImageFormat.RAW_DEPTH10) {
+ throw new IllegalArgumentException(
+ "Copy of RAW_DEPTH10 format has not been implemented");
+ }
if (!(dst.getOwner() instanceof ImageWriter)) {
throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
+ " the images from ImageWriter are writable");
@@ -202,6 +207,7 @@ class ImageUtils {
estimatedBytePerPixel = 1.0;
break;
case ImageFormat.RAW10:
+ case ImageFormat.RAW_DEPTH10:
estimatedBytePerPixel = 1.25;
break;
case ImageFormat.YV12:
@@ -264,6 +270,7 @@ class ImageUtils {
case ImageFormat.RAW10:
case ImageFormat.RAW12:
case ImageFormat.RAW_DEPTH:
+ case ImageFormat.RAW_DEPTH10:
case ImageFormat.HEIC:
return new Size(image.getWidth(), image.getHeight());
case ImageFormat.PRIVATE:
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index 876628fefff4..acd284f3fad9 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -268,8 +268,11 @@ public final class MicrophoneInfo {
/**
* Returns A {@link Coordinate3F} object that represents the geometric location of microphone
- * in meters, from bottom-left-back corner of appliance. X-axis, Y-axis and Z-axis show
- * as the x, y, z values.
+ * in meters. X-axis, Y-axis and Z-axis show as the x, y, z values. For mobile devices, the axes
+ * originate from the bottom-left-back corner of the appliance. In devices with
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE}, axes are defined with respect
+ * to the vehicle body frame, originating from the center of the vehicle's rear axle.
+ * @see <a href="https://source.android.com/devices/sensors/sensor-types#auto_axes">auto axes</a>
*
* @return the geometric location of the microphone or {@link #POSITION_UNKNOWN} if the
* geometric location is unknown
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 20006934ee46..9494295e4bd9 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -68,16 +68,19 @@ public final class MediaSessionManager {
private static final String TAG = "SessionManager";
/**
- * Used by IOnMediaKeyListener to indicate that the media key event isn't handled.
+ * Used to indicate that the media key event isn't handled.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0;
/**
- * Used by IOnMediaKeyListener to indicate that the media key event is handled.
+ * Used to indicate that the media key event is handled.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int RESULT_MEDIA_KEY_HANDLED = 1;
+
private final ISessionManager mService;
private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
new OnMediaKeyEventDispatchedListenerStub();
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index d62e132b5745..4dd3f008f97a 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -23907,6 +23907,7 @@ package android.location {
method @NonNull public java.util.List<java.lang.String> getAllProviders();
method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
method @Nullable public String getGnssHardwareModelName();
method public int getGnssYearOfHardware();
@@ -23941,6 +23942,8 @@ package android.location {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
@@ -23984,6 +23987,30 @@ package android.location {
field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
+ public final class LocationRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDurationMillis();
+ method public long getIntervalMillis();
+ method public int getMaxUpdates();
+ method public float getMinUpdateDistanceMeters();
+ method public long getMinUpdateIntervalMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ }
+
+ public static final class LocationRequest.Builder {
+ ctor public LocationRequest.Builder(long);
+ ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+ method @NonNull public android.location.LocationRequest build();
+ method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+ method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+ method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+ method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index f7f42d0a5956..63b98cb5bd6a 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -66,6 +66,8 @@ package android.media.session {
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
+ field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 8fae240a95b4..a403f4521aa0 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4015,7 +4015,7 @@ package android.location {
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
@@ -4026,9 +4026,9 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -4037,42 +4037,49 @@ package android.location {
}
public final class LocationRequest implements android.os.Parcelable {
- method @NonNull public static android.location.LocationRequest create();
- method @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
- method @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
- method public int describeContents();
+ method @Deprecated @NonNull public static android.location.LocationRequest create();
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+ method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
method @Deprecated public long getExpireAt();
- method public long getExpireIn();
- method public long getFastestInterval();
- method public boolean getHideFromAppOps();
- method public long getInterval();
- method public int getNumUpdates();
- method @NonNull public String getProvider();
+ method @Deprecated public long getExpireIn();
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public boolean getHideFromAppOps();
+ method @Deprecated public long getInterval();
+ method @Deprecated public int getNumUpdates();
+ method @Deprecated @NonNull public String getProvider();
method public int getQuality();
- method public float getSmallestDisplacement();
+ method @Deprecated public float getSmallestDisplacement();
method @Nullable public android.os.WorkSource getWorkSource();
+ method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
- method public boolean isLowPowerMode();
+ method public boolean isLowPower();
+ method @Deprecated public boolean isLowPowerMode();
method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @NonNull public android.location.LocationRequest setExpireIn(long);
- method @NonNull public android.location.LocationRequest setFastestInterval(long);
- method public void setHideFromAppOps(boolean);
- method @NonNull public android.location.LocationRequest setInterval(long);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @NonNull public android.location.LocationRequest setQuality(int);
- method @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
- method public void setWorkSource(@Nullable android.os.WorkSource);
- method public void writeToParcel(android.os.Parcel, int);
+ method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+ method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+ method @Deprecated public void setHideFromAppOps(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+ method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+ method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+ method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+ method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
- field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final int POWER_HIGH = 203; // 0xcb
field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+ }
+
+ public static final class LocationRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 781efc118429..900e68d36c32 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -30,7 +30,6 @@ import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
-import android.os.Looper;
import android.os.WorkSource;
import com.android.internal.annotations.GuardedBy;
@@ -182,6 +181,7 @@ public class FusedLocationProvider extends LocationProviderBase {
for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
switch (request.getQuality()) {
case LocationRequestUnbundled.ACCURACY_FINE:
+ case LocationRequestUnbundled.ACCURACY_BLOCK:
case LocationRequestUnbundled.POWER_HIGH:
if (request.getInterval() < gpsInterval) {
gpsInterval = request.getInterval();
@@ -190,7 +190,6 @@ public class FusedLocationProvider extends LocationProviderBase {
networkInterval = request.getInterval();
}
break;
- case LocationRequestUnbundled.ACCURACY_BLOCK:
case LocationRequestUnbundled.ACCURACY_CITY:
case LocationRequestUnbundled.POWER_LOW:
if (request.getInterval() < networkInterval) {
@@ -219,13 +218,12 @@ public class FusedLocationProvider extends LocationProviderBase {
mLocationManager.removeUpdates(listener);
}
if (newInterval != Long.MAX_VALUE) {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- provider, newInterval, 0, false);
- if (mRequest.isLocationSettingsIgnored()) {
- request.setLocationSettingsIgnored(true);
- }
- request.setWorkSource(mWorkSource);
- mLocationManager.requestLocationUpdates(request, listener, Looper.getMainLooper());
+ LocationRequest request = new LocationRequest.Builder(newInterval)
+ .setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
+ .setWorkSource(mWorkSource)
+ .build();
+ mLocationManager.requestLocationUpdates(provider, request, mContext.getMainExecutor(),
+ listener);
}
}
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index 2c4545e7b265..687dd13f8732 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -16,7 +16,6 @@
package com.android.location.fused.tests;
-import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
@@ -121,8 +120,7 @@ public class FusedLocationServiceTest {
@Test
public void testNetworkRequest() throws Exception {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000,
- 0, false);
+ LocationRequest request = new LocationRequest.Builder(1000).build();
mProvider.setRequest(
new ProviderRequest.Builder()
@@ -139,8 +137,9 @@ public class FusedLocationServiceTest {
@Test
public void testGpsRequest() throws Exception {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000,
- 0, false).setQuality(LocationRequest.POWER_HIGH);
+ LocationRequest request = new LocationRequest.Builder(1000)
+ .setQuality(LocationRequest.POWER_HIGH)
+ .build();
mProvider.setRequest(
new ProviderRequest.Builder()
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 467a60e62e14..8e140ca27971 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -31,6 +31,7 @@ import android.location.LocationRequest;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.SystemClock;
import android.print.PrintManager;
@@ -250,9 +251,13 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
}
- mLocationManager.requestLocationUpdates(LocationRequest.create()
- .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this,
- Looper.getMainLooper());
+ mLocationManager.requestLocationUpdates(
+ LocationManager.FUSED_PROVIDER,
+ new LocationRequest.Builder(LOCATION_UPDATE_MS)
+ .setQuality(LocationRequest.POWER_LOW)
+ .build(),
+ new HandlerExecutor(new Handler(Looper.getMainLooper())),
+ this);
Location lastLocation = mLocationManager.getLastLocation();
if (lastLocation != null) {
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 9acfa0da7747..9ca1814783b5 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -25,7 +25,7 @@
<string name="wifi_remembered" msgid="3266709779723179188">"تم الحفظ"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"غير متصلة"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"غير مفعّلة"</string>
- <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"‏تعذّرت تهيئة عنوان IP"</string>
+ <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"‏تعذّر إعداد عنوان IP"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"الجهاز غير متصل بسبب انخفاض جودة الشبكة"</string>
<string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"‏تعذّر اتصال WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="6892387079613226738">"حدثت مشكلة في المصادقة"</string>
@@ -292,8 +292,8 @@
<string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"عندما نتوقف عن رصد أي أخطاء باستخدام المسجِّل الدائم مرة أخرى، يتعين علينا محو بيانات المسجِّل الموجودة على جهازك."</string>
<string name="select_logpersist_title" msgid="447071974007104196">"تخزين بيانات المسجِّل باستمرار على الجهاز"</string>
<string name="select_logpersist_dialog_title" msgid="7745193591195485594">"تحديد مخازن السجلات المؤقتة المراد تخزينها باستمرار على الجهاز"</string>
- <string name="select_usb_configuration_title" msgid="6339801314922294586">"‏حدد تهيئة USB"</string>
- <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"‏حدد تهيئة USB"</string>
+ <string name="select_usb_configuration_title" msgid="6339801314922294586">"‏حدد إعداد USB"</string>
+ <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"‏حدد إعداد USB"</string>
<string name="allow_mock_location" msgid="2102650981552527884">"السماح بمواقع وهمية"</string>
<string name="allow_mock_location_summary" msgid="179780881081354579">"السماح بمواقع وهمية"</string>
<string name="debug_view_attributes" msgid="3539609843984208216">"تفعيل فحص سمة العرض"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5ce40a837663..a6a39034c5eb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -107,7 +107,7 @@
<string name="status_bar_settings_notifications">Notifications</string>
<!-- Separator for PLMN and SPN in network name. -->
- <string name="status_bar_network_name_separator" translatable="false">|</string>
+ <string name="status_bar_network_name_separator" translatable="false"> - </string>
<!-- Network connection string for Bluetooth Reverse Tethering -->
<string name="bluetooth_tethered">Bluetooth tethered</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index f663d1a0d77c..1ebe64860a98 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -105,6 +105,9 @@ public class ScreenDecorations extends SystemUI implements Tunable {
public static final String SIZE = "sysui_rounded_size";
public static final String PADDING = "sysui_rounded_content_padding";
+ // Provide a way for factory to disable ScreenDecorations to run the Display tests.
+ private static final boolean DEBUG_DISABLE_SCREEN_DECORATIONS =
+ SystemProperties.getBoolean("debug.disable_screen_decorations", false);
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
private static final boolean VERBOSE = false;
@@ -204,6 +207,10 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Override
public void start() {
+ if (DEBUG_DISABLE_SCREEN_DECORATIONS) {
+ Log.i(TAG, "ScreenDecorations is disabled");
+ return;
+ }
mHandler = startHandlerThread();
mHandler.post(this::startOnScreenDecorationsThread);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 99875f8675d8..b6106025a17a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -458,6 +458,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mCurrentUserId = mNotifUserManager.getCurrentUserId();
+ mBubbleData.setCurrentUserId(mCurrentUserId);
+
mNotifUserManager.addUserChangedListener(
new NotificationLockscreenUserManager.UserChangedListener() {
@Override
@@ -466,6 +468,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleData.dismissAll(DISMISS_USER_CHANGED);
BubbleController.this.restoreBubbles(newUserId);
mCurrentUserId = newUserId;
+ mBubbleData.setCurrentUserId(newUserId);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index a747db680b2e..bab18ec053ee 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -35,6 +35,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -61,6 +62,8 @@ public class BubbleData {
private BubbleLoggerImpl mLogger = new BubbleLoggerImpl();
+ private int mCurrentUserId;
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleData" : TAG_BUBBLES;
private static final Comparator<Bubble> BUBBLES_BY_SORT_KEY_DESCENDING =
@@ -617,6 +620,10 @@ public class BubbleData {
mStateChange.selectionChanged = true;
}
+ void setCurrentUserId(int uid) {
+ mCurrentUserId = uid;
+ }
+
/**
* Logs the bubble UI event.
*
@@ -634,7 +641,9 @@ public class BubbleData {
if (provider == null) {
mLogger.logStackUiChanged(packageName, action, bubbleCount, normalX, normalY);
} else if (provider.getKey().equals(BubbleOverflow.KEY)) {
- mLogger.logShowOverflow(packageName, action, bubbleCount, normalX, normalY);
+ if (action == SysUiStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED) {
+ mLogger.logShowOverflow(packageName, mCurrentUserId);
+ }
} else {
mLogger.logBubbleUiChanged((Bubble) provider, packageName, action, bubbleCount, normalX,
normalY, bubbleIndex);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
index 1e6eb8c5c89b..86ba8c5c7192 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
@@ -53,7 +53,10 @@ public interface BubbleLogger extends UiEventLogger {
BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK(489),
@UiEvent(doc = "User blocked notification from bubbling, remove bubble from overflow.")
- BUBBLE_OVERFLOW_REMOVE_BLOCKED(490);
+ BUBBLE_OVERFLOW_REMOVE_BLOCKED(490),
+
+ @UiEvent(doc = "User selected the overflow.")
+ BUBBLE_OVERFLOW_SELECTED(600);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
index d702cc4e0062..2d90c8626a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.bubbles;
+import android.os.UserHandle;
+
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -31,11 +33,7 @@ public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger
* @param e UI event
*/
public void log(Bubble b, UiEventEnum e) {
- if (b.getInstanceId() == null) {
- // Added from persistence -- TODO log this with specific event?
- return;
- }
- logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId());
+ super.log(e, b.getUser().getIdentifier(), b.getPackageName());
}
/**
@@ -82,20 +80,9 @@ public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger
false /* isAppForeground (unused) */);
}
- void logShowOverflow(String packageName, int action, int bubbleCount, float normalX,
- float normalY) {
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- packageName,
- BubbleOverflow.KEY /* notification channel */,
- 0 /* notification ID */,
- 0 /* bubble position */,
- bubbleCount,
- action,
- normalX,
- normalY,
- false /* unread bubble */,
- false /* on-going bubble */,
- false /* isAppForeground (unused) */);
+ void logShowOverflow(String packageName, int currentUserId) {
+ super.log(BubbleLogger.Event.BUBBLE_OVERFLOW_SELECTED, currentUserId,
+ packageName);
}
void logBubbleUiChanged(Bubble bubble, String packageName, int action, int bubbleCount,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 7c7bb5c83762..b19997d15664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -42,6 +42,8 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -538,12 +540,21 @@ public class NotificationConversationInfo extends LinearLayout implements
&& Settings.Global.getInt(mContext.getContentResolver(),
NOTIFICATION_BUBBLES, 0) == 1;
+ Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo);
+ if (person == null) {
+ person = mContext.getDrawable(R.drawable.ic_person).mutate();
+ TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ person.setTint(colorAccent);
+ }
+
PriorityOnboardingDialogController controller = mBuilderProvider.get()
.setContext(mUserContext)
.setView(onboardingView)
.setIgnoresDnd(ignoreDnd)
.setShowsAsBubble(showAsBubble)
- .setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo))
+ .setIcon(person)
.setBadge(mIconFactory.getAppBadge(
mPackageName, UserHandle.getUserId(mSbn.getUid())))
.setOnSettingsClick(mOnConversationSettingsClickListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 31c1a5e5a9aa..8254b7f5b32a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1848,7 +1848,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarStateController.setPanelExpanded(isExpanded);
if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
if (DEBUG) {
- Log.v(TAG, "clearing notification effects from setExpandedHeight");
+ Log.v(TAG, "clearing notification effects from Height");
}
clearNotificationEffects();
}
@@ -2809,6 +2809,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ Trace.beginSection("StatusBar#onReceive");
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
@@ -2833,7 +2834,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeWindowController.setNotTouchable(false);
}
if (mBubbleController.isStackExpanded()) {
- mBubbleController.collapseStack();
+ // Post to main thread handler, since updating the UI.
+ mMainThreadHandler.post(() -> mBubbleController.collapseStack());
}
finishBarAnimations();
resetUserExpandedStates();
@@ -2841,6 +2843,7 @@ public class StatusBar extends SystemUI implements DemoMode,
else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
mQSPanel.showDeviceMonitoringDialog();
}
+ Trace.endSection();
}
};
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index d3d56d7f857d..9cbd78bf4482 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -68,6 +68,7 @@ public class WindowMagnificationManager implements
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
private int mUserId;
+ private boolean mReceiverRegistered = false;
@VisibleForTesting
protected final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
@Override
@@ -150,10 +151,16 @@ public class WindowMagnificationManager implements
}
if (connect) {
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- mContext.registerReceiver(mScreenStateReceiver, intentFilter);
+ if (!mReceiverRegistered) {
+ mContext.registerReceiver(mScreenStateReceiver, intentFilter);
+ mReceiverRegistered = true;
+ }
} else {
disableAllWindowMagnifiers();
- mContext.unregisterReceiver(mScreenStateReceiver);
+ if (mReceiverRegistered) {
+ mContext.unregisterReceiver(mScreenStateReceiver);
+ mReceiverRegistered = false;
+ }
}
}
@@ -240,6 +247,9 @@ public class WindowMagnificationManager implements
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
@Nullable Runnable endCallback) {
synchronized (mLock) {
+ if (mConnectionWrapper == null) {
+ return;
+ }
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
@@ -269,7 +279,7 @@ public class WindowMagnificationManager implements
void disableWindowMagnification(int displayId, boolean clear, Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || mConnectionWrapper == null) {
return;
}
magnifier.disableWindowMagnificationInternal(endCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd590d317910..bc79a6a5817b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
@@ -1136,6 +1137,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
null /* broadcastPermission */,
mHandler);
+ // Listen to lockdown VPN reset.
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
+ mContext.registerReceiverAsUser(
+ mIntentReceiver, UserHandle.ALL, intentFilter, NETWORK_STACK, mHandler);
+
try {
mNMS.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
@@ -5204,6 +5211,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void onVpnLockdownReset() {
+ synchronized (mVpns) {
+ if (mLockdownTracker != null) mLockdownTracker.reset();
+ }
+ }
+
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -5214,6 +5227,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
final Uri packageData = intent.getData();
final String packageName =
packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
+ onVpnLockdownReset();
+ }
+
+ // UserId should be filled for below intents, check the existence.
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
@@ -5232,6 +5251,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final boolean isReplacing = intent.getBooleanExtra(
Intent.EXTRA_REPLACING, false);
onPackageRemoved(packageName, uid, isReplacing);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
}
}
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index fede1d2832b8..48055b51722f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -26,6 +26,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
+import android.os.Message;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
@@ -124,6 +125,7 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
+ private static final int DEFAULT_MAX_PHANTOM_PROCESSES = 32;
// Flag stored in the DeviceConfig API.
@@ -133,6 +135,11 @@ final class ActivityManagerConstants extends ContentObserver {
private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
/**
+ * Maximum number of cached processes.
+ */
+ private static final String KEY_MAX_PHANTOM_PROCESSES = "max_phantom_processes";
+
+ /**
* Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
* Settings.Global. This allows it to be set experimentally unless it has been
* enabled/disabled in developer options. Defaults to false.
@@ -364,6 +371,11 @@ final class ActivityManagerConstants extends ContentObserver {
*/
public final ArraySet<ComponentName> KEEP_WARMING_SERVICES = new ArraySet<ComponentName>();
+ /**
+ * Maximum number of phantom processes.
+ */
+ public int MAX_PHANTOM_PROCESSES = DEFAULT_MAX_PHANTOM_PROCESSES;
+
private List<String> mDefaultImperceptibleKillExemptPackages;
private List<Integer> mDefaultImperceptibleKillExemptProcStates;
@@ -481,6 +493,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD:
updateBinderHeavyHitterWatcher();
break;
+ case KEY_MAX_PHANTOM_PROCESSES:
+ updateMaxPhantomProcesses();
+ break;
default:
break;
}
@@ -599,6 +614,8 @@ final class ActivityManagerConstants extends ContentObserver {
// with defaults.
Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e);
}
+ final long currentPowerCheckInterval = POWER_CHECK_INTERVAL;
+
BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME,
DEFAULT_BACKGROUND_SETTLE_TIME);
FGSERVICE_MIN_SHOWN_TIME = mParser.getLong(KEY_FGSERVICE_MIN_SHOWN_TIME,
@@ -664,6 +681,13 @@ final class ActivityManagerConstants extends ContentObserver {
PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
+ if (POWER_CHECK_INTERVAL != currentPowerCheckInterval) {
+ mService.mHandler.removeMessages(
+ ActivityManagerService.CHECK_EXCESSIVE_POWER_USE_MSG);
+ final Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.CHECK_EXCESSIVE_POWER_USE_MSG);
+ mService.mHandler.sendMessageDelayed(msg, POWER_CHECK_INTERVAL);
+ }
// For new flags that are intended for server-side experiments, please use the new
// DeviceConfig package.
}
@@ -811,6 +835,16 @@ final class ActivityManagerConstants extends ContentObserver {
mService.scheduleUpdateBinderHeavyHitterWatcherConfig();
}
+ private void updateMaxPhantomProcesses() {
+ final int oldVal = MAX_PHANTOM_PROCESSES;
+ MAX_PHANTOM_PROCESSES = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MAX_PHANTOM_PROCESSES,
+ DEFAULT_MAX_PHANTOM_PROCESSES);
+ if (oldVal > MAX_PHANTOM_PROCESSES) {
+ mService.mHandler.post(mService.mPhantomProcessList::trimPhantomProcessesIfNecessary);
+ }
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -897,6 +931,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(BINDER_HEAVY_HITTER_AUTO_SAMPLER_BATCHSIZE);
pw.print(" "); pw.print(KEY_BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD); pw.print("=");
pw.println(BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD);
+ pw.print(" "); pw.print(KEY_MAX_PHANTOM_PROCESSES); pw.print("=");
+ pw.println(MAX_PHANTOM_PROCESSES);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b55d55562110..b1b4018036c0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -635,6 +635,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessList mProcessList;
/**
+ * The list of phantom processes.
+ * @see PhantomProcessRecord
+ */
+ final PhantomProcessList mPhantomProcessList;
+
+ /**
* Tracking long-term execution of processes to look for abuse and other
* bad app behavior.
*/
@@ -1996,6 +2002,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList = injector.getProcessList(this);
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
+ mPhantomProcessList = new PhantomProcessList(this);
mOomAdjuster = hasHandlerThread
? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
@@ -2053,6 +2060,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(),
new LowMemDetector(this));
+ mPhantomProcessList = new PhantomProcessList(this);
mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
// Broadcast policy parameters
@@ -9209,6 +9217,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ if (dumpAll) {
+ mPhantomProcessList.dump(pw, " ");
+ }
+
if (mImportantProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
@@ -14832,44 +14844,24 @@ public class ActivityManagerService extends IActivityManager.Stub
int i = mProcessList.mLruProcesses.size();
while (i > 0) {
i--;
- ProcessRecord app = mProcessList.mLruProcesses.get(i);
+ final ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
- if (app.lastCpuTime <= 0) {
- continue;
- }
- long cputimeUsed = app.curCpuTime - app.lastCpuTime;
- if (DEBUG_POWER) {
- StringBuilder sb = new StringBuilder(128);
- sb.append("CPU for ");
- app.toShortString(sb);
- sb.append(": over ");
- TimeUtils.formatDuration(uptimeSince, sb);
- sb.append(" used ");
- TimeUtils.formatDuration(cputimeUsed, sb);
- sb.append(" (");
- sb.append((cputimeUsed * 100) / uptimeSince);
- sb.append("%)");
- Slog.i(TAG_POWER, sb.toString());
+ int cpuLimit;
+ long checkDur = curUptime - app.getWhenUnimportant();
+ if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;
+ } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 2)
+ || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2;
+ } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 3)) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3;
+ } else {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;
}
- // If the process has used too much CPU over the last duration, the
- // user probably doesn't want this, so kill!
- if (doCpuKills && uptimeSince > 0) {
- // What is the limit for this process?
- int cpuLimit;
- long checkDur = curUptime - app.getWhenUnimportant();
- if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {
- cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;
- } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 2)
- || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) {
- cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2;
- } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 3)) {
- cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3;
- } else {
- cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;
- }
- if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) {
- mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
- uptimeSince, cputimeUsed);
+ if (app.lastCpuTime > 0) {
+ final long cputimeUsed = app.curCpuTime - app.lastCpuTime;
+ if (checkExcessivePowerUsageLocked(uptimeSince, doCpuKills, cputimeUsed,
+ app.processName, app.toShortString(), cpuLimit, app)) {
app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ " dur=" + checkDur + " limit=" + cpuLimit,
ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
@@ -14878,21 +14870,71 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (mProcessStats.mLock) {
app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList);
}
- for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(
- FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
- app.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- holder.appVersion);
- }
}
}
+
app.lastCpuTime = app.curCpuTime;
+
+ // Also check the phantom processes if there is any
+ final long chkDur = checkDur;
+ final int cpuLmt = cpuLimit;
+ final boolean doKill = doCpuKills;
+ mPhantomProcessList.forEachPhantomProcessOfApp(app, r -> {
+ if (r.mLastCputime > 0) {
+ final long cputimeUsed = r.mCurrentCputime - r.mLastCputime;
+ if (checkExcessivePowerUsageLocked(uptimeSince, doKill, cputimeUsed,
+ app.processName, r.toString(), cpuLimit, app)) {
+ mPhantomProcessList.killPhantomProcessGroupLocked(app, r,
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
+ "excessive cpu " + cputimeUsed + " during "
+ + uptimeSince + " dur=" + chkDur + " limit=" + cpuLmt);
+ return false;
+ }
+ }
+ r.mLastCputime = r.mCurrentCputime;
+ return true;
+ });
+ }
+ }
+ }
+ }
+
+ private boolean checkExcessivePowerUsageLocked(final long uptimeSince, boolean doCpuKills,
+ final long cputimeUsed, final String processName, final String description,
+ final int cpuLimit, final ProcessRecord app) {
+ if (DEBUG_POWER) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("CPU for ");
+ sb.append(description);
+ sb.append(": over ");
+ TimeUtils.formatDuration(uptimeSince, sb);
+ sb.append(" used ");
+ TimeUtils.formatDuration(cputimeUsed, sb);
+ sb.append(" (");
+ sb.append((cputimeUsed * 100.0) / uptimeSince);
+ sb.append("%)");
+ Slog.i(TAG_POWER, sb.toString());
+ }
+ // If the process has used too much CPU over the last duration, the
+ // user probably doesn't want this, so kill!
+ if (doCpuKills && uptimeSince > 0) {
+ if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) {
+ mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
+ uptimeSince, cputimeUsed);
+ for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
+ app.info.uid,
+ processName,
+ holder.state.getPackage(),
+ holder.appVersion);
}
+ return true;
}
}
+ return false;
}
final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 0b5d5859e86e..31ffb35f24b3 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1257,6 +1257,10 @@ public class AppProfiler {
}
}
+ if (haveNewCpuStats) {
+ mService.mPhantomProcessList.updateProcessCpuStatesLocked(mProcessCpuTracker);
+ }
+
final BatteryStatsImpl bstats = mService.mBatteryStatsService.getActiveStatistics();
synchronized (bstats) {
if (haveNewCpuStats) {
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
new file mode 100644
index 000000000000..e2fcf08ce82b
--- /dev/null
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2020 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.server.am;
+
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.ApplicationExitInfo.Reason;
+import android.app.ApplicationExitInfo.SubReason;
+import android.os.Handler;
+import android.os.Process;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.ProcessCpuTracker;
+
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.function.Function;
+
+/**
+ * Activity manager code dealing with phantom processes.
+ */
+public final class PhantomProcessList {
+ static final String TAG = TAG_WITH_CLASS_NAME ? "PhantomProcessList" : TAG_AM;
+
+ final Object mLock = new Object();
+
+ /**
+ * All of the phantom process record we track, key is the pid of the process.
+ */
+ @GuardedBy("mLock")
+ final SparseArray<PhantomProcessRecord> mPhantomProcesses = new SparseArray<>();
+
+ /**
+ * The mapping between app processes and their phantom processess, outer key is the pid of
+ * the app process, while the inner key is the pid of the phantom process.
+ */
+ @GuardedBy("mLock")
+ final SparseArray<SparseArray<PhantomProcessRecord>> mAppPhantomProcessMap =
+ new SparseArray<>();
+
+ /**
+ * The mapping of the pidfd to PhantomProcessRecord.
+ */
+ @GuardedBy("mLock")
+ final SparseArray<PhantomProcessRecord> mPhantomProcessesPidFds = new SparseArray<>();
+
+ /**
+ * The list of phantom processes tha's being signaled to be killed but still undead yet.
+ */
+ @GuardedBy("mLock")
+ final SparseArray<PhantomProcessRecord> mZombiePhantomProcesses = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ private final ArrayList<PhantomProcessRecord> mTempPhantomProcesses = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private boolean mTrimPhantomProcessScheduled = false;
+
+ @GuardedBy("mLock")
+ int mUpdateSeq;
+
+ private final ActivityManagerService mService;
+ private final Handler mKillHandler;
+
+ PhantomProcessList(final ActivityManagerService service) {
+ mService = service;
+ mKillHandler = service.mProcessList.sKillHandler;
+ }
+
+ /**
+ * Get the existing phantom process record, or create if it's not existing yet;
+ * however, before creating it, we'll check if this is really a phantom process
+ * and we'll return null if it's not.
+ */
+ @GuardedBy("mLock")
+ PhantomProcessRecord getOrCreatePhantomProcessIfNeededLocked(final String processName,
+ final int uid, final int pid) {
+ // First check if it's actually an app process we know
+ if (isAppProcess(pid)) {
+ return null;
+ }
+
+ // Have we already been aware of this?
+ final int index = mPhantomProcesses.indexOfKey(pid);
+ if (index >= 0) {
+ final PhantomProcessRecord proc = mPhantomProcesses.valueAt(index);
+ if (proc.equals(processName, uid, pid)) {
+ return proc;
+ }
+ // Somehow our record doesn't match, remove it anyway
+ Slog.w(TAG, "Stale " + proc + ", removing");
+ mPhantomProcesses.removeAt(index);
+ } else {
+ // Is this one of the zombie processes we've known?
+ final int idx = mZombiePhantomProcesses.indexOfKey(pid);
+ if (idx >= 0) {
+ final PhantomProcessRecord proc = mZombiePhantomProcesses.valueAt(idx);
+ if (proc.equals(processName, uid, pid)) {
+ return proc;
+ }
+ // Our zombie process information is outdated, let's remove this one, it shoud
+ // have been gone.
+ mZombiePhantomProcesses.removeAt(idx);
+ }
+ }
+
+ int ppid = getParentPid(pid);
+
+ // Walk through its parents and see if it could be traced back to an app process.
+ while (ppid > 1) {
+ if (isAppProcess(ppid)) {
+ // It's a phantom process, bookkeep it
+ try {
+ final PhantomProcessRecord proc = new PhantomProcessRecord(
+ processName, uid, pid, ppid, mService,
+ this::onPhantomProcessKilledLocked);
+ proc.mUpdateSeq = mUpdateSeq;
+ mPhantomProcesses.put(pid, proc);
+ SparseArray<PhantomProcessRecord> array = mAppPhantomProcessMap.get(ppid);
+ if (array == null) {
+ array = new SparseArray<>();
+ mAppPhantomProcessMap.put(ppid, array);
+ }
+ array.put(pid, proc);
+ if (proc.mPidFd != null) {
+ mKillHandler.getLooper().getQueue().addOnFileDescriptorEventListener(
+ proc.mPidFd, EVENT_INPUT | EVENT_ERROR,
+ this::onPhantomProcessFdEvent);
+ mPhantomProcessesPidFds.put(proc.mPidFd.getInt$(), proc);
+ }
+ scheduleTrimPhantomProcessesLocked();
+ return proc;
+ } catch (IllegalStateException e) {
+ return null;
+ }
+ }
+
+ ppid = getParentPid(ppid);
+ }
+ return null;
+ }
+
+ private static int getParentPid(int pid) {
+ try {
+ return Process.getParentPid(pid);
+ } catch (Exception e) {
+ }
+ return -1;
+ }
+
+ private boolean isAppProcess(int pid) {
+ synchronized (mService.mPidsSelfLocked) {
+ return mService.mPidsSelfLocked.get(pid) != null;
+ }
+ }
+
+ private int onPhantomProcessFdEvent(FileDescriptor fd, int events) {
+ synchronized (mLock) {
+ final PhantomProcessRecord proc = mPhantomProcessesPidFds.get(fd.getInt$());
+ if ((events & EVENT_INPUT) != 0) {
+ proc.onProcDied(true);
+ } else {
+ // EVENT_ERROR, kill the process
+ proc.killLocked("Process error", true);
+ }
+ }
+ return 0;
+ }
+
+ @GuardedBy("mLock")
+ private void onPhantomProcessKilledLocked(final PhantomProcessRecord proc) {
+ if (proc.mPidFd != null && proc.mPidFd.valid()) {
+ mKillHandler.getLooper().getQueue()
+ .removeOnFileDescriptorEventListener(proc.mPidFd);
+ mPhantomProcessesPidFds.remove(proc.mPidFd.getInt$());
+ IoUtils.closeQuietly(proc.mPidFd);
+ }
+ mPhantomProcesses.remove(proc.mPid);
+ final int index = mAppPhantomProcessMap.indexOfKey(proc.mPpid);
+ if (index < 0) {
+ return;
+ }
+ SparseArray<PhantomProcessRecord> array = mAppPhantomProcessMap.valueAt(index);
+ array.remove(proc.mPid);
+ if (array.size() == 0) {
+ mAppPhantomProcessMap.removeAt(index);
+ }
+ if (proc.mZombie) {
+ // If it's not really dead, bookkeep it
+ mZombiePhantomProcesses.put(proc.mPid, proc);
+ } else {
+ // In case of race condition, let's try to remove it from zombie list
+ mZombiePhantomProcesses.remove(proc.mPid);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void scheduleTrimPhantomProcessesLocked() {
+ if (!mTrimPhantomProcessScheduled) {
+ mTrimPhantomProcessScheduled = true;
+ mService.mHandler.post(this::trimPhantomProcessesIfNecessary);
+ }
+ }
+
+ /**
+ * Clamp the number of phantom processes to
+ * {@link ActivityManagerConstants#MAX_PHANTOM_PROCESSE}, kills those surpluses in the
+ * order of the oom adjs of their parent process.
+ */
+ void trimPhantomProcessesIfNecessary() {
+ synchronized (mLock) {
+ mTrimPhantomProcessScheduled = false;
+ if (mService.mConstants.MAX_PHANTOM_PROCESSES < mPhantomProcesses.size()) {
+ for (int i = mPhantomProcesses.size() - 1; i >= 0; i--) {
+ mTempPhantomProcesses.add(mPhantomProcesses.valueAt(i));
+ }
+ synchronized (mService.mPidsSelfLocked) {
+ Collections.sort(mTempPhantomProcesses, (a, b) -> {
+ final ProcessRecord ra = mService.mPidsSelfLocked.get(a.mPpid);
+ if (ra == null) {
+ // parent is gone, this process should have been killed too
+ return 1;
+ }
+ final ProcessRecord rb = mService.mPidsSelfLocked.get(b.mPpid);
+ if (rb == null) {
+ // parent is gone, this process should have been killed too
+ return -1;
+ }
+ if (ra.curAdj != rb.curAdj) {
+ return ra.curAdj - rb.curAdj;
+ }
+ if (a.mKnownSince != b.mKnownSince) {
+ // In case of identical oom adj, younger one first
+ return a.mKnownSince < b.mKnownSince ? 1 : -1;
+ }
+ return 0;
+ });
+ }
+ for (int i = mTempPhantomProcesses.size() - 1;
+ i >= mService.mConstants.MAX_PHANTOM_PROCESSES; i--) {
+ final PhantomProcessRecord proc = mTempPhantomProcesses.get(i);
+ proc.killLocked("Trimming phantom processes", true);
+ }
+ mTempPhantomProcesses.clear();
+ }
+ }
+ }
+
+ /**
+ * Remove all entries with outdated seq num.
+ */
+ @GuardedBy("mLock")
+ void pruneStaleProcessesLocked() {
+ for (int i = mPhantomProcesses.size() - 1; i >= 0; i--) {
+ final PhantomProcessRecord proc = mPhantomProcesses.valueAt(i);
+ if (proc.mUpdateSeq < mUpdateSeq) {
+ if (DEBUG_PROCESSES) {
+ Slog.v(TAG, "Pruning " + proc + " as it should have been dead.");
+ }
+ proc.killLocked("Stale process", true);
+ }
+ }
+ for (int i = mZombiePhantomProcesses.size() - 1; i >= 0; i--) {
+ final PhantomProcessRecord proc = mZombiePhantomProcesses.valueAt(i);
+ if (proc.mUpdateSeq < mUpdateSeq) {
+ if (DEBUG_PROCESSES) {
+ Slog.v(TAG, "Pruning " + proc + " as it should have been dead.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Kill the given phantom process, all its siblings (if any) and their parent process
+ */
+ @GuardedBy("mService")
+ void killPhantomProcessGroupLocked(ProcessRecord app, PhantomProcessRecord proc,
+ @Reason int reasonCode, @SubReason int subReason, String msg) {
+ synchronized (mLock) {
+ int index = mAppPhantomProcessMap.indexOfKey(proc.mPpid);
+ if (index >= 0) {
+ final SparseArray<PhantomProcessRecord> array =
+ mAppPhantomProcessMap.valueAt(index);
+ for (int i = array.size() - 1; i >= 0; i--) {
+ final PhantomProcessRecord r = array.valueAt(i);
+ if (r == proc) {
+ r.killLocked(msg, true);
+ } else {
+ r.killLocked("Caused by siling process: " + msg, false);
+ }
+ }
+ }
+ }
+ // Lastly, kill the parent process too
+ app.kill("Caused by child process: " + msg, reasonCode, subReason, true);
+ }
+
+ /**
+ * Iterate all phantom process belonging to the given app, and invokve callback
+ * for each of them.
+ */
+ void forEachPhantomProcessOfApp(final ProcessRecord app,
+ final Function<PhantomProcessRecord, Boolean> callback) {
+ synchronized (mLock) {
+ int index = mAppPhantomProcessMap.indexOfKey(app.pid);
+ if (index >= 0) {
+ final SparseArray<PhantomProcessRecord> array =
+ mAppPhantomProcessMap.valueAt(index);
+ for (int i = array.size() - 1; i >= 0; i--) {
+ final PhantomProcessRecord r = array.valueAt(i);
+ if (!callback.apply(r)) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("tracker")
+ void updateProcessCpuStatesLocked(ProcessCpuTracker tracker) {
+ synchronized (mLock) {
+ // refresh the phantom process list with the latest cpu stats results.
+ mUpdateSeq++;
+ for (int i = tracker.countStats() - 1; i >= 0; i--) {
+ final ProcessCpuTracker.Stats st = tracker.getStats(i);
+ final PhantomProcessRecord r =
+ getOrCreatePhantomProcessIfNeededLocked(st.name, st.uid, st.pid);
+ if (r != null) {
+ r.mUpdateSeq = mUpdateSeq;
+ r.mCurrentCputime += st.rel_utime + st.rel_stime;
+ if (r.mLastCputime == 0) {
+ r.mLastCputime = r.mCurrentCputime;
+ }
+ r.updateAdjLocked();
+ }
+ }
+ // remove the stale ones
+ pruneStaleProcessesLocked();
+ }
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ dumpPhantomeProcessLocked(pw, prefix, "All Active App Child Processes:",
+ mPhantomProcesses);
+ dumpPhantomeProcessLocked(pw, prefix, "All Zombie App Child Processes:",
+ mZombiePhantomProcesses);
+ }
+ }
+
+ void dumpPhantomeProcessLocked(PrintWriter pw, String prefix, String headline,
+ SparseArray<PhantomProcessRecord> list) {
+ final int size = list.size();
+ if (size == 0) {
+ return;
+ }
+ pw.println();
+ pw.print(prefix);
+ pw.println(headline);
+ for (int i = 0; i < size; i++) {
+ final PhantomProcessRecord proc = list.valueAt(i);
+ pw.print(prefix);
+ pw.print(" proc #");
+ pw.print(i);
+ pw.print(": ");
+ pw.println(proc.toString());
+ proc.dump(pw, prefix + " ");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/PhantomProcessRecord.java b/services/core/java/com/android/server/am/PhantomProcessRecord.java
new file mode 100644
index 000000000000..0156ee5bb018
--- /dev/null
+++ b/services/core/java/com/android/server/am/PhantomProcessRecord.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2020 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.server.am;
+
+import static android.os.Process.PROC_NEWLINE_TERM;
+import static android.os.Process.PROC_OUT_LONG;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.os.Handler;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
+/**
+ * The "phantom" app processes, which are forked by app processes so we are not aware of
+ * them until we walk through the process list in /proc.
+ */
+public final class PhantomProcessRecord {
+ static final String TAG = TAG_WITH_CLASS_NAME ? "PhantomProcessRecord" : TAG_AM;
+
+ static final long[] LONG_OUT = new long[1];
+ static final int[] LONG_FORMAT = new int[] {PROC_NEWLINE_TERM | PROC_OUT_LONG};
+
+ final String mProcessName; // name of the process
+ final int mUid; // uid of the process
+ final int mPid; // The id of the process
+ final int mPpid; // Ancestor (managed app process) pid of the process
+ final long mKnownSince; // The timestamp when we're aware of the process
+ final FileDescriptor mPidFd; // The fd to monitor the termination of this process
+
+ long mLastCputime; // How long proc has run CPU at last check
+ long mCurrentCputime; // How long proc has run CPU most recently
+ int mUpdateSeq; // Seq no, indicating the last check on this process
+ int mAdj; // The last known oom adj score
+ boolean mKilled; // Whether it has been killed by us or not
+ boolean mZombie; // Whether it was signaled to be killed but timed out
+ String mStringName; // Caching of the toString() result
+
+ final ActivityManagerService mService;
+ final Object mLock;
+ final Consumer<PhantomProcessRecord> mOnKillListener;
+ final Handler mKillHandler;
+
+ PhantomProcessRecord(final String processName, final int uid, final int pid,
+ final int ppid, final ActivityManagerService service,
+ final Consumer<PhantomProcessRecord> onKillListener) throws IllegalStateException {
+ mProcessName = processName;
+ mUid = uid;
+ mPid = pid;
+ mPpid = ppid;
+ mKilled = false;
+ mAdj = ProcessList.NATIVE_ADJ;
+ mKnownSince = SystemClock.elapsedRealtime();
+ mService = service;
+ mLock = service.mPhantomProcessList.mLock;
+ mOnKillListener = onKillListener;
+ mKillHandler = service.mProcessList.sKillHandler;
+ if (Process.supportsPidFd()) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ mPidFd = Process.openPidFd(pid, 0);
+ if (mPidFd == null) {
+ throw new IllegalStateException();
+ }
+ } catch (IOException e) {
+ // Maybe a race condition, the process is gone.
+ Slog.w(TAG, "Unable to open process " + pid + ", it might be gone");
+ IllegalStateException ex = new IllegalStateException();
+ ex.initCause(e);
+ throw ex;
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ } else {
+ mPidFd = null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ void killLocked(String reason, boolean noisy) {
+ if (!mKilled) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
+ if (noisy || mUid == mService.mCurOomAdjUid) {
+ mService.reportUidInfoMessageLocked(TAG,
+ "Killing " + toString() + ": " + reason, mUid);
+ }
+ if (mPid > 0) {
+ EventLog.writeEvent(EventLogTags.AM_KILL, UserHandle.getUserId(mUid),
+ mPid, mProcessName, mAdj, reason);
+ if (!Process.supportsPidFd()) {
+ onProcDied(false);
+ } else {
+ // We'll notify the listener when we're notified it's dead.
+ // Meanwhile, we'd also need handle the case of zombie processes.
+ mKillHandler.postDelayed(mProcKillTimer, this,
+ ProcessList.PROC_KILL_TIMEOUT);
+ }
+ Process.killProcessQuiet(mPid);
+ ProcessList.killProcessGroup(mUid, mPid);
+ }
+ mKilled = true;
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
+ private Runnable mProcKillTimer = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ // The process is maybe in either D or Z state.
+ Slog.w(TAG, "Process " + toString() + " is still alive after "
+ + ProcessList.PROC_KILL_TIMEOUT + "ms");
+ // Force a cleanup as we can't keep the fd open forever
+ mZombie = true;
+ onProcDied(false);
+ // But still bookkeep it, so it won't be added as a new one if it's spotted again.
+ }
+ }
+ };
+
+ @GuardedBy("mLock")
+ void updateAdjLocked() {
+ if (Process.readProcFile("/proc/" + mPid + "/oom_score_adj",
+ LONG_FORMAT, null, LONG_OUT, null)) {
+ mAdj = (int) LONG_OUT[0];
+ }
+ }
+
+ @GuardedBy("mLock")
+ void onProcDied(boolean reallyDead) {
+ if (reallyDead) {
+ Slog.i(TAG, "Process " + toString() + " died");
+ }
+ mKillHandler.removeCallbacks(mProcKillTimer, this);
+ if (mOnKillListener != null) {
+ mOnKillListener.accept(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (mStringName != null) {
+ return mStringName;
+ }
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("PhantomProcessRecord {");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(mPid);
+ sb.append(':');
+ sb.append(mPpid);
+ sb.append(':');
+ sb.append(mProcessName);
+ sb.append('/');
+ if (mUid < Process.FIRST_APPLICATION_UID) {
+ sb.append(mUid);
+ } else {
+ sb.append('u');
+ sb.append(UserHandle.getUserId(mUid));
+ int appId = UserHandle.getAppId(mUid);
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ sb.append('a');
+ sb.append(appId - Process.FIRST_APPLICATION_UID);
+ } else {
+ sb.append('s');
+ sb.append(appId);
+ }
+ if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
+ sb.append('i');
+ sb.append(appId - Process.FIRST_ISOLATED_UID);
+ }
+ }
+ sb.append('}');
+ return mStringName = sb.toString();
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final long now = SystemClock.elapsedRealtime();
+ pw.print(prefix);
+ pw.print("user #");
+ pw.print(UserHandle.getUserId(mUid));
+ pw.print(" uid=");
+ pw.print(mUid);
+ pw.print(" pid=");
+ pw.print(mPid);
+ pw.print(" ppid=");
+ pw.print(mPpid);
+ pw.print(" knownSince=");
+ TimeUtils.formatDuration(mKnownSince, now, pw);
+ pw.print(" killed=");
+ pw.println(mKilled);
+ pw.print(prefix);
+ pw.print("lastCpuTime=");
+ pw.print(mLastCputime);
+ if (mLastCputime > 0) {
+ pw.print(" timeUsed=");
+ TimeUtils.formatDuration(mCurrentCputime - mLastCputime, pw);
+ }
+ pw.print(" oom adj=");
+ pw.print(mAdj);
+ pw.print(" seq=");
+ pw.println(mUpdateSeq);
+ }
+
+ boolean equals(final String processName, final int uid, final int pid) {
+ return mUid == uid && mPid == pid && TextUtils.equals(mProcessName, processName);
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ced2f0f5ebc4..5e6556339b43 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -329,7 +329,7 @@ public final class ProcessList {
/**
* How long between a process kill and we actually receive its death recipient
*/
- private static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
+ static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
/**
* Native heap allocations will now have a non-zero tag in the most significant byte.
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 713f8008e313..425fbc5687ec 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -329,6 +329,30 @@ final class Constants {
static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL;
+ // The relationship from one path (physical address) to another.
+ @IntDef({
+ PATH_RELATIONSHIP_UNKNOWN,
+ PATH_RELATIONSHIP_DIFFERENT_BRANCH,
+ PATH_RELATIONSHIP_ANCESTOR,
+ PATH_RELATIONSHIP_DESCENDANT,
+ PATH_RELATIONSHIP_SIBLING,
+ PATH_RELATIONSHIP_SAME
+ })
+ @interface PathRelationship {}
+
+ // One or both of the paths is invalid
+ static final int PATH_RELATIONSHIP_UNKNOWN = 0;
+ // None of the relationships below holds
+ static final int PATH_RELATIONSHIP_DIFFERENT_BRANCH = 1;
+ // A path is either the TV, or between the TV and another path
+ static final int PATH_RELATIONSHIP_ANCESTOR = 2;
+ // A path is located somewhere below another path
+ static final int PATH_RELATIONSHIP_DESCENDANT = 3;
+ // A path has the same parent as another path
+ static final int PATH_RELATIONSHIP_SIBLING = 4;
+ // A path is equal to another path
+ static final int PATH_RELATIONSHIP_SAME = 5;
+
// Strategy for device polling.
// Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
static final int POLL_STRATEGY_MASK = 0x3; // first and second bit.
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index cd65db6055af..a6951ef1958f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -24,10 +24,11 @@ import android.util.Xml;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
-
import com.android.server.hdmi.Constants.AbortReason;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.Constants.FeatureOpcode;
+import com.android.server.hdmi.Constants.PathRelationship;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -311,26 +312,43 @@ final class HdmiUtils {
* @return true if the new path in the active routing path
*/
static boolean isInActiveRoutingPath(int activePath, int newPath) {
- // Check each nibble of the currently active path and the new path till the position
- // where the active nibble is not zero. For (activePath, newPath),
- // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
- // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
- // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
- // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
- for (int i = 12; i >= 0; i -= 4) {
- int nibbleActive = (activePath >> i) & 0xF;
- if (nibbleActive == 0) {
- break;
- }
- int nibbleNew = (newPath >> i) & 0xF;
- if (nibbleNew == 0) {
- break;
- }
- if (nibbleActive != nibbleNew) {
- return false;
+ @PathRelationship int pathRelationship = pathRelationship(newPath, activePath);
+ return (pathRelationship == Constants.PATH_RELATIONSHIP_ANCESTOR
+ || pathRelationship == Constants.PATH_RELATIONSHIP_DESCENDANT
+ || pathRelationship == Constants.PATH_RELATIONSHIP_SAME);
+ }
+
+ /**
+ * Computes the relationship from the first path to the second path.
+ */
+ static @PathRelationship int pathRelationship(int firstPath, int secondPath) {
+ if (firstPath == Constants.INVALID_PHYSICAL_ADDRESS
+ || secondPath == Constants.INVALID_PHYSICAL_ADDRESS) {
+ return Constants.PATH_RELATIONSHIP_UNKNOWN;
+ }
+ // Loop forwards through both paths, looking for the first nibble where the paths differ.
+ // Checking this nibble and the next one distinguishes between most possible relationships.
+ for (int nibbleIndex = 0; nibbleIndex <= 3; nibbleIndex++) {
+ int shift = 12 - nibbleIndex * 4;
+ int firstPathNibble = (firstPath >> shift) & 0xF;
+ int secondPathNibble = (secondPath >> shift) & 0xF;
+ // Found the first nibble where the paths differ.
+ if (firstPathNibble != secondPathNibble) {
+ int firstPathNextNibble = (firstPath >> (shift - 4)) & 0xF;
+ int secondPathNextNibble = (secondPath >> (shift - 4)) & 0xF;
+ if (firstPathNibble == 0) {
+ return Constants.PATH_RELATIONSHIP_ANCESTOR;
+ } else if (secondPathNibble == 0) {
+ return Constants.PATH_RELATIONSHIP_DESCENDANT;
+ } else if (nibbleIndex == 3
+ || (firstPathNextNibble == 0 && secondPathNextNibble == 0)) {
+ return Constants.PATH_RELATIONSHIP_SIBLING;
+ } else {
+ return Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH;
+ }
}
}
- return true;
+ return Constants.PATH_RELATIONSHIP_SAME;
}
/**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index f4d0a6254318..807784dde505 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -553,8 +553,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void registerLocationListener(LocationRequest request, ILocationListener listener,
- String packageName, String attributionTag, String listenerId) {
+ public void registerLocationListener(String provider, LocationRequest request,
+ ILocationListener listener, String packageName, String attributionTag,
+ String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
@@ -570,16 +571,16 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.registerLocationRequest(request, identity, permissionLevel, listener);
}
@Override
- public void registerLocationPendingIntent(LocationRequest request, PendingIntent pendingIntent,
- String packageName, String attributionTag) {
+ public void registerLocationPendingIntent(String provider, LocationRequest request,
+ PendingIntent pendingIntent, String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
AppOpsManager.toReceiverId(pendingIntent));
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
@@ -592,24 +593,22 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
@PermissionLevel int permissionLevel) {
- Objects.requireNonNull(request.getProvider());
-
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_DEVICE_STATS,
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- if (request.getHideFromAppOps()) {
+ if (request.isHiddenFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_APP_OPS_STATS,
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
@@ -620,12 +619,12 @@ public class LocationManagerService extends ILocationManager.Stub {
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
}
- LocationRequest sanitized = new LocationRequest(request);
+ LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
- sanitized.setLowPowerMode(false);
+ sanitized.setLowPower(false);
}
if (permissionLevel < PERMISSION_FINE) {
- switch (sanitized.getQuality()) {
+ switch (request.getQuality()) {
case LocationRequest.ACCURACY_FINE:
sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
break;
@@ -634,24 +633,21 @@ public class LocationManagerService extends ILocationManager.Stub {
break;
}
- if (sanitized.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.setInterval(FASTEST_COARSE_INTERVAL_MS);
+ if (request.getIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setIntervalMillis(FASTEST_COARSE_INTERVAL_MS);
}
- if (sanitized.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitized.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
+ if (request.getMinUpdateIntervalMillis() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.clearMinUpdateIntervalMillis();
}
}
- if (sanitized.getFastestInterval() > sanitized.getInterval()) {
- sanitized.setFastestInterval(request.getInterval());
- }
- if (sanitized.getWorkSource() != null) {
- if (sanitized.getWorkSource().isEmpty()) {
+ if (request.getWorkSource() != null) {
+ if (request.getWorkSource().isEmpty()) {
sanitized.setWorkSource(null);
- } else if (sanitized.getWorkSource().getPackageName(0) == null) {
+ } else if (request.getWorkSource().getPackageName(0) == null) {
Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
sanitized.setWorkSource(null);
} else {
- List<WorkChain> workChains = sanitized.getWorkSource().getWorkChains();
+ List<WorkChain> workChains = request.getWorkSource().getWorkChains();
if (workChains != null && !workChains.isEmpty() && workChains.get(
0).getAttributionTag() == null) {
Log.w(TAG,
@@ -661,7 +657,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- return sanitized;
+ return sanitized.build();
}
@Override
@@ -679,8 +675,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public Location getLastLocation(LocationRequest request, String packageName,
- String attributionTag) {
+ public Location getLastLocation(String provider, String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
@@ -690,15 +685,12 @@ public class LocationManagerService extends ILocationManager.Stub {
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateAndSanitizeLocationRequest(request, permissionLevel);
-
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
if (manager == null) {
return null;
}
- Location location = manager.getLastLocation(identity, permissionLevel,
- request.isLocationSettingsIgnored());
+ Location location = manager.getLastLocation(identity, permissionLevel, false);
// lastly - note app ops
if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
@@ -710,7 +702,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void getCurrentLocation(LocationRequest request,
+ public void getCurrentLocation(String provider, LocationRequest request,
ICancellationSignal cancellationTransport, ILocationCallback consumer,
String packageName, String attributionTag, String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
@@ -725,9 +717,9 @@ public class LocationManagerService extends ILocationManager.Stub {
request = validateAndSanitizeLocationRequest(request, permissionLevel);
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
- "provider \"" + request.getProvider() + "\" does not exist");
+ "provider \"" + provider + "\" does not exist");
manager.getCurrentLocation(request, identity, permissionLevel, cancellationTransport,
consumer);
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 1815a8554705..830548b044a6 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -291,7 +291,7 @@ class LocationProviderManager extends
@Override
protected final ListenerOperation<LocationTransport> onActive() {
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
}
onHighPowerUsageChanged();
@@ -301,7 +301,7 @@ class LocationProviderManager extends
@Override
protected final ListenerOperation<LocationTransport> onInactive() {
onHighPowerUsageChanged();
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
return null;
@@ -343,7 +343,7 @@ class LocationProviderManager extends
if (isUsingHighPower != mIsUsingHighPower) {
mIsUsingHighPower = isUsingHighPower;
- if (!getRequest().getHideFromAppOps()) {
+ if (!getRequest().isHiddenFromAppOps()) {
if (mIsUsingHighPower) {
mLocationAttributionHelper.reportHighPowerLocationStart(
getIdentity(), getName(), getKey());
@@ -362,7 +362,7 @@ class LocationProviderManager extends
}
return isActive()
- && getRequest().getInterval() < MAX_HIGH_POWER_INTERVAL_MS
+ && getRequest().getIntervalMillis() < MAX_HIGH_POWER_INTERVAL_MS
&& getProperties().mPowerRequirement == Criteria.POWER_HIGH;
}
@@ -448,26 +448,26 @@ class LocationProviderManager extends
}
private LocationRequest calculateProviderLocationRequest() {
- LocationRequest newRequest = new LocationRequest(super.getRequest());
+ LocationRequest.Builder builder = new LocationRequest.Builder(super.getRequest());
- if (newRequest.isLocationSettingsIgnored()) {
+ if (super.getRequest().isLocationSettingsIgnored()) {
// if we are not currently allowed use location settings ignored, disable it
if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
null, getIdentity())) {
- newRequest.setLocationSettingsIgnored(false);
+ builder.setLocationSettingsIgnored(false);
}
}
- if (!newRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
+ if (!super.getRequest().isLocationSettingsIgnored() && !isThrottlingExempt()) {
// throttle in the background
if (!mForeground) {
- newRequest.setInterval(Math.max(newRequest.getInterval(),
+ builder.setIntervalMillis(Math.max(super.getRequest().getIntervalMillis(),
mSettingsHelper.getBackgroundThrottleIntervalMs()));
}
}
- return newRequest;
+ return builder.build();
}
private boolean isThrottlingExempt() {
@@ -635,14 +635,15 @@ class LocationProviderManager extends
long deltaMs = NANOSECONDS.toMillis(
location.getElapsedRealtimeNanos()
- mLastLocation.getElapsedRealtimeNanos());
- if (deltaMs < getRequest().getFastestInterval() - MAX_FASTEST_INTERVAL_JITTER_MS) {
+ if (deltaMs < getRequest().getMinUpdateIntervalMillis()
+ - MAX_FASTEST_INTERVAL_JITTER_MS) {
return null;
}
// check smallest displacement
- double smallestDisplacement = getRequest().getSmallestDisplacement();
- if (smallestDisplacement > 0.0 && location.distanceTo(mLastLocation)
- <= smallestDisplacement) {
+ double smallestDisplacementM = getRequest().getMinUpdateDistanceMeters();
+ if (smallestDisplacementM > 0.0 && location.distanceTo(mLastLocation)
+ <= smallestDisplacementM) {
return null;
}
}
@@ -692,7 +693,7 @@ class LocationProviderManager extends
if (success) {
// check num updates - if successful then this function will always be run
// from the same thread, and no additional synchronization is necessary
- boolean remove = ++mNumLocationsDelivered >= getRequest().getNumUpdates();
+ boolean remove = ++mNumLocationsDelivered >= getRequest().getMaxUpdates();
if (remove) {
if (D) {
Log.d(TAG, "removing " + getIdentity() + " from " + mName
@@ -1326,10 +1327,10 @@ class LocationProviderManager extends
public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
int permissionLevel, ICancellationSignal cancellationTransport,
ILocationCallback callback) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
- if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
- request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+ if (request.getDurationMillis() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+ request = new LocationRequest.Builder(request)
+ .setDurationMillis(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS)
+ .build();
}
GetCurrentLocationListenerRegistration registration =
@@ -1404,8 +1405,6 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
@@ -1424,8 +1423,6 @@ class LocationProviderManager extends
public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
synchronized (mLock) {
long identity = Binder.clearCallingIdentity();
try {
@@ -1517,17 +1514,17 @@ class LocationProviderManager extends
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ mName,
registration.getRequest(),
key instanceof PendingIntent,
- key instanceof IBinder,
- /* geofence= */ null,
- registration.isForeground());
+ /* geofence= */ key instanceof IBinder,
+ null, registration.isForeground());
mLocationRequestStatistics.startRequesting(
registration.getIdentity().getPackageName(),
registration.getIdentity().getAttributionTag(),
mName,
- registration.getRequest().getInterval(),
+ registration.getRequest().getIntervalMillis(),
registration.isForeground());
}
@@ -1547,11 +1544,11 @@ class LocationProviderManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ mName,
registration.getRequest(),
key instanceof PendingIntent,
- key instanceof IBinder,
- /* geofence= */ null,
- registration.isForeground());
+ /* geofence= */ key instanceof IBinder,
+ null, registration.isForeground());
}
@GuardedBy("mLock")
@@ -1643,15 +1640,20 @@ class LocationProviderManager extends
for (Registration registration : registrations) {
LocationRequest locationRequest = registration.getRequest();
+ // passive requests do not contribute to the provider
+ if (locationRequest.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
+ continue;
+ }
+
if (locationRequest.isLocationSettingsIgnored()) {
providerRequest.setLocationSettingsIgnored(true);
}
- if (!locationRequest.isLowPowerMode()) {
+ if (!locationRequest.isLowPower()) {
providerRequest.setLowPowerMode(false);
}
providerRequest.setInterval(
- Math.min(locationRequest.getInterval(), providerRequest.getInterval()));
+ Math.min(locationRequest.getIntervalMillis(), providerRequest.getInterval()));
providerRegistrations.add(registration);
}
@@ -1674,7 +1676,7 @@ class LocationProviderManager extends
}
for (int i = 0; i < registrationsSize; i++) {
LocationRequest request = providerRegistrations.get(i).getRequest();
- if (request.getInterval() <= thresholdIntervalMs) {
+ if (request.getIntervalMillis() <= thresholdIntervalMs) {
providerRequest.getWorkSource().add(providerRegistrations.get(i).getWorkSource());
}
}
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index d4999ab8be0a..92ef5b7c73a8 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -20,11 +20,16 @@ import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.Binder;
+import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
import com.android.server.location.util.Injector;
+import java.util.ArrayList;
+import java.util.Collection;
+
class PassiveLocationProviderManager extends LocationProviderManager {
PassiveLocationProviderManager(Context context, Injector injector) {
@@ -57,4 +62,20 @@ class PassiveLocationProviderManager extends LocationProviderManager {
}
}
}
+
+ @Override
+ protected ProviderRequest mergeRequests(Collection<Registration> registrations) {
+ ProviderRequest.Builder providerRequest = new ProviderRequest.Builder()
+ .setInterval(0);
+
+ ArrayList<LocationRequest> requests = new ArrayList<>(registrations.size());
+ for (Registration registration : registrations) {
+ requests.add(registration.getRequest());
+ if (registration.getRequest().isLocationSettingsIgnored()) {
+ providerRequest.setLocationSettingsIgnored(true);
+ }
+ }
+
+ return providerRequest.setLocationRequests(requests).build();
+ }
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 2d7f02873b8f..7f02b2a807c3 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -16,6 +16,7 @@
package com.android.server.location.geofence;
+import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.KEY_PROXIMITY_ENTERING;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
@@ -350,11 +351,11 @@ public class GeofenceManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ null,
/* LocationRequest= */ null,
/* hasListener= */ false,
true,
- registration.getRequest(),
- true);
+ registration.getRequest(), true);
}
@Override
@@ -363,16 +364,17 @@ public class GeofenceManager extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ null,
/* LocationRequest= */ null,
/* hasListener= */ false,
true,
- registration.getRequest(),
- true);
+ registration.getRequest(), true);
}
@Override
protected boolean registerWithService(LocationRequest locationRequest) {
- getLocationManager().requestLocationUpdates(locationRequest, DIRECT_EXECUTOR, this);
+ getLocationManager().requestLocationUpdates(FUSED_PROVIDER, locationRequest,
+ DIRECT_EXECUTOR, this);
return true;
}
@@ -417,13 +419,11 @@ public class GeofenceManager extends
intervalMs = mSettingsHelper.getBackgroundThrottleProximityAlertIntervalMs();
}
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- LocationManager.FUSED_PROVIDER, intervalMs, 0, false);
- request.setFastestInterval(0);
- request.setHideFromAppOps(true);
- request.setWorkSource(workSource);
-
- return request;
+ return new LocationRequest.Builder(intervalMs)
+ .setMinUpdateIntervalMillis(0)
+ .setHiddenFromAppOps(true)
+ .setWorkSource(workSource)
+ .build();
}
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 a4486d7b5898..bd4fc135d2bb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -45,6 +45,7 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -700,9 +701,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
Context.LOCATION_SERVICE);
String provider;
LocationChangeListener locationListener;
- LocationRequest locationRequest = new LocationRequest()
- .setInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS)
- .setFastestInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
+ LocationRequest.Builder locationRequest = new LocationRequest.Builder(
+ LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
if (independentFromGnss) {
// For fast GNSS TTFF
@@ -716,8 +716,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
}
- locationRequest.setProvider(provider);
-
// Ignore location settings if in emergency mode. This is only allowed for
// isUserEmergency request (introduced in HAL v2.0), or HAL v1.1.
if (mNIHandler.getInEmergency()) {
@@ -735,8 +733,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
provider, durationMillis));
try {
- locationManager.requestLocationUpdates(locationRequest,
- locationListener, mHandler.getLooper());
+ locationManager.requestLocationUpdates(provider, locationRequest.build(),
+ new HandlerExecutor(mHandler), locationListener);
locationListener.mNumLocationUpdateRequest++;
mHandler.postDelayed(() -> {
if (--locationListener.mNumLocationUpdateRequest == 0) {
@@ -1952,20 +1950,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// listen for PASSIVE_PROVIDER updates
LocationManager locManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- long minTime = 0;
- float minDistance = 0;
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(
- LocationManager.PASSIVE_PROVIDER,
- minTime,
- minDistance,
- false);
- // Don't keep track of this request since it's done on behalf of other clients
- // (which are kept track of separately).
- request.setHideFromAppOps(true);
locManager.requestLocationUpdates(
- request,
- new NetworkLocationListener(),
- getLooper());
+ LocationManager.PASSIVE_PROVIDER,
+ new LocationRequest.Builder(0)
+ .setHiddenFromAppOps(true)
+ .build(),
+ new HandlerExecutor(this),
+ new NetworkLocationListener());
updateEnabled();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 0815d46a735d..37db02337a2f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -141,11 +141,11 @@ public class GnssMeasurementsProvider extends
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
@Override
@@ -154,11 +154,11 @@ public class GnssMeasurementsProvider extends
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
/**
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 19f79273c992..68813b3e0777 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -71,11 +71,11 @@ public class GnssStatusProvider extends GnssListenerMultiplexer<Void, IGnssStatu
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
- registration.isForeground());
+ null,
+ null,
+ true,
+ false,
+ null, registration.isForeground());
}
@Override
@@ -84,10 +84,11 @@ public class GnssStatusProvider extends GnssListenerMultiplexer<Void, IGnssStatu
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
- /* LocationRequest= */ null,
- /* hasListener= */ true,
- /* hasIntent= */ false,
- /* geofence= */ null,
+ null,
+ null,
+ true,
+ false,
+ null,
registration.isForeground());
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 8a6b8aa1e463..feb4fbd1de31 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -88,7 +88,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
private boolean mServiceRegistered = false;
@GuardedBy("mRegistrations")
- private TMergedRequest mCurrentRequest;
+ @Nullable private TMergedRequest mCurrentRequest;
/**
* Should be implemented to register with the backing service with the given merged request, and
diff --git a/services/core/java/com/android/server/location/util/LocationUsageLogger.java b/services/core/java/com/android/server/location/util/LocationUsageLogger.java
index 2e50d4fecf15..a229964d8701 100644
--- a/services/core/java/com/android/server/location/util/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/util/LocationUsageLogger.java
@@ -49,7 +49,7 @@ public class LocationUsageLogger {
* Log a location API usage event.
*/
public void logLocationApiUsage(int usageType, int apiInUse,
- String packageName, LocationRequest locationRequest,
+ String packageName, String provider, LocationRequest locationRequest,
boolean hasListener, boolean hasIntent,
Geofence geofence, boolean foreground) {
try {
@@ -64,22 +64,22 @@ public class LocationUsageLogger {
usageType, apiInUse, packageName,
isLocationRequestNull
? LocationStatsEnums.PROVIDER_UNKNOWN
- : bucketizeProvider(locationRequest.getProvider()),
+ : bucketizeProvider(provider),
isLocationRequestNull
? LocationStatsEnums.QUALITY_UNKNOWN
: locationRequest.getQuality(),
isLocationRequestNull
? LocationStatsEnums.INTERVAL_UNKNOWN
- : bucketizeInterval(locationRequest.getInterval()),
+ : bucketizeInterval(locationRequest.getIntervalMillis()),
isLocationRequestNull
? LocationStatsEnums.DISTANCE_UNKNOWN
: bucketizeDistance(
- locationRequest.getSmallestDisplacement()),
- isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
+ locationRequest.getMinUpdateDistanceMeters()),
+ isLocationRequestNull ? 0 : locationRequest.getMaxUpdates(),
// only log expireIn for USAGE_STARTED
isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
? LocationStatsEnums.EXPIRATION_UNKNOWN
- : bucketizeExpireIn(locationRequest.getExpireIn()),
+ : bucketizeExpireIn(locationRequest.getDurationMillis()),
getCallbackType(apiInUse, hasListener, hasIntent),
isGeofenceNull
? LocationStatsEnums.RADIUS_UNKNOWN
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3cafafffc62a..05f280884432 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,7 +16,6 @@
package com.android.server.net;
-import static android.Manifest.permission.NETWORK_STACK;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.annotation.NonNull;
@@ -24,10 +23,8 @@ import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -41,6 +38,7 @@ import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
@@ -63,7 +61,7 @@ public class LockdownVpnTracker {
/** Number of VPN attempts before waiting for user intervention. */
private static final int MAX_ERROR_COUNT = 4;
- private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
+ public static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
@NonNull private final Context mContext;
@NonNull private final ConnectivityService mConnService;
@@ -104,13 +102,6 @@ public class LockdownVpnTracker {
mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0);
}
- private BroadcastReceiver mResetReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reset();
- }
- };
-
/**
* Watch for state changes to both active egress network, kicking off a VPN
* connection when ready, or setting firewall rules once VPN is connected.
@@ -200,9 +191,6 @@ public class LockdownVpnTracker {
mVpn.setEnableTeardown(false);
mVpn.setLockdown(true);
-
- final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
- mContext.registerReceiver(mResetReceiver, resetFilter, NETWORK_STACK, mHandler);
handleStateChangedLocked();
}
@@ -222,10 +210,14 @@ public class LockdownVpnTracker {
mVpn.setLockdown(false);
hideNotification();
- mContext.unregisterReceiver(mResetReceiver);
mVpn.setEnableTeardown(true);
}
+ /**
+ * Reset VPN lockdown tracker. Called by ConnectivityService when receiving
+ * {@link #ACTION_LOCKDOWN_RESET} pending intent.
+ */
+ @GuardedBy("mConnService.mVpns")
public void reset() {
Slog.d(TAG, "reset()");
synchronized (mStateLock) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 87dedfe9c84a..bcb5fdba7a3b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2606,6 +2606,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
DexMetadataHelper.buildDexMetadataPathForApk(targetFile.getName()));
stageFileLocked(dexMetadataFile, targetDexMetadataFile);
+ maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile);
}
private static ApkChecksum[] createApkChecksums(String splitName,
@@ -2662,20 +2663,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@GuardedBy("mLock")
- private void inheritFileLocked(File origFile) {
- mResolvedInheritedFiles.add(origFile);
-
+ private void maybeInheritFsveritySignatureLocked(File origFile) {
// Inherit the fsverity signature file if present.
final File fsveritySignatureFile = new File(
VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
if (fsveritySignatureFile.exists()) {
mResolvedInheritedFiles.add(fsveritySignatureFile);
}
+ }
+
+ @GuardedBy("mLock")
+ private void inheritFileLocked(File origFile) {
+ mResolvedInheritedFiles.add(origFile);
+
+ maybeInheritFsveritySignatureLocked(origFile);
+
// Inherit the dex metadata if present.
final File dexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(origFile);
if (dexMetadataFile != null) {
mResolvedInheritedFiles.add(dexMetadataFile);
+ maybeInheritFsveritySignatureLocked(dexMetadataFile);
}
// Inherit the digests if present.
final File digestsFile = ApkChecksums.findDigestsForFile(origFile);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 999bbc9ecf4e..5850dc012226 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1849,7 +1849,7 @@ public class PackageManagerService extends IPackageManager.Stub
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
- mPermissionManager.writeStateToPackageSettingsTEMP();
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -3520,7 +3520,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
- mPermissionManager.readStateFromPackageSettingsTEMP();
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
@@ -19863,7 +19863,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
if (removeExisting && existing != null) {
- mSettings.removeFiltersLPw(pir, filter, existing);
+ Settings.removeFilters(pir, filter, existing);
}
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
@@ -19964,7 +19964,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (existing != null) {
- mSettings.removeFiltersLPw(pir, filter, existing);
+ Settings.removeFilters(pir, filter, existing);
}
}
}
@@ -21827,7 +21827,7 @@ public class PackageManagerService extends IPackageManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- mPermissionManager.writeStateToPackageSettingsTEMP();
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
@@ -23707,7 +23707,7 @@ public class PackageManagerService extends IPackageManager.Stub
mDirtyUsers.remove(userId);
mUserNeedsBadging.delete(userId);
mPermissionManager.onUserRemoved(userId);
- mPermissionManager.writeStateToPackageSettingsTEMP();
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.removeUserLPw(userId);
mPendingBroadcasts.remove(userId);
mInstantAppRegistry.onUserRemovedLPw(userId);
@@ -23808,9 +23808,9 @@ public class PackageManagerService extends IPackageManager.Stub
boolean readPermissionStateForUser(@UserIdInt int userId) {
synchronized (mPackages) {
- mPermissionManager.writeStateToPackageSettingsTEMP();
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
- mPermissionManager.readStateFromPackageSettingsTEMP();
+ mPermissionManager.readPermissionsStateFromPackageSettingsTEMP();
return mPmInternal.isPermissionUpgradeNeeded(userId);
}
}
@@ -25824,12 +25824,12 @@ public class PackageManagerService extends IPackageManager.Stub
/**
* Temporary method that wraps mSettings.writeLPr() and calls
- * mPermissionManager.writeStateToPackageSettingsTEMP() beforehand.
+ * mPermissionManager.writePermissionsStateToPackageSettingsTEMP() beforehand.
*
* TODO(zhanghai): This should be removed once we finish migration of permission storage.
*/
private void writeSettingsLPrTEMP() {
- mPermissionManager.writeStateToPackageSettingsTEMP();
+ mPermissionManager.writePermissionsStateToPackageSettingsTEMP();
mSettings.writeLPr();
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 74bc49dd9108..f801702f7ddd 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3183,7 +3183,7 @@ public final class Settings {
}
}
- void removeFiltersLPw(@NonNull PreferredIntentResolver pir,
+ static void removeFilters(@NonNull PreferredIntentResolver pir,
@NonNull IntentFilter filter, @NonNull List<PreferredActivity> existing) {
if (PackageManagerService.DEBUG_PREFERRED) {
Slog.i(TAG, existing.size() + " preferred matches for:");
@@ -3405,7 +3405,7 @@ public final class Settings {
final PreferredIntentResolver pir = editPreferredActivitiesLPw(userId);
final List<PreferredActivity> existing = pir.findFilters(filter);
if (existing != null) {
- removeFiltersLPw(pir, filter, existing);
+ removeFilters(pir, filter, existing);
}
PreferredActivity pa = new PreferredActivity(filter, systemMatch, set, cn, true);
pir.addFilter(pa);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 865b8a1e97eb..962638b4f63c 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -36,7 +36,6 @@ import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.util.ArrayUtils;
import com.android.server.pm.DumpState;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageSettingBase;
@@ -140,10 +139,6 @@ public final class BasePermission {
this.perm = perm;
}
- public boolean hasGids() {
- return !ArrayUtils.isEmpty(gids);
- }
-
public int[] computeGids(int userId) {
if (perUser) {
final int[] userGids = new int[gids.length];
@@ -424,9 +419,9 @@ public final class BasePermission {
}
public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
- UidPermissionState uidState) {
+ PermissionsState permsState) {
int index = pkg.getRequestedPermissions().indexOf(name);
- if (!uidState.hasRequestedPermission(name) && index == -1) {
+ if (!permsState.hasRequestedPermission(name) && index == -1) {
throw new SecurityException("Package " + pkg.getPackageName()
+ " has not requested permission " + name);
}
diff --git a/services/core/java/com/android/server/pm/permission/DevicePermissionState.java b/services/core/java/com/android/server/pm/permission/DevicePermissionState.java
deleted file mode 100644
index b9456acfced5..000000000000
--- a/services/core/java/com/android/server/pm/permission/DevicePermissionState.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2020 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.server.pm.permission;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * Permission state for this device.
- */
-public final class DevicePermissionState {
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<UserPermissionState> mUserStates = new SparseArray<>();
-
- @NonNull
- private final Object mLock;
-
- public DevicePermissionState(@NonNull Object lock) {
- mLock = lock;
- }
-
- @Nullable
- public UserPermissionState getUserState(@UserIdInt int userId) {
- synchronized (mLock) {
- return mUserStates.get(userId);
- }
- }
-
- @NonNull
- public UserPermissionState getOrCreateUserState(@UserIdInt int userId) {
- synchronized (mLock) {
- UserPermissionState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = new UserPermissionState(mLock);
- mUserStates.put(userId, userState);
- }
- return userState;
- }
- }
-
- public void removeUserState(@UserIdInt int userId) {
- synchronized (mLock) {
- mUserStates.delete(userId);
- }
- }
-
- public int[] getUserIds() {
- synchronized (mLock) {
- final int userStatesSize = mUserStates.size();
- final int[] userIds = new int[userStatesSize];
- for (int i = 0; i < userStatesSize; i++) {
- final int userId = mUserStates.keyAt(i);
- userIds[i] = userId;
- }
- return userIds;
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 75e5944b3cb4..1cfc5b135cfa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -148,9 +148,12 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal.Default
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
+import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
+import libcore.util.EmptyArray;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -223,8 +226,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
- @NonNull
- private final DevicePermissionState mState;
+ /** Maps from App ID to PermissionsState */
+ private final SparseArray<PermissionsState> mAppIdStates = new SparseArray<>();
/** Permission controller: User space permission management */
private PermissionControllerManager mPermissionControllerManager;
@@ -392,7 +395,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
mSettings = new PermissionSettings(mLock);
- mState = new DevicePermissionState(mLock);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mHandlerThread = new ServiceThread(TAG,
@@ -679,12 +681,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return 0;
}
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return 0;
}
- return uidState.getPermissionFlags(permName);
+ return permissionsState.getPermissionFlags(permName, userId);
}
@Override
@@ -786,13 +788,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return;
}
- final boolean hadState = uidState.getPermissionState(permName) != null;
+ final boolean hadState =
+ permissionsState.getRuntimePermissionState(permName, userId) != null;
if (!hadState) {
boolean isRequested = false;
// Fast path, the current package has requested the permission.
@@ -819,18 +822,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
final boolean permissionUpdated =
- uidState.updatePermissionFlags(bp, flagMask, flagValues);
+ permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
if (permissionUpdated && bp.isRuntime()) {
notifyRuntimePermissionStateChanged(packageName, userId);
}
if (permissionUpdated && callback != null) {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
- if (!bp.isRuntime()) {
+ if (permissionsState.getInstallPermissionState(permName) != null) {
int userUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
callback.onInstallPermissionUpdatedNotifyListener(userUid);
- } else {
- callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, pkg.getUid());
+ } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
+ || hadState) {
+ callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false,
+ pkg.getUid());
}
}
}
@@ -863,14 +868,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final boolean[] changed = new boolean[1];
mPackageManagerInt.forEachPackage(pkg -> {
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- changed[0] |= uidState.updatePermissionFlagsForAllPermissions(
- effectiveFlagMask, effectiveFlagValues);
+ changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
+ userId, effectiveFlagMask, effectiveFlagValues);
mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
});
@@ -922,20 +926,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return PackageManager.PERMISSION_DENIED;
}
- if (checkSinglePermissionInternal(uid, uidState, permissionName)) {
+ if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null
- && checkSinglePermissionInternal(uid, uidState, fullerPermissionName)) {
+ && checkSinglePermissionInternal(uid, permissionsState, fullerPermissionName)) {
return PackageManager.PERMISSION_GRANTED;
}
@@ -943,8 +946,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private boolean checkSinglePermissionInternal(int uid,
- @NonNull UidPermissionState uidState, @NonNull String permissionName) {
- if (!uidState.hasPermission(permissionName)) {
+ @NonNull PermissionsState permissionsState, @NonNull String permissionName) {
+ if (!permissionsState.hasPermission(permissionName, UserHandle.getUserId(uid))) {
return false;
}
@@ -1138,9 +1141,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return null;
}
@@ -1161,7 +1164,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int i = 0; i < permissionCount; i++) {
final String permissionName = pkg.getRequestedPermissions().get(i);
final int currentFlags =
- uidState.getPermissionFlags(permissionName);
+ permissionsState.getPermissionFlags(permissionName, userId);
if ((currentFlags & queryFlags) != 0) {
if (whitelistedPermissions == null) {
whitelistedPermissions = new ArrayList<>();
@@ -1450,14 +1453,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1470,7 +1472,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
- final int flags = uidState.getPermissionFlags(permName);
+ final int flags = permissionsState.getPermissionFlags(permName, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
Log.e(TAG, "Cannot grant system fixed permission "
+ permName + " for package " + packageName);
@@ -1500,9 +1502,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
- // TODO(zhanghai): We are breaking the behavior above by making all permission state
- // per-user. It isn't documented behavior and relatively rarely used anyway.
- if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
+ if (permissionsState.grantInstallPermission(bp)
+ != PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
callback.onInstallPermissionGranted();
}
@@ -1520,7 +1521,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
- final int result = uidState.grantPermission(bp);
+ final int result = permissionsState.grantRuntimePermission(bp, userId);
switch (result) {
case PERMISSION_OPERATION_FAILURE: {
return;
@@ -1616,14 +1617,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, uidState);
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, permissionsState);
// If a permission review is required for legacy apps we represent
// their permissions as always granted runtime ones since we need
@@ -1634,7 +1634,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
- final int flags = uidState.getPermissionFlags(permName);
+ final int flags = permissionsState.getPermissionFlags(permName, userId);
// Only the system may revoke SYSTEM_FIXED permissions.
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
&& UserHandle.getCallingAppId() != Process.SYSTEM_UID) {
@@ -1649,9 +1649,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
- // TODO(zhanghai): We are breaking the behavior above by making all permission state
- // per-user. It isn't documented behavior and relatively rarely used anyway.
- if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
+ if (permissionsState.revokeInstallPermission(bp)
+ != PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
mDefaultPermissionCallback.onInstallPermissionRevoked();
}
@@ -1660,11 +1659,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Permission is already revoked, no need to do anything.
- if (!uidState.hasPermission(permName)) {
+ if (!permissionsState.hasRuntimePermission(permName, userId)) {
return;
}
- if (uidState.revokePermission(bp) == PERMISSION_OPERATION_FAILURE) {
+ if (permissionsState.revokeRuntimePermission(bp, userId)
+ == PERMISSION_OPERATION_FAILURE) {
return;
}
@@ -2466,7 +2466,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void onUserRemoved(@UserIdInt int userId) {
synchronized (mLock) {
- mState.removeUserState(userId);
+ final int appIdStatesSize = mAppIdStates.size();
+ for (int i = 0; i < appIdStatesSize; i++) {
+ PermissionsState permissionsState = mAppIdStates.valueAt(i);
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mSettings.getPermission(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ }
+ }
}
}
@@ -2477,18 +2489,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return Collections.emptySet();
}
- final UidPermissionState uidState = getUidState(ps, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return Collections.emptySet();
}
if (!ps.getInstantApp(userId)) {
- return uidState.getPermissions();
+ return permissionsState.getPermissions(userId);
} else {
// Install permission state is shared among all users, but instant app state is
// per-user, so we can only filter it here unless we make install permission state
// per-user as well.
- final Set<String> instantPermissions = new ArraySet<>(uidState.getPermissions());
+ final Set<String> instantPermissions = new ArraySet<>(permissionsState.getPermissions(
+ userId));
instantPermissions.removeIf(permissionName -> {
BasePermission permission = mSettings.getPermission(permissionName);
if (permission == null) {
@@ -2520,12 +2533,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return null;
}
- final UidPermissionState uidState = getUidState(ps, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
+ final PermissionsState permissionsState = getPermissionsState(ps);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + packageName);
return null;
}
- return uidState.computeGids(userId);
+ return permissionsState.computeGids(userId);
}
/**
@@ -2562,17 +2575,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (ps == null) {
return;
}
+ final PermissionsState permissionsState = getOrCreatePermissionsState(ps);
final int[] userIds = getAllUserIds();
boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;
- for (final int userId : userIds) {
- final UserPermissionState userState = mState.getOrCreateUserState(userId);
- final UidPermissionState uidState = userState.getOrCreateUidState(ps.getAppId());
-
- if (uidState.isMissing()) {
+ for (int userId : userIds) {
+ if (permissionsState.isMissing(userId)) {
Collection<String> requestedPermissions;
int targetSdkVersion;
if (!ps.isSharedUser()) {
@@ -2600,220 +2611,222 @@ public class PermissionManagerService extends IPermissionManager.Stub {
&& permission.isRuntime() && !permission.isRemoved()) {
if (permission.isHardOrSoftRestricted()
|| permission.isImmutablyRestricted()) {
- uidState.updatePermissionFlags(permission,
+ permissionsState.updatePermissionFlags(permission, userId,
FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,
FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT);
}
if (targetSdkVersion < Build.VERSION_CODES.M) {
- uidState.updatePermissionFlags(permission,
+ permissionsState.updatePermissionFlags(permission, userId,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
| PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
| PackageManager.FLAG_PERMISSION_REVOKED_COMPAT);
- uidState.grantPermission(permission);
+ permissionsState.grantRuntimePermission(permission, userId);
}
}
}
- uidState.setMissing(false);
+ permissionsState.setMissing(false, userId);
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
+ }
- UidPermissionState origState = uidState;
+ PermissionsState origPermissions = permissionsState;
- boolean changedInstallPermission = false;
+ boolean changedInstallPermission = false;
- if (replace) {
- userState.setInstallPermissionsFixed(ps.name, false);
- if (!ps.isSharedUser()) {
- origState = new UidPermissionState(uidState);
- uidState.reset();
- } else {
- // We need to know only about runtime permission changes since the
- // calling code always writes the install permissions state but
- // the runtime ones are written only if changed. The only cases of
- // changed runtime permissions here are promotion of an install to
- // runtime and revocation of a runtime from a shared user.
- synchronized (mLock) {
- if (revokeUnusedSharedUserPermissionsLocked(
- ps.getSharedUser().getPackages(), uidState)) {
- updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
- runtimePermissionsRevoked = true;
- }
+ if (replace) {
+ ps.setInstallPermissionsFixed(false);
+ if (!ps.isSharedUser()) {
+ origPermissions = new PermissionsState(permissionsState);
+ permissionsState.reset();
+ } else {
+ // We need to know only about runtime permission changes since the
+ // calling code always writes the install permissions state but
+ // the runtime ones are written only if changed. The only cases of
+ // changed runtime permissions here are promotion of an install to
+ // runtime and revocation of a runtime from a shared user.
+ synchronized (mLock) {
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
+ ps.getSharedUser().getPackages(), permissionsState, userIds);
+ if (!ArrayUtils.isEmpty(updatedUserIds)) {
+ runtimePermissionsRevoked = true;
}
}
}
+ }
- uidState.setGlobalGids(mGlobalGids);
+ permissionsState.setGlobalGids(mGlobalGids);
- ArraySet<String> newImplicitPermissions = new ArraySet<>();
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
- final int N = pkg.getRequestedPermissions().size();
- for (int i = 0; i < N; i++) {
- final String permName = pkg.getRequestedPermissions().get(i);
- final BasePermission bp = mSettings.getPermission(permName);
- final boolean appSupportsRuntimePermissions =
- pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
- String upgradedActivityRecognitionPermission = null;
+ final int N = pkg.getRequestedPermissions().size();
+ for (int i = 0; i < N; i++) {
+ final String permName = pkg.getRequestedPermissions().get(i);
+ final BasePermission bp = mSettings.getPermission(permName);
+ final boolean appSupportsRuntimePermissions =
+ pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
+ String upgradedActivityRecognitionPermission = null;
- if (DEBUG_INSTALL && bp != null) {
- Log.i(TAG, "Package " + pkg.getPackageName()
- + " checking " + permName + ": " + bp);
- }
+ if (DEBUG_INSTALL && bp != null) {
+ Log.i(TAG, "Package " + pkg.getPackageName()
+ + " checking " + permName + ": " + bp);
+ }
- if (bp == null || getSourcePackageSetting(bp) == null) {
- if (packageOfInterest == null || packageOfInterest.equals(
- pkg.getPackageName())) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Unknown permission " + permName
- + " in package " + pkg.getPackageName());
- }
+ if (bp == null || getSourcePackageSetting(bp) == null) {
+ if (packageOfInterest == null || packageOfInterest.equals(
+ pkg.getPackageName())) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Unknown permission " + permName
+ + " in package " + pkg.getPackageName());
}
- continue;
}
+ continue;
+ }
- // Cache newImplicitPermissions before modifing permissionsState as for the shared
- // uids the original and new state are the same object
- if (!origState.hasRequestedPermission(permName)
- && (pkg.getImplicitPermissions().contains(permName)
- || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
- if (pkg.getImplicitPermissions().contains(permName)) {
- // If permName is an implicit permission, try to auto-grant
- newImplicitPermissions.add(permName);
+ // Cache newImplicitPermissions before modifing permissionsState as for the shared
+ // uids the original and new state are the same object
+ if (!origPermissions.hasRequestedPermission(permName)
+ && (pkg.getImplicitPermissions().contains(permName)
+ || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
+ if (pkg.getImplicitPermissions().contains(permName)) {
+ // If permName is an implicit permission, try to auto-grant
+ newImplicitPermissions.add(permName);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
- }
- } else {
- // Special case for Activity Recognition permission. Even if AR permission
- // is not an implicit permission we want to add it to the list (try to
- // auto-grant it) if the app was installed on a device before AR permission
- // was split, regardless of if the app now requests the new AR permission
- // or has updated its target SDK and AR is no longer implicit to it.
- // This is a compatibility workaround for apps when AR permission was
- // split in Q.
- final List<SplitPermissionInfoParcelable> permissionList =
- getSplitPermissions();
- int numSplitPerms = permissionList.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
- String splitPermName = sp.getSplitPermission();
- if (sp.getNewPermissions().contains(permName)
- && origState.hasInstallPermission(splitPermName)) {
- upgradedActivityRecognitionPermission = splitPermName;
- newImplicitPermissions.add(permName);
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
+ }
+ } else {
+ // Special case for Activity Recognition permission. Even if AR permission
+ // is not an implicit permission we want to add it to the list (try to
+ // auto-grant it) if the app was installed on a device before AR permission
+ // was split, regardless of if the app now requests the new AR permission
+ // or has updated its target SDK and AR is no longer implicit to it.
+ // This is a compatibility workaround for apps when AR permission was
+ // split in Q.
+ final List<SplitPermissionInfoParcelable> permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
+ String splitPermName = sp.getSplitPermission();
+ if (sp.getNewPermissions().contains(permName)
+ && origPermissions.hasInstallPermission(splitPermName)) {
+ upgradedActivityRecognitionPermission = splitPermName;
+ newImplicitPermissions.add(permName);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for "
- + pkg.getPackageName());
- }
- break;
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for "
+ + pkg.getPackageName());
}
+ break;
}
}
}
+ }
- // TODO(b/140256621): The package instant app method has been removed
- // as part of work in b/135203078, so this has been commented out in the meantime
- // Limit ephemeral apps to ephemeral allowed permissions.
- // if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
- // if (DEBUG_PERMISSIONS) {
- // Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
- // + " for package " + pkg.getPackageName());
- // }
- // continue;
- // }
-
- if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
- if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.getName()
- + " for package " + pkg.getPackageName());
- }
- continue;
+ // TODO(b/140256621): The package instant app method has been removed
+ // as part of work in b/135203078, so this has been commented out in the meantime
+ // Limit ephemeral apps to ephemeral allowed permissions.
+// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
+// if (DEBUG_PERMISSIONS) {
+// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
+// + " for package " + pkg.getPackageName());
+// }
+// continue;
+// }
+
+ if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
+ if (DEBUG_PERMISSIONS) {
+ Log.i(TAG, "Denying runtime-only permission " + bp.getName()
+ + " for package " + pkg.getPackageName());
}
+ continue;
+ }
- final String perm = bp.getName();
- boolean allowedSig = false;
- int grant = GRANT_DENIED;
+ final String perm = bp.getName();
+ boolean allowedSig = false;
+ int grant = GRANT_DENIED;
- // Keep track of app op permissions.
- if (bp.isAppOp()) {
- mSettings.addAppOpPackage(perm, pkg.getPackageName());
- }
+ // Keep track of app op permissions.
+ if (bp.isAppOp()) {
+ mSettings.addAppOpPackage(perm, pkg.getPackageName());
+ }
- if (bp.isNormal()) {
- // For all apps normal permissions are install time ones.
+ if (bp.isNormal()) {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if (bp.isRuntime()) {
+ if (origPermissions.hasInstallPermission(bp.getName())
+ || upgradedActivityRecognitionPermission != null) {
+ // Before Q we represented some runtime permissions as install permissions,
+ // in Q we cannot do this anymore. Hence upgrade them all.
+ grant = GRANT_UPGRADE;
+ } else {
+ // For modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
+ }
+ } else if (bp.isSignature()) {
+ // For all apps signature permissions are install time ones.
+ allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origPermissions);
+ if (allowedSig) {
grant = GRANT_INSTALL;
- } else if (bp.isRuntime()) {
- if (origState.hasInstallPermission(bp.getName())
- || upgradedActivityRecognitionPermission != null) {
- // Before Q we represented some runtime permissions as install permissions,
- // in Q we cannot do this anymore. Hence upgrade them all.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
- }
- } else if (bp.isSignature()) {
- // For all apps signature permissions are install time ones.
- allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origState);
- if (allowedSig) {
- grant = GRANT_INSTALL;
- }
}
+ }
- if (grant != GRANT_DENIED) {
- if (!ps.isSystem() && userState.areInstallPermissionsFixed(ps.name)
- && !bp.isRuntime()) {
- // If this is an existing, non-system package, then
- // we can't add any new permissions to it. Runtime
- // permissions can be added any time - they ad dynamic.
- if (!allowedSig && !origState.hasInstallPermission(perm)) {
- // Except... if this is a permission that was added
- // to the platform (note: need to only do this when
- // updating the platform).
- if (!isNewPlatformPermissionForPackage(perm, pkg)) {
- grant = GRANT_DENIED;
- }
+ if (grant != GRANT_DENIED) {
+ if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
+ // If this is an existing, non-system package, then
+ // we can't add any new permissions to it. Runtime
+ // permissions can be added any time - they ad dynamic.
+ if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
+ // Except... if this is a permission that was added
+ // to the platform (note: need to only do this when
+ // updating the platform).
+ if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+ grant = GRANT_DENIED;
}
}
}
+ }
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Considering granting permission " + perm + " to package "
- + pkg.getPackageName());
- }
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ + pkg.getPackageName());
+ }
- synchronized (mLock) {
- if (grant != GRANT_DENIED) {
- switch (grant) {
- case GRANT_INSTALL: {
- // Revoke this as runtime permission to handle the case of
- // a runtime permission being downgraded to an install one.
- // Also in permission review mode we keep dangerous permissions
- // for legacy apps
- final PermissionState origPermissionState =
- origState.getPermissionState(perm);
- if (origPermissionState != null
- && origPermissionState.isRuntime()) {
+ synchronized (mLock) {
+ if (grant != GRANT_DENIED) {
+ switch (grant) {
+ case GRANT_INSTALL: {
+ // Revoke this as runtime permission to handle the case of
+ // a runtime permission being downgraded to an install one.
+ // Also in permission review mode we keep dangerous permissions
+ // for legacy apps
+ for (int userId : userIds) {
+ if (origPermissions.getRuntimePermissionState(
+ perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
- origState.revokePermission(bp);
- origState.updatePermissionFlags(bp,
+ origPermissions.revokeRuntimePermission(bp, userId);
+ origPermissions.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
// If we revoked a permission permission, we have to write.
updatedUserIds = ArrayUtils.appendInt(
updatedUserIds, userId);
}
- // Grant an install permission.
- if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
- changedInstallPermission = true;
- }
- } break;
+ }
+ // Grant an install permission.
+ if (permissionsState.grantInstallPermission(bp) !=
+ PERMISSION_OPERATION_FAILURE) {
+ changedInstallPermission = true;
+ }
+ } break;
- case GRANT_RUNTIME: {
- boolean hardRestricted = bp.isHardRestricted();
- boolean softRestricted = bp.isSoftRestricted();
+ case GRANT_RUNTIME: {
+ boolean hardRestricted = bp.isHardRestricted();
+ boolean softRestricted = bp.isSoftRestricted();
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -2821,24 +2834,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
mPermissionPolicyInternal != null
&& mPermissionPolicyInternal.isInitialized(userId);
- PermissionState origPermState = origState.getPermissionState(perm);
- int flags = origPermState != null ? origPermState.getFlags() : 0;
+ PermissionState permState = origPermissions
+ .getRuntimePermissionState(perm, userId);
+ int flags = permState != null ? permState.getFlags() : 0;
boolean wasChanged = false;
boolean restrictionExempt =
- (origState.getPermissionFlags(bp.name)
+ (origPermissions.getPermissionFlags(bp.name, userId)
& FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
- boolean restrictionApplied = (origState.getPermissionFlags(
- bp.name) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+ boolean restrictionApplied = (origPermissions.getPermissionFlags(
+ bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
if (appSupportsRuntimePermissions) {
// If hard restricted we don't allow holding it
if (permissionPolicyInitialized && hardRestricted) {
if (!restrictionExempt) {
- if (origPermState != null && origPermState.isGranted()
- && uidState.revokePermission(
- bp) != PERMISSION_OPERATION_FAILURE) {
+ if (permState != null && permState.isGranted()
+ && permissionsState.revokeRuntimePermission(
+ bp, userId) != PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
}
if (!restrictionApplied) {
@@ -2868,15 +2882,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Hard restricted permissions cannot be held.
} else if (!permissionPolicyInitialized
|| (!hardRestricted || restrictionExempt)) {
- if (origPermState != null && origPermState.isGranted()) {
- if (uidState.grantPermission(bp)
+ if (permState != null && permState.isGranted()) {
+ if (permissionsState.grantRuntimePermission(bp, userId)
== PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
}
}
}
} else {
- if (origPermState == null) {
+ if (permState == null) {
// New permission
if (PLATFORM_PACKAGE_NAME.equals(
bp.getSourcePackageName())) {
@@ -2888,8 +2902,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- if (!uidState.hasPermission(bp.name)
- && uidState.grantPermission(bp)
+ if (!permissionsState.hasRuntimePermission(bp.name, userId)
+ && permissionsState.grantRuntimePermission(bp, userId)
!= PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
}
@@ -2922,32 +2936,36 @@ public class PermissionManagerService extends IPermissionManager.Stub {
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
- uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL,
- flags);
- } break;
-
- case GRANT_UPGRADE: {
- // Upgrade from Pre-Q to Q permission model. Make all permissions
- // runtime
- PermissionState origPermState = origState.getPermissionState(perm);
- int flags = (origPermState != null) ? origPermState.getFlags() : 0;
-
- BasePermission bpToRevoke =
- upgradedActivityRecognitionPermission == null
- ? bp : mSettings.getPermissionLocked(
- upgradedActivityRecognitionPermission);
- // Remove install permission
- if (origState.revokePermission(bpToRevoke)
- != PERMISSION_OPERATION_FAILURE) {
- origState.updatePermissionFlags(bpToRevoke,
- (MASK_PERMISSION_FLAGS_ALL
- & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
- changedInstallPermission = true;
- }
+ permissionsState.updatePermissionFlags(bp, userId,
+ MASK_PERMISSION_FLAGS_ALL, flags);
+ }
+ } break;
+
+ case GRANT_UPGRADE: {
+ // Upgrade from Pre-Q to Q permission model. Make all permissions
+ // runtime
+ PermissionState permState = origPermissions
+ .getInstallPermissionState(perm);
+ int flags = (permState != null) ? permState.getFlags() : 0;
+
+ BasePermission bpToRevoke =
+ upgradedActivityRecognitionPermission == null
+ ? bp : mSettings.getPermissionLocked(
+ upgradedActivityRecognitionPermission);
+ // Remove install permission
+ if (origPermissions.revokeInstallPermission(bpToRevoke)
+ != PERMISSION_OPERATION_FAILURE) {
+ origPermissions.updatePermissionFlags(bpToRevoke,
+ UserHandle.USER_ALL,
+ (MASK_PERMISSION_FLAGS_ALL
+ & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
+ changedInstallPermission = true;
+ }
- boolean hardRestricted = bp.isHardRestricted();
- boolean softRestricted = bp.isSoftRestricted();
+ boolean hardRestricted = bp.isHardRestricted();
+ boolean softRestricted = bp.isSoftRestricted();
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -2958,18 +2976,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean wasChanged = false;
boolean restrictionExempt =
- (origState.getPermissionFlags(bp.name)
+ (origPermissions.getPermissionFlags(bp.name, userId)
& FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
- boolean restrictionApplied = (origState.getPermissionFlags(
- bp.name) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+ boolean restrictionApplied = (origPermissions.getPermissionFlags(
+ bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
if (appSupportsRuntimePermissions) {
// If hard restricted we don't allow holding it
if (permissionPolicyInitialized && hardRestricted) {
if (!restrictionExempt) {
- if (origPermState != null && origPermState.isGranted()
- && uidState.revokePermission(
- bp) != PERMISSION_OPERATION_FAILURE) {
+ if (permState != null && permState.isGranted()
+ && permissionsState.revokeRuntimePermission(
+ bp, userId) != PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
}
if (!restrictionApplied) {
@@ -2999,15 +3017,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Hard restricted permissions cannot be held.
} else if (!permissionPolicyInitialized ||
(!hardRestricted || restrictionExempt)) {
- if (uidState.grantPermission(bp)
- != PERMISSION_OPERATION_FAILURE) {
+ if (permissionsState.grantRuntimePermission(bp, userId) !=
+ PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
}
}
} else {
- if (!uidState.hasPermission(bp.name)
- && uidState.grantPermission(bp)
- != PERMISSION_OPERATION_FAILURE) {
+ if (!permissionsState.hasRuntimePermission(bp.name, userId)
+ && permissionsState.grantRuntimePermission(bp,
+ userId) != PERMISSION_OPERATION_FAILURE) {
flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
wasChanged = true;
}
@@ -3040,74 +3058,71 @@ public class PermissionManagerService extends IPermissionManager.Stub {
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
- uidState.updatePermissionFlags(bp,
+ permissionsState.updatePermissionFlags(bp, userId,
MASK_PERMISSION_FLAGS_ALL, flags);
- } break;
+ }
+ } break;
- default: {
- if (packageOfInterest == null
- || packageOfInterest.equals(pkg.getPackageName())) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.getPackageName()
- + " because it was previously installed without");
- }
+ default: {
+ if (packageOfInterest == null
+ || packageOfInterest.equals(pkg.getPackageName())) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Not granting permission " + perm
+ + " to package " + pkg.getPackageName()
+ + " because it was previously installed without");
}
- } break;
- }
- } else {
- if (uidState.revokePermission(bp) != PERMISSION_OPERATION_FAILURE) {
- // Also drop the permission flags.
- uidState.updatePermissionFlags(bp,
- MASK_PERMISSION_FLAGS_ALL, 0);
- changedInstallPermission = true;
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Un-granting permission " + perm
- + " from package " + pkg.getPackageName()
- + " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x"
- + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
- ps))
- + ")");
- }
- } else if (bp.isAppOp()) {
- // Don't print warning for app op permissions, since it is fine for them
- // not to be granted, there is a UI for the user to decide.
- if (DEBUG_PERMISSIONS
- && (packageOfInterest == null
- || packageOfInterest.equals(pkg.getPackageName()))) {
- Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.getPackageName()
- + " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x"
- + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
- ps))
- + ")");
}
+ } break;
+ }
+ } else {
+ if (permissionsState.revokeInstallPermission(bp) !=
+ PERMISSION_OPERATION_FAILURE) {
+ // Also drop the permission flags.
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ MASK_PERMISSION_FLAGS_ALL, 0);
+ changedInstallPermission = true;
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Un-granting permission " + perm
+ + " from package " + pkg.getPackageName()
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ + " flags=0x"
+ + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
+ + ")");
+ }
+ } else if (bp.isAppOp()) {
+ // Don't print warning for app op permissions, since it is fine for them
+ // not to be granted, there is a UI for the user to decide.
+ if (DEBUG_PERMISSIONS
+ && (packageOfInterest == null
+ || packageOfInterest.equals(pkg.getPackageName()))) {
+ Slog.i(TAG, "Not granting permission " + perm
+ + " to package " + pkg.getPackageName()
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ + " flags=0x"
+ + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg, ps))
+ + ")");
}
}
}
}
+ }
- if ((changedInstallPermission || replace)
- && !userState.areInstallPermissionsFixed(ps.name)
- && !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
- // This is the first that we have heard about this package, so the
- // permissions we have now selected are fixed until explicitly
- // changed.
- userState.setInstallPermissionsFixed(ps.name, true);
- }
-
- synchronized (mLock) {
- updatedUserIds = revokePermissionsNoLongerImplicitLocked(uidState, pkg,
- userId, updatedUserIds);
- updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origState,
- uidState, pkg, newImplicitPermissions, userId, updatedUserIds);
- }
+ if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
+ !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
+ // This is the first that we have heard about this package, so the
+ // permissions we have now selected are fixed until explicitly
+ // changed.
+ ps.setInstallPermissionsFixed(true);
}
- updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds,
- updatedUserIds);
+ synchronized (mLock) {
+ updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
+ userIds, updatedUserIds);
+ updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
+ permissionsState, pkg, newImplicitPermissions, userIds, updatedUserIds);
+ updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds,
+ updatedUserIds);
+ }
// TODO: Kill UIDs whose GIDs or runtime permissions changed. This might be more important
// for shared users.
@@ -3144,38 +3159,40 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @return The updated value of the {@code updatedUserIds} parameter
*/
- private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull UidPermissionState ps,
- @NonNull AndroidPackage pkg, int userId, @NonNull int[] updatedUserIds) {
+ private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull PermissionsState ps,
+ @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
- for (String permission : ps.getPermissions()) {
- if (!pkg.getImplicitPermissions().contains(permission)) {
- if (!ps.hasInstallPermission(permission)) {
- int flags = ps.getPermissionFlags(permission);
+ for (int userId : userIds) {
+ for (String permission : ps.getPermissions(userId)) {
+ if (!pkg.getImplicitPermissions().contains(permission)) {
+ if (!ps.hasInstallPermission(permission)) {
+ int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
- if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
- BasePermission bp = mSettings.getPermissionLocked(permission);
+ if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ BasePermission bp = mSettings.getPermissionLocked(permission);
- int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
- if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
- && supportsRuntimePermissions) {
- int revokeResult = ps.revokePermission(bp);
- if (revokeResult != PERMISSION_OPERATION_FAILURE) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Revoking runtime permission "
- + permission + " for " + pkgName
- + " as it is now requested");
+ if ((flags & BLOCKING_PERMISSION_FLAGS) == 0
+ && supportsRuntimePermissions) {
+ int revokeResult = ps.revokeRuntimePermission(bp, userId);
+ if (revokeResult != PERMISSION_OPERATION_FAILURE) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking runtime permission "
+ + permission + " for " + pkgName
+ + " as it is now requested");
+ }
}
+
+ flagsToRemove |= USER_PERMISSION_FLAGS;
}
- flagsToRemove |= USER_PERMISSION_FLAGS;
+ ps.updatePermissionFlags(bp, userId, flagsToRemove, 0);
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
-
- ps.updatePermissionFlags(bp, flagsToRemove, 0);
- updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
}
}
@@ -3196,10 +3213,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param newPerm The permission to inherit to
* @param ps The permission state of the package
* @param pkg The package requesting the permissions
+ * @param userId The user the permission belongs to
*/
private void inheritPermissionStateToNewImplicitPermissionLocked(
@NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
- @NonNull UidPermissionState ps, @NonNull AndroidPackage pkg) {
+ @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
+ @UserIdInt int userId) {
String pkgName = pkg.getPackageName();
boolean isGranted = false;
int flags = 0;
@@ -3207,16 +3226,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
int numSourcePerm = sourcePerms.size();
for (int i = 0; i < numSourcePerm; i++) {
String sourcePerm = sourcePerms.valueAt(i);
- if (ps.hasPermission(sourcePerm)) {
+ if ((ps.hasRuntimePermission(sourcePerm, userId))
+ || ps.hasInstallPermission(sourcePerm)) {
if (!isGranted) {
flags = 0;
}
isGranted = true;
- flags |= ps.getPermissionFlags(sourcePerm);
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
} else {
if (!isGranted) {
- flags |= ps.getPermissionFlags(sourcePerm);
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
}
}
}
@@ -3227,11 +3247,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ " for " + pkgName);
}
- ps.grantPermission(mSettings.getPermissionLocked(newPerm));
+ ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
}
// Add permission flags
- ps.updatePermissionFlags(mSettings.getPermission(newPerm), flags, flags);
+ ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags);
}
/**
@@ -3263,15 +3283,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param origPs The permission state of the package before the split
* @param ps The new permission state
* @param pkg The package the permission belongs to
- * @param userId The user ID
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds List of users for which the permission state has already been changed
*
* @return List of users for which the permission state has been changed
*/
private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
- @NonNull UidPermissionState origPs, @NonNull UidPermissionState ps,
+ @NonNull PermissionsState origPs, @NonNull PermissionsState ps,
@NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions,
- @UserIdInt int userId, @NonNull int[] updatedUserIds) {
+ @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
@@ -3305,33 +3325,35 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!ps.hasInstallPermission(newPerm)) {
BasePermission bp = mSettings.getPermissionLocked(newPerm);
- if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
- ps.updatePermissionFlags(bp,
- FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
- FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
- }
- updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ for (int userId : userIds) {
+ if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
+ ps.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+ }
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
- boolean inheritsFromInstallPerm = false;
- for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
- sourcePermNum++) {
- if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) {
- inheritsFromInstallPerm = true;
- break;
+ boolean inheritsFromInstallPerm = false;
+ for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
+ sourcePermNum++) {
+ if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) {
+ inheritsFromInstallPerm = true;
+ break;
+ }
}
- }
- if (!origPs.hasRequestedPermission(sourcePerms)
- && !inheritsFromInstallPerm) {
- // Both permissions are new so nothing to inherit.
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
- + " for " + pkgName + " as split permission is also new");
+ if (!origPs.hasRequestedPermission(sourcePerms)
+ && !inheritsFromInstallPerm) {
+ // Both permissions are new so nothing to inherit.
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+ + " for " + pkgName + " as split permission is also new");
+ }
+ } else {
+ // Inherit from new install or existing runtime permissions
+ inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
+ newPerm, ps, pkg, userId);
}
- } else {
- // Inherit from new install or existing runtime permissions
- inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
- newPerm, ps, pkg);
}
}
}
@@ -3462,7 +3484,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private boolean shouldGrantSignaturePermission(String perm, AndroidPackage pkg,
- PackageSetting pkgSetting, BasePermission bp, UidPermissionState origPermissions) {
+ PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) {
boolean oemPermission = bp.isOEM();
boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged();
@@ -3738,13 +3760,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// Legacy apps have the permission and get user consent on launch.
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return false;
}
- return uidState.isPermissionReviewRequired();
+ return permissionsState.isPermissionReviewRequired(userId);
}
private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) {
@@ -3768,10 +3789,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
String[] grantedPermissions, int callingUid, PermissionCallback callback) {
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
return;
}
@@ -3796,7 +3816,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
&& (supportsRuntimePermissions || !bp.isRuntimeOnly())
&& (grantedPermissions == null
|| ArrayUtils.contains(grantedPermissions, permission))) {
- final int flags = uidState.getPermissionFlags(permission);
+ final int flags = permissionsState.getPermissionFlags(permission, userId);
if (supportsRuntimePermissions) {
// Installer cannot change immutable permissions.
if ((flags & immutableFlags) == 0) {
@@ -3818,19 +3838,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void setWhitelistedRestrictedPermissionsForUsers(@NonNull AndroidPackage pkg,
@UserIdInt int[] userIds, @Nullable List<String> permissions, int callingUid,
@PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
+ final PermissionsState permissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
+ return;
+ }
+
SparseArray<ArraySet<String>> oldGrantedRestrictedPermissions = new SparseArray<>();
boolean updatePermissions = false;
final int permissionCount = pkg.getRequestedPermissions().size();
for (int i = 0; i < userIds.length; i++) {
int userId = userIds[i];
- final UidPermissionState uidState = getUidState(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
- + userId);
- continue;
- }
-
for (int j = 0; j < permissionCount; j++) {
final String permissionName = pkg.getRequestedPermissions().get(j);
@@ -3840,14 +3859,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- if (uidState.hasPermission(permissionName)) {
+ if (permissionsState.hasPermission(permissionName, userId)) {
if (oldGrantedRestrictedPermissions.get(userId) == null) {
oldGrantedRestrictedPermissions.put(userId, new ArraySet<>());
}
oldGrantedRestrictedPermissions.get(userId).add(permissionName);
}
- final int oldFlags = uidState.getPermissionFlags(permissionName);
+ final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
int newFlags = oldFlags;
int mask = 0;
@@ -3902,7 +3921,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// as whitelisting trumps policy i.e. policy cannot grant a non
// grantable permission.
if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- final boolean isGranted = uidState.hasPermission(permissionName);
+ final boolean isGranted = permissionsState.hasPermission(permissionName,
+ userId);
if (!isWhitelisted && isGranted) {
mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3938,13 +3958,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int j = 0; j < oldGrantedCount; j++) {
final String permission = oldPermsForUser.valueAt(j);
// Sometimes we create a new permission state instance during update.
- final UidPermissionState newUidState = getUidState(pkg, userId);
- if (newUidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
- + " and user " + userId);
+ final PermissionsState newPermissionsState = getPermissionsState(pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName());
continue;
}
- if (!newUidState.hasPermission(permission)) {
+ if (!newPermissionsState.hasPermission(permission, userId)) {
callback.onPermissionRevoked(pkg.getUid(), userId, null);
break;
}
@@ -3993,10 +4012,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- UidPermissionState uidState = getUidState(deletedPs.pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName()
- + " and user " + userId);
+ PermissionsState permissionsState = getPermissionsState(deletedPs.pkg);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + deletedPs.pkg.getPackageName());
continue;
}
@@ -4018,15 +4036,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ // Try to revoke as an install permission which is for all users.
// The package is gone - no need to keep flags for applying policy.
- uidState.updatePermissionFlags(bp, PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
+
+ if (permissionsState.revokeInstallPermission(bp)
+ == PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ affectedUserId = UserHandle.USER_ALL;
+ }
// Try to revoke as a runtime permission which is per user.
- // TODO(zhanghai): This doesn't make sense. revokePermission() doesn't fail, and why are
- // we only killing the uid when gids changed, instead of any permission change?
- if (uidState.revokePermission(bp)
+ if (permissionsState.revokeRuntimePermission(bp, userId)
== PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- affectedUserId = userId;
+ if (affectedUserId == UserHandle.USER_NULL) {
+ affectedUserId = userId;
+ } else if (affectedUserId != userId) {
+ // Multiple users affected.
+ affectedUserId = UserHandle.USER_ALL;
+ }
}
}
@@ -4034,12 +4062,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@GuardedBy("mLock")
- private boolean revokeUnusedSharedUserPermissionsLocked(
- List<AndroidPackage> pkgList, UidPermissionState uidState) {
+ private int[] revokeUnusedSharedUserPermissionsLocked(
+ List<AndroidPackage> pkgList, PermissionsState permissionsState, int[] allUserIds) {
// Collect all used permissions in the UID
final ArraySet<String> usedPermissions = new ArraySet<>();
if (pkgList == null || pkgList.size() == 0) {
- return false;
+ return EmptyArray.INT;
}
for (AndroidPackage pkg : pkgList) {
if (pkg.getRequestedPermissions().isEmpty()) {
@@ -4055,27 +4083,44 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- boolean runtimePermissionChanged = false;
-
- // Prune permissions
- final List<com.android.server.pm.permission.PermissionState> permissionStates =
- uidState.getPermissionStates();
- final int permissionStatesSize = permissionStates.size();
- for (int i = permissionStatesSize - 1; i >= 0; i--) {
- PermissionState permissionState = permissionStates.get(i);
+ // Prune install permissions
+ List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
+ final int installPermCount = installPermStates.size();
+ for (int i = installPermCount - 1; i >= 0; i--) {
+ PermissionState permissionState = installPermStates.get(i);
if (!usedPermissions.contains(permissionState.getName())) {
BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
if (bp != null) {
- uidState.revokePermission(bp);
- uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, 0);
- if (permissionState.isRuntime()) {
- runtimePermissionChanged = true;
+ permissionsState.revokeInstallPermission(bp);
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ }
+ }
+
+ int[] runtimePermissionChangedUserIds = EmptyArray.INT;
+
+ // Prune runtime permissions
+ for (int userId : allUserIds) {
+ List<PermissionState> runtimePermStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ final int runtimePermCount = runtimePermStates.size();
+ for (int i = runtimePermCount - 1; i >= 0; i--) {
+ PermissionState permissionState = runtimePermStates.get(i);
+ if (!usedPermissions.contains(permissionState.getName())) {
+ BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ MASK_PERMISSION_FLAGS_ALL, 0);
+ runtimePermissionChangedUserIds = ArrayUtils.appendInt(
+ runtimePermissionChangedUserIds, userId);
}
}
}
}
- return runtimePermissionChanged;
+ return runtimePermissionChangedUserIds;
}
/**
@@ -4323,19 +4368,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
} else {
mPackageManagerInt.forEachPackage(p -> {
- final int[] userIds = mUserManagerInt.getUserIds();
- for (final int userId : userIds) {
- final UidPermissionState uidState = getUidState(p, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for "
- + p.getPackageName() + " and user " + userId);
- return;
- }
- if (uidState.getPermissionState(bp.getName()) != null) {
- uidState.revokePermission(bp);
- uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL,
- 0);
- }
+ final PermissionsState permissionsState = getPermissionsState(p);
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + p.getPackageName());
+ return;
+ }
+ if (permissionsState.getInstallPermissionState(bp.getName()) != null) {
+ permissionsState.revokeInstallPermission(bp);
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ MASK_PERMISSION_FLAGS_ALL, 0);
}
});
}
@@ -4743,124 +4784,62 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Nullable
- private UidPermissionState getUidState(@NonNull PackageSetting ps,
- @UserIdInt int userId) {
- return getUidState(ps.getAppId(), userId);
+ private PermissionsState getPermissionsState(@NonNull PackageSetting ps) {
+ return getPermissionsState(ps.getAppId());
}
@Nullable
- private UidPermissionState getUidState(@NonNull AndroidPackage pkg,
- @UserIdInt int userId) {
- return getUidState(pkg.getUid(), userId);
+ private PermissionsState getPermissionsState(@NonNull AndroidPackage pkg) {
+ return getPermissionsState(pkg.getUid());
}
@Nullable
- private UidPermissionState getUidState(int appId, @UserIdInt int userId) {
+ private PermissionsState getPermissionsState(int appId) {
synchronized (mLock) {
- final UserPermissionState userState = mState.getUserState(userId);
- if (userState == null) {
- return null;
- }
- return userState.getUidState(appId);
+ return mAppIdStates.get(appId);
}
}
- private void removeAppState(int appId) {
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(@NonNull PackageSetting ps) {
+ return getOrCreatePermissionsState(ps.getAppId());
+ }
+
+ @Nullable
+ private PermissionsState getOrCreatePermissionsState(int appId) {
synchronized (mLock) {
- final int[] userIds = mState.getUserIds();
- for (final int userId : userIds) {
- final UserPermissionState userState = mState.getUserState(userId);
- userState.removeUidState(appId);
+ PermissionsState state = mAppIdStates.get(appId);
+ if (state == null) {
+ state = new PermissionsState();
+ mAppIdStates.put(appId, state);
}
+ return state;
}
}
- private void readStateFromPackageSettings() {
- final int[] userIds = getAllUserIds();
- mPackageManagerInt.forEachPackageSetting(ps -> {
- final int appId = ps.getAppId();
- final PermissionsState permissionsState = ps.getPermissionsState();
+ private void removePermissionsState(int appId) {
+ synchronized (mLock) {
+ mAppIdStates.remove(appId);
+ }
+ }
+ private void readPermissionsStateFromPackageSettings() {
+ mPackageManagerInt.forEachPackageSetting(ps -> {
synchronized (mLock) {
- for (final int userId : userIds) {
- final UserPermissionState userState = mState.getOrCreateUserState(userId);
-
- userState.setInstallPermissionsFixed(ps.name, ps.areInstallPermissionsFixed());
- final UidPermissionState uidState = userState.getOrCreateUidState(appId);
- uidState.reset();
- uidState.setGlobalGids(permissionsState.getGlobalGids());
- uidState.setMissing(permissionsState.isMissing(userId));
- readStateFromPermissionStates(uidState,
- permissionsState.getInstallPermissionStates(), false);
- readStateFromPermissionStates(uidState,
- permissionsState.getRuntimePermissionStates(userId), true);
- }
+ mAppIdStates.put(ps.getAppId(), new PermissionsState(ps.getPermissionsState()));
}
});
}
- private void readStateFromPermissionStates(@NonNull UidPermissionState uidState,
- @NonNull List<PermissionsState.PermissionState> permissionStates, boolean isRuntime) {
- final int permissionStatesSize = permissionStates.size();
- for (int i = 0; i < permissionStatesSize; i++) {
- final PermissionsState.PermissionState permissionState = permissionStates.get(i);
- final BasePermission permission = permissionState.getPermission();
- uidState.putPermissionState(permission, isRuntime, permissionState.isGranted(),
- permissionState.getFlags());
- }
- }
-
- private void writeStateToPackageSettings() {
- final int[] userIds = mState.getUserIds();
+ private void writePermissionsStateToPackageSettings() {
mPackageManagerInt.forEachPackageSetting(ps -> {
- ps.setInstallPermissionsFixed(false);
- final PermissionsState permissionsState = ps.getPermissionsState();
- permissionsState.reset();
- final int appId = ps.getAppId();
-
synchronized (mLock) {
- for (final int userId : userIds) {
- final UserPermissionState userState = mState.getUserState(userId);
- if (userState == null) {
- Slog.e(TAG, "Missing user state for " + userId);
- continue;
- }
-
- if (userState.areInstallPermissionsFixed(ps.name)) {
- ps.setInstallPermissionsFixed(true);
- }
-
- final UidPermissionState uidState = userState.getUidState(appId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permission state for " + ps.name + " and user "
- + userId);
- continue;
- }
-
- permissionsState.setGlobalGids(uidState.getGlobalGids());
- permissionsState.setMissing(uidState.isMissing(), userId);
- final List<PermissionState> permissionStates = uidState.getPermissionStates();
- final int permissionStatesSize = permissionStates.size();
- for (int i = 0; i < permissionStatesSize; i++) {
- final PermissionState permissionState = permissionStates.get(i);
-
- final BasePermission permission = permissionState.getPermission();
- if (permissionState.isGranted()) {
- if (permissionState.isRuntime()) {
- permissionsState.grantRuntimePermission(permission, userId);
- } else {
- permissionsState.grantInstallPermission(permission);
- }
- }
- final int flags = permissionState.getFlags();
- if (flags != 0) {
- final int flagsUserId = permissionState.isRuntime() ? userId
- : UserHandle.USER_ALL;
- permissionsState.updatePermissionFlags(permission, flagsUserId, flags,
- flags);
- }
- }
+ final PermissionsState permissionsState = mAppIdStates.get(ps.getAppId());
+ if (permissionsState == null) {
+ Slog.e(TAG, "Missing permissions state for " + ps.name);
+ return;
}
+ ps.getPermissionsState().copyFrom(permissionsState);
}
});
}
@@ -4897,12 +4876,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
@Override
- public void readStateFromPackageSettingsTEMP() {
- PermissionManagerService.this.readStateFromPackageSettings();
+ public void readPermissionsStateFromPackageSettingsTEMP() {
+ PermissionManagerService.this.readPermissionsStateFromPackageSettings();
}
@Override
- public void writeStateToPackageSettingsTEMP() {
- PermissionManagerService.this.writeStateToPackageSettings();
+ public void writePermissionsStateToPackageSettingsTEMP() {
+ PermissionManagerService.this.writePermissionsStateToPackageSettings();
}
@Override
public void onUserRemoved(@UserIdInt int userId) {
@@ -4910,7 +4889,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
public void removePermissionsStateTEMP(int appId) {
- PermissionManagerService.this.removeAppState(appId);
+ PermissionManagerService.this.removePermissionsState(appId);
}
@Override
@UserIdInt
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 7f6a1d4284d2..f319bf495e8b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -266,21 +266,21 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
/**
- * Read permission state from package settings.
+ * Read {@code PermissionsState} from package settings.
*
* TODO(zhanghai): This is a temporary method because we should not expose
* {@code PackageSetting} which is a implementation detail that permission should not know.
* Instead, it should retrieve the legacy state via a defined API.
*/
- public abstract void readStateFromPackageSettingsTEMP();
+ public abstract void readPermissionsStateFromPackageSettingsTEMP();
/**
- * Write permission state to package settings.
+ * Write {@code PermissionsState} from to settings.
*
* TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
* for permission.
*/
- public abstract void writeStateToPackageSettingsTEMP();
+ public abstract void writePermissionsStateToPackageSettingsTEMP();
/**
* Notify that a user has been removed and its permission state should be removed as well.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java
deleted file mode 100644
index 2ed9a50353d4..000000000000
--- a/services/core/java/com/android/server/pm/permission/PermissionState.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2020 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.server.pm.permission;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * State for a single permission.
- */
-public final class PermissionState {
-
- @NonNull
- private final BasePermission mPermission;
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private boolean mRuntime;
-
- @GuardedBy("mLock")
- private boolean mGranted;
-
- @GuardedBy("mLock")
- private int mFlags;
-
- public PermissionState(@NonNull BasePermission permission, boolean isRuntime) {
- mPermission = permission;
- mRuntime = isRuntime;
- }
-
- public PermissionState(@NonNull PermissionState other) {
- this(other.mPermission, other.mRuntime);
-
- mGranted = other.mGranted;
- mFlags = other.mFlags;
- }
-
- @NonNull
- public BasePermission getPermission() {
- return mPermission;
- }
-
- @NonNull
- public String getName() {
- return mPermission.getName();
- }
-
- @Nullable
- public int[] computeGids(@UserIdInt int userId) {
- return mPermission.computeGids(userId);
- }
-
- public boolean isRuntime() {
- synchronized (mLock) {
- return mRuntime;
- }
- }
-
- public boolean isGranted() {
- synchronized (mLock) {
- return mGranted;
- }
- }
-
- public boolean grant() {
- synchronized (mLock) {
- if (mGranted) {
- return false;
- }
- mGranted = true;
- UidPermissionState.invalidateCache();
- return true;
- }
- }
-
- public boolean revoke() {
- synchronized (mLock) {
- if (!mGranted) {
- return false;
- }
- mGranted = false;
- UidPermissionState.invalidateCache();
- return true;
- }
- }
-
- public int getFlags() {
- synchronized (mLock) {
- return mFlags;
- }
- }
-
- public boolean updateFlags(int flagMask, int flagValues) {
- synchronized (mLock) {
- final int newFlags = flagValues & flagMask;
-
- // Okay to do before the modification because we hold the lock.
- UidPermissionState.invalidateCache();
-
- final int oldFlags = mFlags;
- mFlags = (mFlags & ~flagMask) | newFlags;
- return mFlags != oldFlags;
- }
- }
-
- public boolean isDefault() {
- synchronized (mLock) {
- return !mGranted && mFlags == 0;
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
index 4fb2d5fc200e..bad59cb1b567 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java
@@ -86,10 +86,6 @@ public final class PermissionsState {
copyFrom(prototype);
}
- public int[] getGlobalGids() {
- return mGlobalGids;
- }
-
/**
* Sets the global gids, applicable to all users.
*
@@ -829,7 +825,7 @@ public final class PermissionsState {
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
- userState = new PermissionState(mPerm);
+ userState = new PermissionState(mPerm.getName());
mUserStates.put(userId, userState);
}
@@ -912,7 +908,7 @@ public final class PermissionsState {
}
return userState.mFlags != oldFlags;
} else if (newFlags != 0) {
- userState = new PermissionState(mPerm);
+ userState = new PermissionState(mPerm.getName());
userState.mFlags = newFlags;
mUserStates.put(userId, userState);
return true;
@@ -933,16 +929,16 @@ public final class PermissionsState {
}
public static final class PermissionState {
- private final BasePermission mPermission;
+ private final String mName;
private boolean mGranted;
private int mFlags;
- public PermissionState(BasePermission permission) {
- mPermission = permission;
+ public PermissionState(String name) {
+ mName = name;
}
public PermissionState(PermissionState other) {
- mPermission = other.mPermission;
+ mName = other.mName;
mGranted = other.mGranted;
mFlags = other.mFlags;
}
@@ -951,12 +947,8 @@ public final class PermissionsState {
return !mGranted && mFlags == 0;
}
- public BasePermission getPermission() {
- return mPermission;
- }
-
public String getName() {
- return mPermission.getName();
+ return mName;
}
public boolean isGranted() {
diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
deleted file mode 100644
index 4c047ffd30e8..000000000000
--- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 2015 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.server.pm.permission;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Permission state for a UID.
- * <p>
- * This class is also responsible for keeping track of the Linux GIDs per
- * user for a package or a shared user. The GIDs are computed as a set of
- * the GIDs for all granted permissions' GIDs on a per user basis.
- */
-public final class UidPermissionState {
- /** The permission operation failed. */
- public static final int PERMISSION_OPERATION_FAILURE = -1;
-
- /** The permission operation succeeded and no gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS = 0;
-
- /** The permission operation succeeded and gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
-
- private static final int[] NO_GIDS = {};
-
- @NonNull
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private ArrayMap<String, PermissionState> mPermissions;
-
- @NonNull
- private int[] mGlobalGids = NO_GIDS;
-
- private boolean mMissing;
-
- private boolean mPermissionReviewRequired;
-
- public UidPermissionState() {
- /* do nothing */
- }
-
- public UidPermissionState(@NonNull UidPermissionState prototype) {
- copyFrom(prototype);
- }
-
- /**
- * Gets the global gids, applicable to all users.
- */
- @NonNull
- public int[] getGlobalGids() {
- return mGlobalGids;
- }
-
- /**
- * Sets the global gids, applicable to all users.
- *
- * @param globalGids The global gids.
- */
- public void setGlobalGids(@NonNull int[] globalGids) {
- if (!ArrayUtils.isEmpty(globalGids)) {
- mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
- }
- }
-
- static void invalidateCache() {
- PackageManager.invalidatePackageInfoCache();
- }
-
- /**
- * Initialized this instance from another one.
- *
- * @param other The other instance.
- */
- public void copyFrom(@NonNull UidPermissionState other) {
- if (other == this) {
- return;
- }
-
- synchronized (mLock) {
- if (mPermissions != null) {
- if (other.mPermissions == null) {
- mPermissions = null;
- } else {
- mPermissions.clear();
- }
- }
- if (other.mPermissions != null) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- final int permissionCount = other.mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String name = other.mPermissions.keyAt(i);
- PermissionState permissionState = other.mPermissions.valueAt(i);
- mPermissions.put(name, new PermissionState(permissionState));
- }
- }
- }
-
- mGlobalGids = NO_GIDS;
- if (other.mGlobalGids != NO_GIDS) {
- mGlobalGids = other.mGlobalGids.clone();
- }
-
- mMissing = other.mMissing;
-
- mPermissionReviewRequired = other.mPermissionReviewRequired;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final UidPermissionState other = (UidPermissionState) obj;
-
- synchronized (mLock) {
- if (mPermissions == null) {
- if (other.mPermissions != null) {
- return false;
- }
- } else if (!mPermissions.equals(other.mPermissions)) {
- return false;
- }
- }
-
- if (mMissing != other.mMissing) {
- return false;
- }
-
- if (mPermissionReviewRequired != other.mPermissionReviewRequired) {
- return false;
- }
- return Arrays.equals(mGlobalGids, other.mGlobalGids);
- }
-
- /**
- * Check whether the permissions state is missing for a user. This can happen if permission
- * state is rolled back and we'll need to generate a reasonable default state to keep the app
- * usable.
- */
- public boolean isMissing() {
- return mMissing;
- }
-
- /**
- * Set whether the permissions state is missing for a user. This can happen if permission state
- * is rolled back and we'll need to generate a reasonable default state to keep the app usable.
- */
- public void setMissing(boolean missing) {
- mMissing = missing;
- }
-
- public boolean isPermissionReviewRequired() {
- return mPermissionReviewRequired;
- }
-
- /**
- * Gets whether the state has a given permission.
- *
- * @param name The permission name.
- * @return Whether the state has the permission.
- */
- public boolean hasPermission(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- PermissionState permissionState = mPermissions.get(name);
- return permissionState != null && permissionState.isGranted();
- }
- }
-
- /**
- * Gets whether the state has a given install permission.
- *
- * @param name The permission name.
- * @return Whether the state has the install permission.
- */
- public boolean hasInstallPermission(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- PermissionState permissionState = mPermissions.get(name);
- return permissionState != null && permissionState.isGranted()
- && !permissionState.isRuntime();
- }
- }
-
- /**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
- *
- * @deprecated Not all requested permissions may be here.
- */
- @Deprecated
- public boolean hasRequestedPermission(@NonNull ArraySet<String> names) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- for (int i = names.size() - 1; i >= 0; i--) {
- if (mPermissions.get(names.valueAt(i)) != null) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
- *
- * @deprecated Not all requested permissions may be here.
- */
- @Deprecated
- public boolean hasRequestedPermission(@NonNull String name) {
- return mPermissions != null && (mPermissions.get(name) != null);
- }
-
- /**
- * Gets all permissions for a given device user id regardless if they
- * are install time or runtime permissions.
- *
- * @return The permissions or an empty set.
- */
- @NonNull
- public Set<String> getPermissions() {
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptySet();
- }
-
- Set<String> permissions = new ArraySet<>(mPermissions.size());
-
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String permission = mPermissions.keyAt(i);
-
- if (hasPermission(permission)) {
- permissions.add(permission);
- }
- }
-
- return permissions;
- }
- }
-
- /**
- * Gets the flags for a permission.
- *
- * @param name The permission name.
- * @return The permission state or null if no such.
- */
- public int getPermissionFlags(@NonNull String name) {
- PermissionState permState = getPermissionState(name);
- if (permState != null) {
- return permState.getFlags();
- }
- return 0;
- }
-
- /**
- * Update the flags associated with a given permission.
- * @param permission The permission whose flags to update.
- * @param flagMask Mask for which flags to change.
- * @param flagValues New values for the mask flags.
- * @return Whether the permission flags changed.
- */
- public boolean updatePermissionFlags(@NonNull BasePermission permission, int flagMask,
- int flagValues) {
- if (flagMask == 0) {
- return false;
- }
-
- PermissionState permissionState = ensurePermissionState(permission);
-
- final int oldFlags = permissionState.getFlags();
-
- synchronized (mLock) {
- final boolean updated = permissionState.updateFlags(flagMask, flagValues);
- if (updated) {
- final int newFlags = permissionState.getFlags();
- if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- mPermissionReviewRequired = true;
- } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- if (mPermissionReviewRequired && !hasPermissionRequiringReview()) {
- mPermissionReviewRequired = false;
- }
- }
- }
- return updated;
- }
- }
-
- private boolean hasPermissionRequiringReview() {
- synchronized (mLock) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- final PermissionState permission = mPermissions.valueAt(i);
- if ((permission.getFlags() & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- return true;
- }
- }
- }
- return false;
- }
-
- public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- boolean changed = false;
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionState permissionState = mPermissions.valueAt(i);
- changed |= permissionState.updateFlags(flagMask, flagValues);
- }
- return changed;
- }
- }
-
- /**
- * Compute the Linux gids for a given device user from the permissions
- * granted to this user. Note that these are computed to avoid additional
- * state as they are rarely accessed.
- *
- * @param userId The device user id.
- * @return The gids for the device user.
- */
- @NonNull
- public int[] computeGids(@UserIdInt int userId) {
- int[] gids = mGlobalGids;
-
- synchronized (mLock) {
- if (mPermissions != null) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionState permissionState = mPermissions.valueAt(i);
- if (!permissionState.isGranted()) {
- continue;
- }
- final int[] permGids = permissionState.computeGids(userId);
- if (permGids != NO_GIDS) {
- gids = appendInts(gids, permGids);
- }
- }
- }
- }
-
- return gids;
- }
-
- /**
- * Compute the Linux gids for all device users from the permissions
- * granted to these users.
- *
- * @return The gids for all device users.
- */
- @NonNull
- public int[] computeGids(@NonNull int[] userIds) {
- int[] gids = mGlobalGids;
-
- for (int userId : userIds) {
- final int[] userGids = computeGids(userId);
- gids = appendInts(gids, userGids);
- }
-
- return gids;
- }
-
- /**
- * Resets the internal state of this object.
- */
- public void reset() {
- mGlobalGids = NO_GIDS;
-
- synchronized (mLock) {
- mPermissions = null;
- invalidateCache();
- }
-
- mMissing = false;
- mPermissionReviewRequired = false;
- }
-
- /**
- * Gets the state for a permission or null if no such.
- *
- * @param name The permission name.
- * @return The permission state.
- */
- @Nullable
- public PermissionState getPermissionState(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return null;
- }
- return mPermissions.get(name);
- }
- }
-
- /**
- * Gets all permission states.
- *
- * @return The permission states or an empty set.
- */
- @NonNull
- public List<PermissionState> getPermissionStates() {
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptyList();
- }
- return new ArrayList<>(mPermissions.values());
- }
- }
-
- /**
- * Put a permission state.
- */
- public void putPermissionState(@NonNull BasePermission permission, boolean isRuntime,
- boolean isGranted, int flags) {
- synchronized (mLock) {
- ensureNoPermissionState(permission.name);
- PermissionState permissionState = ensurePermissionState(permission, isRuntime);
- if (isGranted) {
- permissionState.grant();
- }
- permissionState.updateFlags(flags, flags);
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- mPermissionReviewRequired = true;
- }
- }
- }
-
- /**
- * Grant a permission.
- *
- * @param permission The permission to grant.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int grantPermission(@NonNull BasePermission permission) {
- if (hasPermission(permission.getName())) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- PermissionState permissionState = ensurePermissionState(permission);
-
- if (!permissionState.grant()) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
- }
-
- /**
- * Revoke a permission.
- *
- * @param permission The permission to revoke.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int revokePermission(@NonNull BasePermission permission) {
- final String permissionName = permission.getName();
- if (!hasPermission(permissionName)) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- PermissionState permissionState;
- synchronized (mLock) {
- permissionState = mPermissions.get(permissionName);
- }
-
- if (!permissionState.revoke()) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- if (permissionState.isDefault()) {
- ensureNoPermissionState(permissionName);
- }
-
- return permission.hasGids() ? PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED
- : PERMISSION_OPERATION_SUCCESS;
- }
-
- // TODO: fix this to use arraycopy and append all ints in one go
- private static int[] appendInts(int[] current, int[] added) {
- if (current != null && added != null) {
- for (int guid : added) {
- current = ArrayUtils.appendInt(current, guid);
- }
- }
- return current;
- }
-
- @NonNull
- private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
- return ensurePermissionState(permission, permission.isRuntime());
- }
-
- @NonNull
- private PermissionState ensurePermissionState(@NonNull BasePermission permission,
- boolean isRuntime) {
- final String permissionName = permission.getName();
- synchronized (mLock) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- PermissionState permissionState = mPermissions.get(permissionName);
- if (permissionState == null) {
- permissionState = new PermissionState(permission, isRuntime);
- mPermissions.put(permissionName, permissionState);
- }
- return permissionState;
- }
- }
-
- private void ensureNoPermissionState(@NonNull String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return;
- }
- mPermissions.remove(name);
- if (mPermissions.isEmpty()) {
- mPermissions = null;
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/permission/UserPermissionState.java b/services/core/java/com/android/server/pm/permission/UserPermissionState.java
deleted file mode 100644
index 7f55cb161e40..000000000000
--- a/services/core/java/com/android/server/pm/permission/UserPermissionState.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2020 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.server.pm.permission;
-
-import android.annotation.AppIdInt;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * Permission state for a user.
- */
-public final class UserPermissionState {
- /**
- * Whether the install permissions have been granted to a package, so that no install
- * permissions should be added to it unless the package is upgraded.
- */
- @GuardedBy("mLock")
- @NonNull
- private final ArraySet<String> mInstallPermissionsFixed = new ArraySet<>();
-
- /**
- * Maps from app ID to {@link UidPermissionState}.
- */
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<UidPermissionState> mUidStates = new SparseArray<>();
-
- @NonNull
- private final Object mLock;
-
- public UserPermissionState(@NonNull Object lock) {
- mLock = lock;
- }
-
- public boolean areInstallPermissionsFixed(@NonNull String packageName) {
- synchronized (mLock) {
- return mInstallPermissionsFixed.contains(packageName);
- }
- }
-
- public void setInstallPermissionsFixed(@NonNull String packageName, boolean fixed) {
- synchronized (mLock) {
- if (fixed) {
- mInstallPermissionsFixed.add(packageName);
- } else {
- mInstallPermissionsFixed.remove(packageName);
- }
- }
- }
-
- @Nullable
- public UidPermissionState getUidState(@AppIdInt int appId) {
- checkAppId(appId);
- synchronized (mLock) {
- return mUidStates.get(appId);
- }
- }
-
- @NonNull
- public UidPermissionState getOrCreateUidState(@AppIdInt int appId) {
- checkAppId(appId);
- synchronized (mLock) {
- UidPermissionState uidState = mUidStates.get(appId);
- if (uidState == null) {
- uidState = new UidPermissionState();
- mUidStates.put(appId, uidState);
- }
- return uidState;
- }
- }
-
- public void removeUidState(@AppIdInt int appId) {
- checkAppId(appId);
- synchronized (mLock) {
- mUidStates.delete(appId);
- }
- }
-
- private void checkAppId(@AppIdInt int appId) {
- if (UserHandle.getUserId(appId) != 0) {
- throw new IllegalArgumentException(appId + " is not an app ID");
- }
- }
-}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index d64032325539..6a12b7c8f9a5 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -117,12 +117,13 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
@Override
public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+ boolean geoDetectionEnabled = mGeoDetectionFeatureEnabled && isGeoDetectionEnabled(userId);
return new ConfigurationInternal.Builder(userId)
.setUserConfigAllowed(isUserConfigAllowed(userId))
.setAutoDetectionSupported(isAutoDetectionSupported())
.setAutoDetectionEnabled(isAutoDetectionEnabled())
.setLocationEnabled(isLocationEnabled(userId))
- .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
+ .setGeoDetectionEnabled(geoDetectionEnabled)
.build();
}
@@ -167,9 +168,11 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
setAutoDetectionEnabled(autoDetectionEnabled);
- final int userId = configuration.getUserId();
- final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
- setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ if (mGeoDetectionFeatureEnabled) {
+ final int userId = configuration.getUserId();
+ final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
+ setGeoDetectionEnabled(userId, geoTzDetectionEnabled);
+ }
}
}
@@ -211,4 +214,4 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
return mContext.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 6e9526afa962..fb06a9cb5887 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -67,6 +67,8 @@ import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.ActivityOptions.SourceInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
import android.content.ComponentName;
@@ -161,6 +163,8 @@ class ActivityMetricsLogger {
* launched successfully.
*/
static final class LaunchingState {
+ /** The device uptime of {@link #notifyActivityLaunching}. */
+ private final long mCurrentUpTimeMs = SystemClock.uptimeMillis();
/** The timestamp of {@link #notifyActivityLaunching}. */
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
@@ -199,6 +203,10 @@ class ActivityMetricsLogger {
/** The latest activity to have been launched. */
@NonNull ActivityRecord mLastLaunchedActivity;
+ /** The type of the source that triggers the launch event. */
+ @SourceInfo.SourceType int mSourceType;
+ /** The time from the source event (e.g. touch) to {@link #notifyActivityLaunching}. */
+ int mSourceEventDelayMs = INVALID_DELAY;
/** The time from {@link #mTransitionStartTimeNs} to {@link #notifyTransitionStarting}. */
int mCurrentTransitionDelayMs;
/** The time from {@link #mTransitionStartTimeNs} to {@link #notifyStartingWindowDrawn}. */
@@ -222,8 +230,8 @@ class ActivityMetricsLogger {
/** @return Non-null if there will be a window drawn event for the launch. */
@Nullable
static TransitionInfo create(@NonNull ActivityRecord r,
- @NonNull LaunchingState launchingState, boolean processRunning,
- boolean processSwitch, int startResult) {
+ @NonNull LaunchingState launchingState, @Nullable ActivityOptions options,
+ boolean processRunning, boolean processSwitch, int startResult) {
int transitionType = INVALID_TRANSITION_TYPE;
if (processRunning) {
if (startResult == START_SUCCESS) {
@@ -240,22 +248,31 @@ class ActivityMetricsLogger {
// That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
return null;
}
- return new TransitionInfo(r, launchingState, transitionType, processRunning,
+ return new TransitionInfo(r, launchingState, options, transitionType, processRunning,
processSwitch);
}
/** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
- private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
- boolean processRunning, boolean processSwitch) {
+ private TransitionInfo(ActivityRecord r, LaunchingState launchingState,
+ ActivityOptions options, int transitionType, boolean processRunning,
+ boolean processSwitch) {
mLaunchingState = launchingState;
mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
mTransitionType = transitionType;
mProcessRunning = processRunning;
mProcessSwitch = processSwitch;
mCurrentTransitionDeviceUptime =
- (int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
+ (int) TimeUnit.MILLISECONDS.toSeconds(launchingState.mCurrentUpTimeMs);
setLatestLaunchedActivity(r);
launchingState.mAssociatedTransitionInfo = this;
+ if (options != null) {
+ final SourceInfo sourceInfo = options.getSourceInfo();
+ if (sourceInfo != null) {
+ mSourceType = sourceInfo.type;
+ mSourceEventDelayMs =
+ (int) (launchingState.mCurrentUpTimeMs - sourceInfo.eventTimeMs);
+ }
+ }
}
/**
@@ -324,6 +341,8 @@ class ActivityMetricsLogger {
final private String launchedActivityAppRecordRequiredAbi;
final String launchedActivityShortComponentName;
final private String processName;
+ @VisibleForTesting final @SourceInfo.SourceType int sourceType;
+ @VisibleForTesting final int sourceEventDelayMs;
final private int reason;
final private int startingWindowDelayMs;
final private int bindApplicationDelayMs;
@@ -352,12 +371,14 @@ class ActivityMetricsLogger {
? null
: launchedActivity.app.getRequiredAbi();
reason = info.mReason;
+ sourceEventDelayMs = info.mSourceEventDelayMs;
startingWindowDelayMs = info.mStartingWindowDelayMs;
bindApplicationDelayMs = info.mBindApplicationDelayMs;
windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
type = info.mTransitionType;
processRecord = launchedActivity.app;
processName = launchedActivity.processName;
+ sourceType = info.mSourceType;
userId = launchedActivity.mUserId;
launchedActivityShortComponentName = launchedActivity.shortComponentName;
activityRecordIdHashCode = System.identityHashCode(launchedActivity);
@@ -513,9 +534,10 @@ class ActivityMetricsLogger {
* @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
* the result of the launch.
* @param launchedActivity The activity that is being launched
+ * @param options The given options of the launching activity.
*/
void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
- @Nullable ActivityRecord launchedActivity) {
+ @Nullable ActivityRecord launchedActivity, @Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
abort(null /* info */, "nothing launched");
@@ -560,7 +582,7 @@ class ActivityMetricsLogger {
}
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
- processRunning, processSwitch, resultCode);
+ options, processRunning, processSwitch, resultCode);
if (newInfo == null) {
abort(info, "unrecognized launch");
return;
@@ -864,7 +886,9 @@ class ActivityMetricsLogger {
info.windowsDrawnDelayMs,
launchToken,
packageOptimizationInfo.getCompilationReason(),
- packageOptimizationInfo.getCompilationFilter());
+ packageOptimizationInfo.getCompilationFilter(),
+ info.sourceType,
+ info.sourceEventDelayMs);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
@@ -970,7 +994,9 @@ class ActivityMetricsLogger {
: FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
info.mLastLaunchedActivity.info.name,
info.mProcessRunning,
- startupTimeMs);
+ startupTimeMs,
+ info.mSourceType,
+ info.mSourceEventDelayMs);
// Ends the trace started at the beginning of this function. This is located here to allow
// the trace slice to have a noticable duration.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 5196416e2cd3..ab464501193c 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2515,7 +2515,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
targetActivity.applyOptionsLocked();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, targetActivity);
+ START_TASK_TO_FRONT, targetActivity, activityOptions);
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 19755f29043e..e8e4059af324 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -616,7 +616,7 @@ class ActivityStarter {
voiceInteractor, startFlags, doResume, options, inTask,
false /* restrictedBgActivity */, intentGrants);
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
- mLastStartActivityResult, mLastStartActivityRecord);
+ mLastStartActivityResult, mLastStartActivityRecord, options);
} finally {
onExecutionComplete();
}
@@ -704,7 +704,7 @@ class ActivityStarter {
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
- mLastStartActivityRecord);
+ mLastStartActivityRecord, mOptions);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 714591a831bd..acf5f75f7e23 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -562,7 +562,8 @@ final class InputMonitor {
}
if (mAddNavInputConsumerHandle) {
- mNavInputConsumer.show(mInputTransaction, w);
+ // We set the layer to z=MAX-1 so that it's always on top.
+ mNavInputConsumer.show(mInputTransaction, Integer.MAX_VALUE - 1);
mAddNavInputConsumerHandle = false;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 6c416830b59e..35338bb67469 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -250,7 +250,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, targetActivity);
+ START_TASK_TO_FRONT, targetActivity, null /* options */);
// Register for stack order changes
mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 15a44e8ab2f8..9172897b4869 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5938,31 +5938,12 @@ class Task extends WindowContainer<WindowContainer> {
if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mRootWindowContainer.allPausedActivitiesComplete()) {
- // If the current top activity may be able to occlude keyguard but the occluded state
- // has not been set, update visibility and check again if we should continue to resume.
- boolean nothingToResume = true;
- if (!mAtmService.mShuttingDown) {
- final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
- && next.canShowWhenLocked();
- final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
- && next.containsDismissKeyguardWindow();
-
- if (canShowWhenLocked || mayDismissKeyguard) {
- ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- !PRESERVE_WINDOWS);
- nothingToResume = shouldSleepActivities();
- } else if (next.currentLaunchCanTurnScreenOn() && next.canTurnScreenOn()) {
- nothingToResume = false;
- }
- }
- if (nothingToResume) {
- // Make sure we have executed any pending transitions, since there
- // should be nothing left to do at this point.
- executeAppTransition(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: Going to sleep and all paused");
- return false;
- }
+ // Make sure we have executed any pending transitions, since there
+ // should be nothing left to do at this point.
+ executeAppTransition(options);
+ if (DEBUG_STATES) Slog.d(TAG_STATES,
+ "resumeTopActivityLocked: Going to sleep and all paused");
+ return false;
}
// Make sure that the user who owns this activity is started. If not,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4b9fab4d8ed6..183a1495b075 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5745,14 +5745,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void wipeDataWithReason(int flags, String wipeReasonForUser, boolean parent) {
+ public void wipeDataWithReason(int flags, String wipeReasonForUser,
+ boolean calledOnParentInstance) {
if (!mHasFeature) {
return;
}
final CallerIdentity caller = getCallerIdentity();
boolean calledByProfileOwnerOnOrgOwnedDevice =
isProfileOwnerOfOrganizationOwnedDevice(caller);
- if (parent) {
+ if (calledOnParentInstance) {
Preconditions.checkCallAuthorization(calledByProfileOwnerOnOrgOwnedDevice,
"Wiping the entire device can only be done by a profile owner on "
+ "organization-owned device.");
@@ -5772,7 +5773,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
String.format("No active admin for user %d", caller.getUserId()));
if (TextUtils.isEmpty(wipeReasonForUser)) {
- if (calledByProfileOwnerOnOrgOwnedDevice && !parent) {
+ if (calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance) {
wipeReasonForUser = mContext.getString(R.string.device_ownership_relinquished);
} else {
wipeReasonForUser = mContext.getString(
@@ -5783,7 +5784,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
int userId = admin.getUserHandle().getIdentifier();
if (calledByProfileOwnerOnOrgOwnedDevice) {
// When wipeData is called on the parent instance, it implies wiping the entire device.
- if (parent) {
+ if (calledOnParentInstance) {
userId = UserHandle.USER_SYSTEM;
} else {
// when wipeData is _not_ called on the parent instance, it implies relinquishing
@@ -5808,7 +5809,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON)
.setAdmin(admin.info.getComponent())
.setInt(flags)
- .setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
+ .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
String internalReason = String.format(
"DevicePolicyManager.wipeDataWithReason() from %s, organization-owned? %s",
@@ -7866,15 +7867,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
synchronized (getLockObject()) {
+ final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ final ComponentName poComponent =
+ mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
+ // Return test only admin by default.
+ if (isAdminTestOnlyLocked(doComponent, userHandle.getIdentifier())) {
+ return doComponent;
+ } else if (isAdminTestOnlyLocked(poComponent, userHandle.getIdentifier())) {
+ return poComponent;
+ }
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
if (supervisor == null) {
return null;
}
final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
- final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
- final ComponentName poComponent =
- mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
if (supervisorComponent.equals(doComponent) || supervisorComponent.equals(
poComponent)) {
return supervisorComponent;
@@ -9527,8 +9534,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
&& UserRestrictionsUtils.canProfileOwnerChange(key, userHandle);
boolean orgOwnedProfileOwnerCanChangesGlobally = parent
&& isProfileOwnerOfOrganizationOwnedDevice(caller)
- && UserRestrictionsUtils
- .canProfileOwnerOfOrganizationOwnedDeviceChange(key);
+ && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+ key);
if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
throw new SecurityException("Profile owner cannot set user restriction " + key);
@@ -10224,6 +10231,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException(
"User " + userId + " is not allowed to call setSecondaryLockscreenEnabled");
}
+ synchronized (getLockObject()) {
+ if (isAdminTestOnlyLocked(who, userId)) {
+ // Allow testOnly admins to bypass supervision config requirement.
+ return;
+ }
+ }
// Only the default supervision app can use this API.
final String supervisor = mContext.getResources().getString(
com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
new file mode 100644
index 000000000000..04e8b634e72e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2020 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.server.am;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.am.ActivityManagerService.Injector;
+import com.android.server.appop.AppOpsService;
+import com.android.server.wm.ActivityTaskManagerService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+
+@Presubmit
+public class AppChildProcessTest {
+ private static final String TAG = AppChildProcessTest.class.getSimpleName();
+
+ @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+ @Mock private AppOpsService mAppOpsService;
+ @Mock private PackageManagerInternal mPackageManagerInt;
+ private StaticMockitoSession mMockitoSession;
+
+ private Context mContext = getInstrumentation().getTargetContext();
+ private TestInjector mInjector;
+ private ActivityManagerService mAms;
+ private ProcessList mProcessList;
+ private PhantomProcessList mPhantomProcessList;
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ System.setProperty("dexmaker.share_classloader", "true");
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mMockitoSession = mockitoSession()
+ .spyStatic(Process.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ final ProcessList pList = new ProcessList();
+ mProcessList = spy(pList);
+
+ mInjector = new TestInjector(mContext);
+ mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
+ mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+ mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
+ mAms.mPackageManagerInt = mPackageManagerInt;
+ pList.mService = mAms;
+ mPhantomProcessList = mAms.mPhantomProcessList;
+ doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+ doReturn(false).when(() -> Process.supportsPidFd());
+ // Remove stale instance of PackageManagerInternal if there is any
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ mMockitoSession.finishMocking();
+ mHandlerThread.quit();
+ }
+
+ @Test
+ public void testManageAppChildProcesses() throws Exception {
+ final int initPid = 1;
+ final int rootUid = 0;
+ final int zygote64Pid = 100;
+ final int zygote32Pid = 101;
+ final int app1Pid = 200;
+ final int app2Pid = 201;
+ final int app1Uid = 10000;
+ final int app2Uid = 10001;
+ final int child1Pid = 300;
+ final int child2Pid = 301;
+ final int nativePid = 400;
+ final String zygote64ProcessName = "zygote64";
+ final String zygote32ProcessName = "zygote32";
+ final String app1ProcessName = "test1";
+ final String app2ProcessName = "test2";
+ final String child1ProcessName = "test1_child1";
+ final String child2ProcessName = "test1_child1_child2";
+ final String nativeProcessName = "test_native";
+
+ makeParent(zygote64Pid, initPid);
+ makeParent(zygote32Pid, initPid);
+
+ makeAppProcess(app1Pid, app1Uid, app1ProcessName, app1ProcessName);
+ makeParent(app1Pid, zygote64Pid);
+ makeAppProcess(app2Pid, app2Uid, app2ProcessName, app2ProcessName);
+ makeParent(app2Pid, zygote64Pid);
+
+ assertEquals(0, mPhantomProcessList.mPhantomProcesses.size());
+
+ // Verify zygote itself isn't a phantom process
+ assertEquals(null, mPhantomProcessList.getOrCreatePhantomProcessIfNeededLocked(
+ zygote64ProcessName, rootUid, zygote64Pid));
+ assertEquals(null, mPhantomProcessList.getOrCreatePhantomProcessIfNeededLocked(
+ zygote32ProcessName, rootUid, zygote32Pid));
+ // Verify none of the app isn't a phantom process
+ assertEquals(null, mPhantomProcessList.getOrCreatePhantomProcessIfNeededLocked(
+ app1ProcessName, app1Uid, app1Pid));
+ assertEquals(null, mPhantomProcessList.getOrCreatePhantomProcessIfNeededLocked(
+ app2ProcessName, app2Uid, app2Pid));
+
+ // "Fork" an app child process
+ makeParent(child1Pid, app1Pid);
+ PhantomProcessRecord pr = mPhantomProcessList
+ .getOrCreatePhantomProcessIfNeededLocked(child1ProcessName, app1Uid, child1Pid);
+ assertTrue(pr != null);
+ assertEquals(1, mPhantomProcessList.mPhantomProcesses.size());
+ assertEquals(pr, mPhantomProcessList.mPhantomProcesses.valueAt(0));
+ verifyPhantomProcessRecord(pr, child1ProcessName, app1Uid, child1Pid);
+
+ // Create another native process from init
+ makeParent(nativePid, initPid);
+ assertEquals(null, mPhantomProcessList.getOrCreatePhantomProcessIfNeededLocked(
+ nativeProcessName, rootUid, nativePid));
+ assertEquals(1, mPhantomProcessList.mPhantomProcesses.size());
+ assertEquals(pr, mPhantomProcessList.mPhantomProcesses.valueAt(0));
+
+ // "Fork" another app child process
+ makeParent(child2Pid, child1Pid);
+ PhantomProcessRecord pr2 = mPhantomProcessList
+ .getOrCreatePhantomProcessIfNeededLocked(child2ProcessName, app1Uid, child2Pid);
+ assertTrue(pr2 != null);
+ assertEquals(2, mPhantomProcessList.mPhantomProcesses.size());
+ verifyPhantomProcessRecord(pr2, child2ProcessName, app1Uid, child2Pid);
+
+ ArraySet<PhantomProcessRecord> set = new ArraySet<>();
+ set.add(pr);
+ set.add(pr2);
+ for (int i = mPhantomProcessList.mPhantomProcesses.size() - 1; i >= 0; i--) {
+ set.remove(mPhantomProcessList.mPhantomProcesses.valueAt(i));
+ }
+ assertEquals(0, set.size());
+ }
+
+ private void verifyPhantomProcessRecord(PhantomProcessRecord pr,
+ String processName, int uid, int pid) {
+ assertEquals(processName, pr.mProcessName);
+ assertEquals(uid, pr.mUid);
+ assertEquals(pid, pr.mPid);
+ }
+
+ private void makeAppProcess(int pid, int uid, String packageName, String processName) {
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = packageName;
+ ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid);
+ app.pid = pid;
+ mAms.mPidsSelfLocked.doAddInternal(app);
+ }
+
+ private void makeParent(int pid, int ppid) {
+ doReturn(ppid).when(() -> Process.getParentPid(eq(pid)));
+ }
+
+ private class TestInjector extends Injector {
+ TestInjector(Context context) {
+ super(context);
+ }
+
+ @Override
+ public AppOpsService getAppOpsService(File file, Handler handler) {
+ return mAppOpsService;
+ }
+
+ @Override
+ public Handler getUiHandler(ActivityManagerService service) {
+ return mHandler;
+ }
+
+ @Override
+ public ProcessList getProcessList(ActivityManagerService service) {
+ return mProcessList;
+ }
+ }
+
+ static class ServiceThreadRule implements TestRule {
+ private ServiceThread mThread;
+
+ ServiceThread getThread() {
+ return mThread;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ mThread = new ServiceThread("TestServiceThread",
+ Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */);
+ mThread.start();
+ try {
+ base.evaluate();
+ } finally {
+ mThread.getThreadHandler().runWithScissors(mThread::quit, 0 /* timeout */);
+ }
+ }
+ };
+ }
+ }
+
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 8db09b4f156c..e9a50b36693a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -120,6 +120,7 @@ public class ApplicationExitInfoTest {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mProcessList = spy(new ProcessList());
+ ProcessList.sKillHandler = null;
mAppExitInfoTracker = spy(new AppExitInfoTracker());
setFieldValue(AppExitInfoTracker.class, mAppExitInfoTracker, "mIsolatedUidRecords",
spy(mAppExitInfoTracker.new IsolatedUidRecords()));
@@ -147,6 +148,7 @@ public class ApplicationExitInfoTest {
public void tearDown() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
mHandlerThread.quit();
+ ProcessList.sKillHandler = null;
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index 80ad0a838bbb..c36cdeb582bd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -24,7 +24,6 @@ import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.location.Criteria.ACCURACY_COARSE;
import static android.location.Criteria.ACCURACY_FINE;
import static android.location.Criteria.POWER_HIGH;
-import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
import static androidx.test.ext.truth.location.LocationSubject.assertThat;
@@ -356,8 +355,7 @@ public class LocationProviderManagerTest {
@Test
public void testPassive_Listener() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
- 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -382,8 +380,7 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -437,8 +434,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -451,8 +447,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_Unregister() throws Exception {
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), IDENTITY,
PERMISSION_FINE, listener);
mManager.unregisterLocationRequest(listener);
@@ -470,8 +465,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
@@ -493,8 +487,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NumUpdates() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setNumUpdates(5);
+ LocationRequest request = new LocationRequest.Builder(0).setMaxUpdates(5).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -511,8 +504,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(5000);
+ LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(5000).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
long baseTimeMs = SystemClock.elapsedRealtime();
@@ -535,8 +527,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_ExpiringNoAlarm() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(25);
+ LocationRequest request = new LocationRequest.Builder(0).setDurationMillis(25).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Thread.sleep(25);
@@ -547,22 +538,10 @@ public class LocationProviderManagerTest {
}
@Test
- public void testRegisterListener_AlreadyExpired() throws Exception {
- ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setExpireIn(-1);
- mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
-
- mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
- nullable(IRemoteCallback.class));
- }
-
- @Test
public void testRegisterListener_FastestInterval() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
- false).setFastestInterval(5000);
+ LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateIntervalMillis(
+ 5000).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
@@ -575,8 +554,8 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_SmallestDisplacement() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
- false).setSmallestDisplacement(1f);
+ LocationRequest request = new LocationRequest.Builder(5000).setMinUpdateDistanceMeters(
+ 1f).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
Location loc = createLocation(NAME, mRandom);
@@ -590,7 +569,7 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener_NoteOpFailure() throws Exception {
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
@@ -608,8 +587,7 @@ public class LocationProviderManagerTest {
"attribution");
ILocationListener listener = createMockLocationListener();
- mManager.registerLocationRequest(
- LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ mManager.registerLocationRequest(new LocationRequest.Builder(0).build(), identity,
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
@@ -637,8 +615,7 @@ public class LocationProviderManagerTest {
ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -654,8 +631,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Cancel() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -669,8 +645,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_ProviderDisabled() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -686,8 +661,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderAllowed(false);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -705,8 +679,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(loc);
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -718,8 +691,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_Timeout() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
- LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false);
+ LocationRequest locationRequest = new LocationRequest.Builder(0).build();
ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
mManager.getCurrentLocation(locationRequest, IDENTITY,
PERMISSION_FINE, cancellationSignal, listener);
@@ -742,7 +714,7 @@ public class LocationProviderManagerTest {
IDENTITY.getPackageName())).isFalse();
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest request = new LocationRequest.Builder(0).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
@@ -771,7 +743,7 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().locationRequests).isEmpty();
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -782,8 +754,7 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().workSource).isNotNull();
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLowPowerMode(true);
+ LocationRequest request2 = new LocationRequest.Builder(1).setLowPower(true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -811,7 +782,7 @@ public class LocationProviderManagerTest {
@Test
public void testProviderRequest_BackgroundThrottle() {
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().interval).isEqualTo(5);
@@ -827,7 +798,7 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -835,8 +806,8 @@ public class LocationProviderManagerTest {
assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request2 = new LocationRequest.Builder(1).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().reportLocation).isTrue();
@@ -850,12 +821,12 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0, false);
+ LocationRequest request1 = new LocationRequest.Builder(1).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
ILocationListener listener2 = createMockLocationListener();
- LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request2 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
@@ -872,8 +843,8 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request = new LocationRequest.Builder(1).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
@@ -889,8 +860,8 @@ public class LocationProviderManagerTest {
Collections.singleton(IDENTITY.getPackageName()));
ILocationListener listener1 = createMockLocationListener();
- LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
- false).setLocationSettingsIgnored(true);
+ LocationRequest request1 = new LocationRequest.Builder(5).setLocationSettingsIgnored(
+ true).build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().interval).isEqualTo(5);
@@ -905,7 +876,7 @@ public class LocationProviderManagerTest {
LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
ILocationListener listener = createMockLocationListener();
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ LocationRequest request = new LocationRequest.Builder(5).build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
assertThat(mProvider.getRequest().reportLocation).isTrue();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
index 69a9f4415fe7..0b5a6998cd0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
@@ -43,7 +43,6 @@ import org.mockito.InOrder;
import java.util.Collection;
import java.util.function.Consumer;
-import java.util.function.Predicate;
@SuppressWarnings("unchecked")
@Presubmit
@@ -355,10 +354,6 @@ public class ListenerMultiplexerTest {
removeRegistration(consumer, registration);
}
- public void removeListenerIf(Predicate<Consumer<TestListenerRegistration>> predicate) {
- removeRegistrationIf(predicate);
- }
-
public void setActive(Integer request, boolean active) {
updateRegistrations(testRegistration -> {
if (testRegistration.getRequest().equals(request)) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 8759077ea0ad..3a8d9c3e9ff5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4392,6 +4392,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ // Ensure packages are *not* flagged as test_only.
+ doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
+ eq(admin1.getPackageName()),
+ anyInt(),
+ eq(CALLER_USER_HANDLE));
+ doReturn(new ApplicationInfo()).when(getServices().ipackageManager).getApplicationInfo(
+ eq(admin2.getPackageName()),
+ anyInt(),
+ eq(CALLER_USER_HANDLE));
+
// Initial state is disabled.
assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
index f72dbf6ed0b0..d8f5c4c8f58c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -17,6 +17,9 @@ package com.android.server.hdmi;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import android.platform.test.annotations.Presubmit;
import android.util.Slog;
@@ -145,4 +148,91 @@ public class HdmiUtilsTest {
assertThat(config).isEqualTo(expectedConfig);
}
+
+ @Test
+ public void isAffectingActiveRoutingPath() {
+ // New path alters the parent
+ assertTrue(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x2000));
+ // New path is a sibling
+ assertTrue(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x1200));
+ // New path is the descendant of a sibling
+ assertFalse(HdmiUtils.isAffectingActiveRoutingPath(0x1100, 0x1210));
+ // In a completely different path
+ assertFalse(HdmiUtils.isAffectingActiveRoutingPath(0x1000, 0x3200));
+ }
+
+ @Test
+ public void isInActiveRoutingPath() {
+ // New path is a parent
+ assertTrue(HdmiUtils.isInActiveRoutingPath(0x1100, 0x1000));
+ // New path is a descendant
+ assertTrue(HdmiUtils.isInActiveRoutingPath(0x1210, 0x1212));
+ // New path is a sibling
+ assertFalse(HdmiUtils.isInActiveRoutingPath(0x1100, 0x1200));
+ // In a completely different path
+ assertFalse(HdmiUtils.isInActiveRoutingPath(0x1000, 0x2000));
+ }
+
+ @Test
+ public void pathRelationship_unknown() {
+ assertThat(HdmiUtils.pathRelationship(0x1234, Constants.INVALID_PHYSICAL_ADDRESS))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ assertThat(HdmiUtils.pathRelationship(Constants.INVALID_PHYSICAL_ADDRESS, 0x1234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ assertThat(HdmiUtils.pathRelationship(Constants.INVALID_PHYSICAL_ADDRESS,
+ Constants.INVALID_PHYSICAL_ADDRESS))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_UNKNOWN);
+ }
+
+ @Test
+ public void pathRelationship_differentBranch() {
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x2000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1224))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1134))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x2234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DIFFERENT_BRANCH);
+ }
+
+ @Test
+ public void pathRelationship_ancestor() {
+ assertThat(HdmiUtils.pathRelationship(0x0000, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ assertThat(HdmiUtils.pathRelationship(0x1000, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x1230))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_ANCESTOR);
+ }
+
+ @Test
+ public void pathRelationship_descendant() {
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x0000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1200))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_DESCENDANT);
+ }
+
+ @Test
+ public void pathRelationship_sibling() {
+ assertThat(HdmiUtils.pathRelationship(0x1000, 0x2000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1200, 0x1100))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1230, 0x1220))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1233))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SIBLING);
+ }
+
+ @Test
+ public void pathRelationship_same() {
+ assertThat(HdmiUtils.pathRelationship(0x0000, 0x0000))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SAME);
+ assertThat(HdmiUtils.pathRelationship(0x1234, 0x1234))
+ .isEqualTo(Constants.PATH_RELATIONSHIP_SAME);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index e860f2508983..9be31647cf73 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -33,6 +33,8 @@ import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.timeout;
+import android.app.ActivityOptions;
+import android.app.ActivityOptions.SourceInfo;
import android.content.Intent;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -68,6 +70,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private ActivityRecord mTrampolineActivity;
private ActivityRecord mTopActivity;
+ private ActivityOptions mActivityOptions;
private boolean mLaunchTopByTrampoline;
@Before
@@ -209,6 +212,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testOnReportFullyDrawn() {
+ mActivityOptions = ActivityOptions.makeBasic();
+ mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
onActivityLaunched(mTopActivity);
// The activity reports fully drawn before windows drawn, then the fully drawn event will
@@ -216,7 +221,10 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
notifyTransitionStarting(mTopActivity);
// The pending fully drawn event should send when the actual windows drawn event occurs.
- notifyWindowsDrawn(mTopActivity);
+ final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity);
+ assertWithMessage("Record start source").that(info.sourceType)
+ .isEqualTo(SourceInfo.TYPE_LAUNCHER);
+ assertWithMessage("Record event time").that(info.sourceEventDelayMs).isAtLeast(10);
verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
verifyOnActivityLaunchFinished(mTopActivity);
@@ -251,7 +259,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
}
private void notifyActivityLaunched(int resultCode, ActivityRecord activity) {
- mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity);
+ mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity,
+ mActivityOptions);
}
private void notifyTransitionStarting(ActivityRecord activity) {
@@ -260,8 +269,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityMetricsLogger.notifyTransitionStarting(reasons);
}
- private void notifyWindowsDrawn(ActivityRecord r) {
- mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
+ private ActivityMetricsLogger.TransitionInfoSnapshot notifyWindowsDrawn(ActivityRecord r) {
+ return mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
}
@Test
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
index 35cf45fe36ed..7a9b34b16058 100644
--- a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
+++ b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
@@ -157,7 +157,9 @@ public final class NativeScanResult implements Parcelable {
BSS_CAPABILITY_RADIO_MANAGEMENT,
BSS_CAPABILITY_DSSS_OFDM,
BSS_CAPABILITY_DELAYED_BLOCK_ACK,
- BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK
+ BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK,
+ BSS_CAPABILITY_DMG_ESS,
+ BSS_CAPABILITY_DMG_IBSS
})
public @interface BssCapabilityBits { }