diff options
183 files changed, 5734 insertions, 2088 deletions
diff --git a/Android.bp b/Android.bp index abd7d2d6602a..4e2b156afbbf 100644 --- a/Android.bp +++ b/Android.bp @@ -226,6 +226,7 @@ filegroup { ":framework-wifi-non-updatable-sources", ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", + ":net-utils-framework-common-srcs", // AIDL from frameworks/base/native/ ":platform-compat-native-aidl", @@ -348,7 +349,6 @@ java_library { "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", - "android.hardware.wifi-V1.0-java-constants", "devicepolicyprotosnano", "com.android.sysprop.apex", @@ -487,7 +487,7 @@ java_library { "framework-minus-apex", "updatable_media_stubs", "framework_mediaprovider_stubs", - "framework-appsearch-stubs", + "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs "framework-sdkextensions-stubs-systemapi", // TODO(b/146167933): Use framework-statsd-stubs instead. "framework-statsd", @@ -506,7 +506,10 @@ java_library { defaults: ["framework-defaults"], srcs: [":framework-all-sources"], installable: false, - static_libs: ["exoplayer2-core"], + static_libs: [ + "exoplayer2-core", + "android.hardware.wifi-V1.0-java-constants", + ], apex_available: ["//apex_available:platform"], } @@ -604,17 +607,22 @@ gensrcs { filegroup { name: "framework-annotations", srcs: [ + "core/java/android/annotation/CallbackExecutor.java", + "core/java/android/annotation/CheckResult.java", "core/java/android/annotation/IntDef.java", "core/java/android/annotation/IntRange.java", "core/java/android/annotation/NonNull.java", "core/java/android/annotation/Nullable.java", "core/java/android/annotation/RequiresPermission.java", "core/java/android/annotation/SdkConstant.java", + "core/java/android/annotation/StringDef.java", "core/java/android/annotation/SystemApi.java", + "core/java/android/annotation/SystemService.java", "core/java/android/annotation/TestApi.java", "core/java/android/annotation/UnsupportedAppUsage.java", "core/java/com/android/internal/annotations/GuardedBy.java", "core/java/com/android/internal/annotations/VisibleForTesting.java", + "core/java/com/android/internal/annotations/Immutable.java", ], } @@ -629,6 +637,9 @@ filegroup { visibility: ["//frameworks/opt/net/ike"], srcs: [ "core/java/android/net/annotations/PolicyDirection.java", + "core/java/com/android/internal/util/IState.java", + "core/java/com/android/internal/util/State.java", + "core/java/com/android/internal/util/StateMachine.java", "telephony/java/android/telephony/Annotation.java", ], } @@ -1148,13 +1159,36 @@ filegroup { ], } +// utility classes statically linked into framework-wifi and dynamically linked +// into wifi-service +java_library { + name: "framework-wifi-util-lib", + sdk_version: "core_current", + srcs: [ + "core/java/android/content/pm/BaseParceledListSlice.java", + "core/java/android/content/pm/ParceledListSlice.java", + "core/java/android/net/shared/Inet4AddressUtils.java", + "core/java/android/os/HandlerExecutor.java", + "core/java/com/android/internal/util/AsyncChannel.java", + "core/java/com/android/internal/util/AsyncService.java", + "core/java/com/android/internal/util/Protocol.java", + "core/java/com/android/internal/util/Preconditions.java", + "telephony/java/android/telephony/Annotation.java", + ], + libs: [ + "framework-annotations-lib", + "unsupportedappusage", + "android_system_stubs_current", + ], + visibility: ["//frameworks/base/wifi"], +} + +// utility classes statically linked into wifi-service filegroup { name: "framework-wifi-service-shared-srcs", srcs: [ - ":framework-annotations", "core/java/android/net/InterfaceConfiguration.java", "core/java/android/os/BasicShellCommandHandler.java", - "core/java/android/os/HandlerExecutor.java", "core/java/android/util/BackupUtils.java", "core/java/android/util/LocalLog.java", "core/java/android/util/Rational.java", @@ -1162,11 +1196,9 @@ filegroup { "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/MessageUtils.java", - "core/java/com/android/internal/util/Preconditions.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", "core/java/com/android/internal/util/WakeupMessage.java", - "core/java/com/android/internal/util/XmlUtils.java", ], } diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp index 60cc3bec0a9d..1f30dda21ef7 100644 --- a/apex/appsearch/framework/Android.bp +++ b/apex/appsearch/framework/Android.bp @@ -30,10 +30,29 @@ java_library { libs: [ "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs ], - visibility: ["//frameworks/base/apex/appsearch:__subpackages__"], + visibility: [ + "//frameworks/base/apex/appsearch:__subpackages__", + // TODO(b/146218515) remove this when framework is built with the stub of appsearch + "//frameworks/base", + ], apex_available: ["com.android.appsearch"], } +metalava_appsearch_docs_args = + "--hide-package com.android.server " + + "--error UnhiddenSystemApi " + + "--hide RequiresPermission " + + "--hide MissingPermission " + + "--hide BroadcastBehavior " + + "--hide HiddenSuperclass " + + "--hide DeprecationMismatch " + + "--hide UnavailableSymbol " + + "--hide SdkConstant " + + "--hide HiddenTypeParameter " + + "--hide Todo --hide Typo " + + "--hide HiddenTypedefConstant " + + "--show-annotation android.annotation.SystemApi " + droidstubs { name: "framework-appsearch-stubs-srcs", srcs: [ @@ -43,8 +62,9 @@ droidstubs { aidl: { include_dirs: ["frameworks/base/core/java"], }, - defaults: ["framework-module-stubs-defaults-systemapi"], - sdk_version: "system_current", + args: metalava_appsearch_docs_args, + sdk_version: "core_current", + libs: ["android_system_stubs_current"], } java_library { @@ -55,6 +75,7 @@ java_library { "java", ], }, - sdk_version: "system_current", + sdk_version: "core_current", + libs: ["android_system_stubs_current"], installable: false, } diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp index e7abcd9a645a..8aed5d04a32b 100644 --- a/apex/appsearch/service/Android.bp +++ b/apex/appsearch/service/Android.bp @@ -20,7 +20,6 @@ java_library { libs: [ "framework", "services.core", - "framework-appsearch", ], static_libs: [ "icing-java-proto-lite", diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 3f58c72cbdc2..f8b2f32e1a2f 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -761,6 +761,7 @@ public class DeviceIdleController extends SystemService @Override public void onTrigger(TriggerEvent event) { synchronized (DeviceIdleController.this) { + // One_shot sensors (which call onTrigger) are unregistered when onTrigger is called active = false; motionLocked(); } @@ -769,6 +770,9 @@ public class DeviceIdleController extends SystemService @Override public void onSensorChanged(SensorEvent event) { synchronized (DeviceIdleController.this) { + // Since one_shot sensors are unregistered when onTrigger is called, unregister + // listeners here so that the MotionListener is in a consistent state when it calls + // out to motionLocked. mSensorManager.unregisterListener(this, mMotionSensor); active = false; motionLocked(); diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 0f981e25b37a..bbb87ab6ce7c 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -714,60 +714,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void addNetworkStats( - int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) { - int size = stats.size(); - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - long wallClockNanos = SystemClock.currentTimeMicro() * 1000L; - NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling - for (int j = 0; j < size; j++) { - stats.getValues(j, entry); - StatsLogEventWrapper e = new StatsLogEventWrapper(tag, elapsedNanos, wallClockNanos); - e.writeInt(entry.uid); - if (withFGBG) { - e.writeInt(entry.set); - } - e.writeLong(entry.rxBytes); - e.writeLong(entry.rxPackets); - e.writeLong(entry.txBytes); - e.writeLong(entry.txPackets); - ret.add(e); - } - } - - /** - * Allows rollups per UID but keeping the set (foreground/background) slicing. - * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java - */ - private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { - final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.iface = NetworkStats.IFACE_ALL; - entry.tag = NetworkStats.TAG_NONE; - entry.metered = NetworkStats.METERED_ALL; - entry.roaming = NetworkStats.ROAMING_ALL; - - int size = stats.size(); - NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values - for (int i = 0; i < size; i++) { - stats.getValues(i, recycle); - - // Skip specific tags, since already counted in TAG_NONE - if (recycle.tag != NetworkStats.TAG_NONE) continue; - - entry.set = recycle.set; // Allows slicing by background/foreground - entry.uid = recycle.uid; - entry.rxBytes = recycle.rxBytes; - entry.rxPackets = recycle.rxPackets; - entry.txBytes = recycle.txBytes; - entry.txPackets = recycle.txPackets; - // Operations purposefully omitted since we don't use them for statsd. - ret.combineValues(entry); - } - return ret; - } - /** * Helper method to extract the Parcelable controller info from a * SynchronousResultReceiver. @@ -815,94 +761,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullWifiBytesTransferByFgBg( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getWifiIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - NetworkStats stats = rollupNetworkStatsByFGBG( - mNetworkStatsService.getDetailedUidStats(ifaces)); - addNetworkStats(tagId, pulledData, stats, true); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private void pullMobileBytesTransfer( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getMobileIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - // Combine all the metrics per Uid into one record. - NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid(); - addNetworkStats(tagId, pulledData, stats, false); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private void pullBluetoothBytesTransfer( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); - if (info.getUidTraffic() != null) { - for (UidTraffic traffic : info.getUidTraffic()) { - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeInt(traffic.getUid()); - e.writeLong(traffic.getRxBytes()); - e.writeLong(traffic.getTxBytes()); - pulledData.add(e); - } - } - } - - private void pullMobileBytesTransferByFgBg( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getMobileIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - NetworkStats stats = rollupNetworkStatsByFGBG( - mNetworkStatsService.getDetailedUidStats(ifaces)); - addNetworkStats(tagId, pulledData, stats, true); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - private void pullCpuTimePerFreq( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { @@ -1052,33 +910,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullBluetoothActivityInfo( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeLong(info.getTimeStamp()); - e.writeInt(info.getBluetoothStackState()); - e.writeLong(info.getControllerTxTimeMillis()); - e.writeLong(info.getControllerRxTimeMillis()); - e.writeLong(info.getControllerIdleTimeMillis()); - e.writeLong(info.getControllerEnergyUsed()); - pulledData.add(e); - } - - private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( - "bluetooth"); - adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); - return awaitControllerInfo(bluetoothReceiver); - } else { - Slog.e(TAG, "Failed to get bluetooth adapter!"); - return null; - } - } - private void pullSystemElapsedRealtime( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { @@ -1671,21 +1502,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullPowerProfile( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - PowerProfile powerProfile = new PowerProfile(mContext); - Objects.requireNonNull(powerProfile); - - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - ProtoOutputStream proto = new ProtoOutputStream(); - powerProfile.dumpDebug(proto); - proto.flush(); - e.writeStorage(proto.getBytes()); - pulledData.add(e); - } - private void pullBuildInformation(int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); @@ -2291,26 +2107,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { long elapsedNanos = SystemClock.elapsedRealtimeNanos(); long wallClockNanos = SystemClock.currentTimeMicro() * 1000L; switch (tagId) { - - case StatsLog.MOBILE_BYTES_TRANSFER: { - pullMobileBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: { - pullWifiBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: { - pullMobileBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.BLUETOOTH_BYTES_TRANSFER: { - pullBluetoothBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret); - break; - } case StatsLog.KERNEL_WAKELOCK: { pullKernelWakelock(tagId, elapsedNanos, wallClockNanos, ret); @@ -2352,11 +2148,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.BLUETOOTH_ACTIVITY_INFO: { - pullBluetoothActivityInfo(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.SYSTEM_UPTIME: { pullSystemUpTime(tagId, elapsedNanos, wallClockNanos, ret); break; @@ -2455,11 +2246,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.POWER_PROFILE: { - pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.BUILD_INFORMATION: { pullBuildInformation(tagId, elapsedNanos, wallClockNanos, ret); break; diff --git a/api/current.txt b/api/current.txt index 5ab1c0171c61..504f055d41a6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6764,6 +6764,7 @@ package android.app.admin { method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String); method public CharSequence getDeviceOwnerLockScreenInfo(); method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName); + method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName); method @Nullable public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName); method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName); method @NonNull public java.util.List<byte[]> getInstalledCaCerts(@Nullable android.content.ComponentName); @@ -6882,6 +6883,7 @@ package android.app.admin { method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>); method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence); method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence); + method public void setFactoryResetProtectionPolicy(@NonNull android.content.ComponentName, @Nullable android.app.admin.FactoryResetProtectionPolicy); method public int setGlobalPrivateDnsModeOpportunistic(@NonNull android.content.ComponentName); method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String); method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String); @@ -7116,6 +7118,21 @@ package android.app.admin { field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR; } + public final class FactoryResetProtectionPolicy implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getFactoryResetProtectionAccounts(); + method public boolean isFactoryResetProtectionDisabled(); + method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FactoryResetProtectionPolicy> CREATOR; + } + + public static class FactoryResetProtectionPolicy.Builder { + ctor public FactoryResetProtectionPolicy.Builder(); + method @NonNull public android.app.admin.FactoryResetProtectionPolicy build(); + method @NonNull public android.app.admin.FactoryResetProtectionPolicy.Builder setFactoryResetProtectionAccounts(@NonNull java.util.List<java.lang.String>); + method @NonNull public android.app.admin.FactoryResetProtectionPolicy.Builder setFactoryResetProtectionDisabled(boolean); + } + public class FreezePeriod { ctor public FreezePeriod(java.time.MonthDay, java.time.MonthDay); method public java.time.MonthDay getEnd(); @@ -10009,6 +10026,7 @@ package android.content { field public static final String MEDIA_ROUTER_SERVICE = "media_router"; field public static final String MEDIA_SESSION_SERVICE = "media_session"; field public static final String MIDI_SERVICE = "midi"; + field public static final String MMS_SERVICE = "mms"; field public static final int MODE_APPEND = 32768; // 0x8000 field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8 field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4 @@ -17062,13 +17080,13 @@ package android.hardware.camera2 { method public abstract void close(); method @NonNull public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException; method @NonNull public android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int, java.util.Set<java.lang.String>) throws android.hardware.camera2.CameraAccessException; - method public abstract void createCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; method public void createCaptureSession(android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException; - method public abstract void createCaptureSessionByOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract void createConstrainedHighSpeedCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createCaptureSessionByOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createConstrainedHighSpeedCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; method @NonNull public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(@NonNull android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException; - method public abstract void createReprocessableCaptureSession(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; - method public abstract void createReprocessableCaptureSessionByConfigurations(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createReprocessableCaptureSession(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createReprocessableCaptureSessionByConfigurations(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; method public int getCameraAudioRestriction() throws android.hardware.camera2.CameraAccessException; method @NonNull public abstract String getId(); method public boolean isSessionConfigurationSupported(@NonNull android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException; @@ -28683,7 +28701,9 @@ package android.media.tv { ctor public TvInputService(); method public final android.os.IBinder onBind(android.content.Intent); method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(String); + method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String, @NonNull String); method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(String); + method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String); field public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService"; field public static final String SERVICE_META_DATA = "android.media.tv.input"; } @@ -30626,6 +30646,7 @@ package android.net.wifi { field public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; field public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; field public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION = "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION"; + field public static final String ACTION_WIFI_SCAN_AVAILABLE = "android.net.wifi.action.WIFI_SCAN_AVAILABLE"; field @Deprecated public static final int ERROR_AUTHENTICATING = 1; // 0x1 field @Deprecated public static final String EXTRA_BSSID = "bssid"; field public static final String EXTRA_NETWORK_INFO = "networkInfo"; @@ -30634,6 +30655,7 @@ package android.net.wifi { field @Deprecated public static final String EXTRA_NEW_STATE = "newState"; field public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state"; field public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated"; + field public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE"; field @Deprecated public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; field @Deprecated public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError"; field @Deprecated public static final String EXTRA_WIFI_INFO = "wifiInfo"; @@ -45142,7 +45164,7 @@ package android.telephony { field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool"; field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool"; field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool"; - field public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; + field @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool"; field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool"; @@ -45165,6 +45187,7 @@ package android.telephony { field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int"; field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool"; field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string"; + field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; @@ -45633,6 +45656,11 @@ package android.telephony { method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback); } + public class MmsManager { + method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent); + method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent); + } + @Deprecated public class NeighboringCellInfo implements android.os.Parcelable { ctor @Deprecated public NeighboringCellInfo(); ctor @Deprecated public NeighboringCellInfo(int, int); @@ -45870,8 +45898,8 @@ package android.telephony { method public String createAppSpecificSmsToken(android.app.PendingIntent); method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent); method public java.util.ArrayList<java.lang.String> divideMessage(String); - method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); - method @Nullable public android.os.Bundle getCarrierConfigValues(); + method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); + method @NonNull public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); @@ -45880,7 +45908,7 @@ package android.telephony { method public int getSubscriptionId(); method public void injectSmsPdu(byte[], String, android.app.PendingIntent); method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); - method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent); + method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent); method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent); method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent); @@ -54794,6 +54822,7 @@ package android.view.inputmethod { public final class InlineSuggestionsRequest implements android.os.Parcelable { method public int describeContents(); + method @NonNull public String getHostPackageName(); method public int getMaxSuggestionCount(); method @NonNull public java.util.List<android.view.inline.InlinePresentationSpec> getPresentationSpecs(); method public void writeToParcel(@NonNull android.os.Parcel, int); diff --git a/api/system-current.txt b/api/system-current.txt index a1bb3c821b5a..dfa0a23fa6a1 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -211,6 +211,7 @@ package android { field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; + field public static final String TUNER_RESOURCE_ACCESS = "android.permission.TUNER_RESOURCE_ACCESS"; field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"; field public static final String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS"; @@ -283,6 +284,7 @@ package android { field public static final int config_helpIntentNameKey = 17039390; // 0x104001e field public static final int config_helpPackageNameKey = 17039387; // 0x104001b field public static final int config_helpPackageNameValue = 17039388; // 0x104001c + field public static final int config_systemGallery = 17039402; // 0x104002a } public static final class R.style { @@ -815,6 +817,7 @@ package android.app.admin { field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION"; field public static final String ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE"; field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE"; + field public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = "android.app.action.RESET_PROTECTION_POLICY_CHANGED"; field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER"; field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE"; field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME"; @@ -1711,6 +1714,7 @@ package android.content { field public static final String NETD_SERVICE = "netd"; field public static final String NETWORK_POLICY_SERVICE = "netpolicy"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; @@ -2413,7 +2417,7 @@ package android.hardware.biometrics { package android.hardware.camera2 { public abstract class CameraDevice implements java.lang.AutoCloseable { - method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1 field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0 field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000 @@ -4402,10 +4406,12 @@ package android.media.soundtrigger { } public static class SoundTriggerManager.Model { - method public static android.media.soundtrigger.SoundTriggerManager.Model create(java.util.UUID, java.util.UUID, byte[]); - method public byte[] getModelData(); - method public java.util.UUID getModelUuid(); - method public java.util.UUID getVendorUuid(); + method @NonNull public static android.media.soundtrigger.SoundTriggerManager.Model create(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], int); + method @NonNull public static android.media.soundtrigger.SoundTriggerManager.Model create(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[]); + method @Nullable public byte[] getModelData(); + method @NonNull public java.util.UUID getModelUuid(); + method @NonNull public java.util.UUID getVendorUuid(); + method public int getVersion(); } } @@ -4535,6 +4541,7 @@ package android.media.tv { method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating); method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig); method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String); + method @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) public int getClientPid(@NonNull String); method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList(); method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList(); method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList(); @@ -4546,6 +4553,7 @@ package android.media.tv { method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware); method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void removeBlockedRating(@NonNull android.media.tv.TvContentRating); method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void setParentalControlsEnabled(boolean); + field public static final int UNKNOWN_CLIENT_PID = -1; // 0xffffffff } public static final class TvInputManager.Hardware { @@ -4679,10 +4687,30 @@ package android.media.tv.tuner { package android.media.tv.tuner.filter { + public abstract class FilterConfiguration { + field public static final int FILTER_TYPE_ALP = 16; // 0x10 + field public static final int FILTER_TYPE_IP = 4; // 0x4 + field public static final int FILTER_TYPE_MMTP = 2; // 0x2 + field public static final int FILTER_TYPE_TLV = 8; // 0x8 + field public static final int FILTER_TYPE_TS = 1; // 0x1 + } + public abstract class FilterEvent { ctor public FilterEvent(); } + public class PesSettings extends android.media.tv.tuner.filter.Settings { + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.PesSettings.Builder builder(@NonNull android.content.Context, int); + method public int getStreamId(); + method public boolean isRaw(); + } + + public static class PesSettings.Builder { + method @NonNull public android.media.tv.tuner.filter.PesSettings build(); + method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setRaw(boolean); + method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setStreamId(int); + } + public class SectionEvent extends android.media.tv.tuner.filter.FilterEvent { method public int getDataLength(); method public int getSectionNumber(); @@ -4690,6 +4718,22 @@ package android.media.tv.tuner.filter { method public int getVersion(); } + public abstract class Settings { + } + + public class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration { + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder(@NonNull android.content.Context); + method @Nullable public android.media.tv.tuner.filter.Settings getSettings(); + method public int getTpid(); + method public int getType(); + } + + public static class TsFilterConfiguration.Builder { + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build(); + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@NonNull android.media.tv.tuner.filter.Settings); + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int); + } + } package android.metrics { @@ -4740,7 +4784,9 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { method public void logEvent(int, @NonNull String); + method public void reevaluateNetwork(); method public void useNetwork(); + field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64 field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2 @@ -4770,6 +4816,7 @@ package android.net { field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TYPE_NONE = -1; // 0xffffffff } public abstract static class ConnectivityManager.OnStartTetheringCallback { @@ -4911,6 +4958,23 @@ package android.net { field public final int netId; } + public final class NetworkAgentConfig implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getSubscriberId(); + method public boolean isNat64DetectionEnabled(); + method public boolean isProvisioningNotificationEnabled(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR; + } + + public static class NetworkAgentConfig.Builder { + ctor public NetworkAgentConfig.Builder(); + method @NonNull public android.net.NetworkAgentConfig build(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification(); + method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String); + } + public final class NetworkCapabilities implements android.os.Parcelable { method public boolean deduceRestrictedCapability(); method @NonNull public int[] getTransportTypes(); @@ -8109,7 +8173,6 @@ package android.provider { field @NonNull public static final String ENABLE_CMAS_PRESIDENTIAL_PREF = "enable_cmas_presidential_alerts"; field @NonNull public static final String ENABLE_CMAS_SEVERE_THREAT_PREF = "enable_cmas_severe_threat_alerts"; field @NonNull public static final String ENABLE_EMERGENCY_PERF = "enable_emergency_alerts"; - field @NonNull public static final String ENABLE_FULL_VOLUME_PREF = "use_full_volume"; field @NonNull public static final String ENABLE_PUBLIC_SAFETY_PREF = "enable_public_safety_messages"; field @NonNull public static final String ENABLE_STATE_LOCAL_TEST_PREF = "enable_state_local_test_alerts"; field @NonNull public static final String ENABLE_TEST_ALERT_PREF = "enable_test_alerts"; @@ -9345,6 +9408,7 @@ package android.telephony { public final class CallQuality implements android.os.Parcelable { ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int); + ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean); method public int describeContents(); method public int getAverageRelativeJitter(); method public int getAverageRoundTripTime(); @@ -9357,6 +9421,9 @@ package android.telephony { method public int getNumRtpPacketsTransmitted(); method public int getNumRtpPacketsTransmittedLost(); method public int getUplinkCallQualityLevel(); + method public boolean isIncomingSilenceDetected(); + method public boolean isOutgoingSilenceDetected(); + method public boolean isRtpInactivityDetected(); method public void writeToParcel(android.os.Parcel, int); field public static final int CALL_QUALITY_BAD = 4; // 0x4 field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0 @@ -10356,9 +10423,19 @@ package android.telephony { method public boolean disableCellBroadcastRange(int, int, int); method public boolean enableCellBroadcastRange(int, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public java.util.List<android.telephony.SmsMessage> getMessagesFromIcc(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc(); method public void sendMultipartTextMessage(@NonNull String, @NonNull String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int); + field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3 + field public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; // 0x1 + field public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; // 0x2 + field public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; // 0x0 + } + + public class SmsMessage { + method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int); } public class SubscriptionInfo implements android.os.Parcelable { @@ -10553,6 +10630,11 @@ package android.telephony { method public void updateServiceLocation(); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String); field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; + field public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE"; + field public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE"; + field public static final String ACTION_CARRIER_SIGNAL_REDIRECTED = "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"; + field public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED = "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED"; + field public static final String ACTION_CARRIER_SIGNAL_RESET = "com.android.internal.telephony.CARRIER_SIGNAL_RESET"; field public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"; field public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED"; field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE"; @@ -10569,6 +10651,15 @@ package android.telephony { field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION"; field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID"; + field @Deprecated public static final String EXTRA_APN_PROTOCOL = "apnProto"; + field public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt"; + field @Deprecated public static final String EXTRA_APN_TYPE = "apnType"; + field public static final String EXTRA_APN_TYPE_INT = "apnTypeInt"; + field public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable"; + field public static final String EXTRA_ERROR_CODE = "errorCode"; + field public static final String EXTRA_PCO_ID = "pcoId"; + field public static final String EXTRA_PCO_VALUE = "pcoValue"; + field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl"; field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; @@ -11468,10 +11559,12 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19 field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13 diff --git a/api/test-current.txt b/api/test-current.txt index a8f7b51f8046..1db4c9b82343 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -34,6 +34,7 @@ package android { public static final class R.string { field public static final int config_defaultAssistant = 17039393; // 0x1040021 field public static final int config_defaultDialer = 17039395; // 0x1040023 + field public static final int config_systemGallery = 17039402; // 0x104002a } } @@ -756,6 +757,7 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String ROLLBACK_SERVICE = "rollback"; @@ -1020,7 +1022,7 @@ package android.graphics.drawable { package android.hardware.camera2 { public abstract class CameraDevice implements java.lang.AutoCloseable { - method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; + method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1 field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0 field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000 @@ -1496,7 +1498,9 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { method public void logEvent(int, @NonNull String); + method public void reevaluateNetwork(); method public void useNetwork(); + field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64 field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2 @@ -2733,6 +2737,11 @@ package android.service.autofill { method @Nullable public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions(); } + public static final class Dataset.Builder { + ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation); + method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation); + } + public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception; } @@ -3127,6 +3136,7 @@ package android.telephony { public final class CallQuality implements android.os.Parcelable { ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int); + ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean); method public int describeContents(); method public int getAverageRelativeJitter(); method public int getAverageRoundTripTime(); @@ -3139,6 +3149,9 @@ package android.telephony { method public int getNumRtpPacketsTransmitted(); method public int getNumRtpPacketsTransmittedLost(); method public int getUplinkCallQualityLevel(); + method public boolean isIncomingSilenceDetected(); + method public boolean isOutgoingSilenceDetected(); + method public boolean isRtpInactivityDetected(); method public void writeToParcel(android.os.Parcel, int); field public static final int CALL_QUALITY_BAD = 4; // 0x4 field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0 @@ -3813,10 +3826,12 @@ package android.telephony.ims { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public int getProvisioningIntValue(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19 field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13 @@ -4264,6 +4279,7 @@ package android.util { field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override."; field public static final String FFLAG_PREFIX = "sys.fflag."; field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; + field public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = "settings_notif_convo_bypass_shortcut_req"; field public static final String PERSIST_PREFIX = "persist.sys.fflag.override."; field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer"; diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 459520a3eb27..8fac31a05c49 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1113,7 +1113,7 @@ void BootAnimation::handleViewport(nsecs_t timestep) { SurfaceComposerClient::Transaction t; t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset) .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight)); - t.setDisplayProjection(mDisplayToken, 0 /* orientation */, layerStackRect, displayRect); + t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, layerStackRect, displayRect); t.apply(); mTargetInset = mCurrentInset = 0; diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS index 04464ce02b4f..a61babf32e58 100644 --- a/cmds/statsd/OWNERS +++ b/cmds/statsd/OWNERS @@ -1,7 +1,8 @@ -jianjin@google.com +jeffreyhuang@google.com joeo@google.com jtnguyen@google.com muhammadq@google.com +ruchirr@google.com singhtejinder@google.com tsaichristine@google.com yaochen@google.com diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index 6fc1e236c661..967fd323e5a0 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -261,6 +261,11 @@ inline Matcher getSimpleMatcher(int32_t tag, size_t field) { return Matcher(Field(tag, getSimpleField(field)), 0xff7f0000); } +inline Matcher getFirstUidMatcher(int32_t atomId) { + int32_t pos[] = {1, 1, 1}; + return Matcher(Field(atomId, pos, 2), 0xff7f7f7f); +} + /** * A wrapper for a union type to contain multiple types of values. * diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index 6d2bd04756ac..946c55087005 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -30,6 +30,8 @@ enum StateField { PRIMARY = 1; // The field that represents the state. It's an exclusive state. EXCLUSIVE = 2; + + PRIMARY_FIELD_FIRST_UID = 3; } // Used to annotate an atom that reprsents a state change. A state change atom must have exactly ONE diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index fb43783ca9a6..bb01911ee836 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -126,10 +126,10 @@ message Atom { AppStartOccurred app_start_occurred = 48; AppStartCanceled app_start_canceled = 49; AppStartFullyDrawn app_start_fully_drawn = 50; - LmkKillOccurred lmk_kill_occurred = 51; + LmkKillOccurred lmk_kill_occurred = 51 [(module) = "lmkd"]; PictureInPictureStateChanged picture_in_picture_state_changed = 52; WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(module) = "wifi"]; - LmkStateChanged lmk_state_changed = 54; + LmkStateChanged lmk_state_changed = 54 [(module) = "lmkd"]; AppStartMemoryStateCaptured app_start_memory_state_captured = 55; ShutdownSequenceReported shutdown_sequence_reported = 56; BootSequenceReported boot_sequence_reported = 57; @@ -334,6 +334,10 @@ message Atom { MediaProviderIdleMaintenance media_provider_idle_maintenance = 237 [(module) = "mediaprovider"]; RebootEscrowRecoveryReported reboot_escrow_recovery_reported = 238; + BootTimeEventDuration boot_time_event_duration_reported = 239; + BootTimeEventElapsedTime boot_time_event_elapsed_time_reported = 240; + BootTimeEventUtcTime boot_time_event_utc_time_reported = 241; + BootTimeEventErrorCode boot_time_event_error_code_reported = 242; } // Pulled events will start at field 10000. @@ -908,14 +912,16 @@ message CameraStateChanged { * TODO */ message WakelockStateChanged { - repeated AttributionNode attribution_node = 1; + repeated AttributionNode attribution_node = 1 + [(state_field_option).option = PRIMARY_FIELD_FIRST_UID]; // The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock. // From frameworks/base/core/proto/android/os/enums.proto. - optional android.os.WakeLockLevelEnum type = 2; + optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).option = PRIMARY]; + ; // The wakelock tag (Called tag in the Java API, sometimes name elsewhere). - optional string tag = 3; + optional string tag = 3 [(state_field_option).option = PRIMARY]; enum State { RELEASE = 0; @@ -923,7 +929,7 @@ message WakelockStateChanged { CHANGE_RELEASE = 2; CHANGE_ACQUIRE = 3; } - optional State state = 4; + optional State state = 4 [(state_field_option).option = EXCLUSIVE]; } /** @@ -3925,6 +3931,207 @@ message MediaProviderIdleMaintenance { optional float normalized_expired_media = 5; } +/** + * Represents boot time event with duration in ms. + * + * Logged from: bootstat and various system server components. Check each enums for details. + */ +message BootTimeEventDuration { + enum DurationEvent { + UNKNOWN = 0; + // Bootloader time excluding BOOTLOADER_UI_WAIT + boot complete time. Logged from bootstat. + ABSOLUTE_BOOT_TIME = 1; + // Bootloader's 1st stage execution time. + // Logged from bootstat. + BOOTLOADER_FIRST_STAGE_EXEC = 2; + // Bootloader's 1st stage loading time. + // Logged from bootstat. + BOOTLOADER_FIRST_STAGE_LOAD = 3; + // Bootloader's kernel loading time. + // Logged from bootstat. + BOOTLOADER_KERNEL_LOAD = 4; + // Bootloader's 2nd stage execution time. + // Logged from bootstat. + BOOTLOADER_SECOND_STAGE_EXEC = 5; + // Bootloader's 2nd stage loading time. + // Logged from bootstat. + BOOTLOADER_SECOND_STAGE_LOAD = 6; + // Duration for Bootloader to show unlocked device's warning UI. This should not happen + // for locked device. + // Logged from bootstat. + BOOTLOADER_UI_WAIT = 7; + // Total time spend in bootloader. This is the sum of all BOOTLOADER_* listed above. + // Logged from bootstat. + BOOTLOADER_TOTAL = 8; + // Shutdown duration inside init for the reboot before the current boot up. + // Logged from f/b/services/.../BootReceiver.java. + SHUTDOWN_DURATION = 9; + // Total time for mounting of disk devices during bootup. + // Logged from f/b/services/.../BootReceiver.java. + MOUNT_DEFAULT_DURATION = 10; + // Total time for early stage mounting of disk devices during bootup. + // Logged from f/b/services/.../BootReceiver.java. + MOUNT_EARLY_DURATION = 11; + // Total time for late stage mounting of disk devices during bootup. + // Logged from f/b/services/.../BootReceiver.java. + MOUNT_LATE_DURATION = 12; + // Average time to scan non-system app after OTA + // Logged from f/b/services/.../PackageManagerService.java + OTA_PACKAGE_MANAGER_INIT_TIME = 13; + // Time to initialize Package manager after OTA + // Logged from f/b/services/.../PackageManagerService.java + OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME = 14; + // Time to scan all system app from Package manager after OTA + // Logged from f/b/services/.../PackageManagerService.java + OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME = 15; + // Init's total time for cold boot stage. + // Logged from bootstat. + COLDBOOT_WAIT = 16; + // Init's total time for initializing selinux. + // Logged from bootstat. + SELINUX_INIT = 17; + // Time since last factory reset. + // Logged from bootstat. + FACTORY_RESET_TIME_SINCE_RESET = 18; + } + + // Type of the event. + optional DurationEvent event = 1; + // Duration of the event in ms. + optional int64 duration_millis = 2; +} + +/** + * Represents the start of specific boot time event during bootup in ms. This is usually a time + * since boot-up. + * + * Logged from: bootstat and various system server components. Check each enums for details. + */ +message BootTimeEventElapsedTime { + enum ElapsedTimeEvent { + UNKNOWN = 0; + // Time when init starts 1st stage. Logged from bootstat. + ANDROID_INIT_STAGE_1 = 1; + // Time when sys.boot_completed prop is set. + // Logged from bootstat. + BOOT_COMPLETE = 2; + // BOOT_COMPLETE for encrypted device. + BOOT_COMPLETE_ENCRYPTION = 3; + // BOOT_COMPLETE for device with no encryption. + BOOT_COMPLETE_NO_ENCRYPTION = 4; + // Adjusted BOOT_COMPLETE for encrypted device extracting decryption time. + BOOT_COMPLETE_POST_DESCRYPT = 5; + // BOOT_COMPLETE after factory reset. + FACTORY_RESET_BOOT_COMPLETE = 6; + // BOOT_COMPLETE_NO_ENCRYPTION after factory reset. + FACTORY_RESET_BOOT_COMPLETE_NO_ENCRYPTION = 7; + // BOOT_COMPLETE_POST_DESCRYPT after factory reset. + FACTORY_RESET_BOOT_COMPLETE_POST_DESCRYPT = 8; + // BOOT_COMPLETE after OTA. + OTA_BOOT_COMPLETE = 9; + // BOOT_COMPLETE_NO_ENCRYPTION after OTA. + OTA_BOOT_COMPLETE_NO_ENCRYPTION = 10; + // BOOT_COMPLETE_POST_DESCRYPT after OTA. + OTA_BOOT_COMPLETE_POST_DESCRYPT = 11; + // Time when the system starts sending LOCKED_BOOT_COMPLETED broadcast. + // Logged from f/b/services/.../UserController.java + FRAMEWORK_LOCKED_BOOT_COMPLETED = 12; + // Time when the system starts sending BOOT_COMPLETED broadcast. + // Logged from f/b/services/.../UserController.java + FRAMEWORK_BOOT_COMPLETED = 13; + // Time when the package manager starts init. + // Logged from f/b/services/.../SystemServer.java + PACKAGE_MANAGER_INIT_START = 14; + // Time when package manager is ready + // Logged from f/b/services/.../SystemServer.java + PACKAGE_MANAGER_INIT_READY = 15; + // Represents the time when user has entered unlock credential for system with user pin. + // Logged from bootstat. + POST_DECRYPT = 16; + // Represents the start of zygote's init. + // Logged from zygote itself. + ZYGOTE_INIT_START = 17; + // Represents the start of secondary zygote's init. + // TODO: add logging to zygote + SECONDARY_ZYGOTE_INIT_START = 18; + // Represents the start of system server's init. + // Logged from f/b/services/.../SystemServer.java + SYSTEM_SERVER_INIT_START = 19; + // Represents the completion of system server's init. + // Logged from f/b/services/.../SystemServer.java + SYSTEM_SERVER_READY = 20; + // Represents the start of launcher during boot-up. + // TODO: add logging + LAUNCHER_START = 21; + // Represents the completion of launcher's initial rendering. User can use other apps from + // launcher from this point. + // TODO: add logging + LAUNCHER_SHOWN = 22; + } + + // Type of the event. + optional ElapsedTimeEvent event = 1; + // Time since bootup for the event. + // It should be acquired from SystemClock elapsedRealtime() call or equivalent. + optional int64 time_millis = 2; +} + +/** + * Boot time events with UTC time. + * + * Logged from: bootstat and various system server components. Check each enums for details. + */ +message BootTimeEventUtcTime { + enum UtcTimeEvent { + UNKNOWN = 0; + // Time of the bootstat's marking of 1st boot after the last factory reset. + // Logged from bootstat. + FACTORY_RESET_RESET_TIME = 1; + // The time when bootstat records FACTORY_RESET_* events. This is close to + // BOOT_COMPLETE time for the current bootup. + // Logged from bootstat. + FACTORY_RESET_CURRENT_TIME = 2; + // DUplicate of FACTORY_RESET_RESET_TIME added for debugging purpose. + // Logged from bootstat. + FACTORY_RESET_RECORD_VALUE = 3; + } + + // Type of the event. + optional UtcTimeEvent event = 1; + // UTC time for the event. + optional int64 utc_time_secs = 2; +} + +/** + * Boot time events representing specific error code during bootup. + * Meaning of error code can be different per each event type. + * + * Logged from: bootstat and various system server components. Check each enums for details. + */ +message BootTimeEventErrorCode { + enum ErrorCodeEvent { + UNKNOWN = 0; + // Linux error code for time() call to get the current UTC time. + // Logged from bootstat. + FACTORY_RESET_CURRENT_TIME_FAILURE = 1; + // Represents UmountStat before the reboot for the current boot up. Error codes defined + // as UMOUNT_STAT_* from init/reboot.cpp. + // Logged from f/b/services/.../BootReceiver.java. + SHUTDOWN_UMOUNT_STAT = 2; + // Reprepsents fie system mounting error code for the current boot. Error codes defined + // as combination of FsStatFlags from system/core/fs_mgr/fs_mgr.cpp. + // Logged from f/b/services/.../BootReceiver.java. + FS_MGR_FS_STAT = 3; + } + + // Type of the event. + optional ErrorCodeEvent event = 1; + // error code defined per each event type. + // For example, this can have a value of FsStatFlags.FS_STAT_FULL_MOUNT_FAILED for the event of + // FS_MGR_FS_STAT. + optional int32 error_code = 2; +} + ////////////////////////////////////////////////////////////////////// // Pulled atoms below this line // ////////////////////////////////////////////////////////////////////// diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index b5680331f63e..731afe8c0859 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -60,27 +60,6 @@ const int64_t NO_ALARM_UPDATE = INT64_MAX; std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { - // wifi_bytes_transfer_by_fg_bg - {{.atomTag = android::util::WIFI_BYTES_TRANSFER_BY_FG_BG}, - {.additiveFields = {3, 4, 5, 6}, - .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, - - // mobile_bytes_transfer - {{.atomTag = android::util::MOBILE_BYTES_TRANSFER}, - {.additiveFields = {2, 3, 4, 5}, - .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, - - // mobile_bytes_transfer_by_fg_bg - {{.atomTag = android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG}, - {.additiveFields = {3, 4, 5, 6}, - .puller = - new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, - - // bluetooth_bytes_transfer - {{.atomTag = android::util::BLUETOOTH_BYTES_TRANSFER}, - {.additiveFields = {2, 3}, - .puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, - // kernel_wakelock {{.atomTag = android::util::KERNEL_WAKELOCK}, {.puller = new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, @@ -132,10 +111,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{.atomTag = android::util::MODEM_ACTIVITY_INFO}, {.puller = new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, - // bluetooth_activity_info - {{.atomTag = android::util::BLUETOOTH_ACTIVITY_INFO}, - {.puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, - // system_elapsed_realtime {{.atomTag = android::util::SYSTEM_ELAPSED_REALTIME}, {.coolDownNs = NS_PER_SEC, @@ -249,10 +224,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { .coolDownNs = 3 * NS_PER_SEC, .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}}, - // PowerProfile constants for power model calculations. - {{.atomTag = android::util::POWER_PROFILE}, - {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, - // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. {{.atomTag = android::util::PROCESS_CPU_TIME}, {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/, diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp index ef59c9242cb2..3ad21e0c96ae 100644 --- a/cmds/statsd/src/state/StateTracker.cpp +++ b/cmds/statsd/src/state/StateTracker.cpp @@ -28,10 +28,14 @@ namespace statsd { StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo) : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) { // create matcher for each primary field - // TODO(tsaichristine): b/142108433 handle when primary field is first uid in chain - for (const auto& primary : stateAtomInfo.primaryFields) { - Matcher matcher = getSimpleMatcher(atomId, primary); - mPrimaryFields.push_back(matcher); + for (const auto& primaryField : stateAtomInfo.primaryFields) { + if (primaryField == util::FIRST_UID_IN_CHAIN) { + Matcher matcher = getFirstUidMatcher(atomId); + mPrimaryFields.push_back(matcher); + } else { + Matcher matcher = getSimpleMatcher(atomId, primaryField); + mPrimaryFields.push_back(matcher); + } } // TODO(tsaichristine): b/142108433 set default state, reset state, and nesting diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h index 7453370f25fd..70f16274c7f6 100644 --- a/cmds/statsd/src/state/StateTracker.h +++ b/cmds/statsd/src/state/StateTracker.h @@ -72,7 +72,7 @@ private: int32_t mDefaultState = kStateUnknown; - int32_t mResetState; + int32_t mResetState = kStateUnknown; // Maps primary key to state value info std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap; diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp index 26a3733ed598..84aaa54bc5bf 100644 --- a/cmds/statsd/tests/state/StateTracker_test.cpp +++ b/cmds/statsd/tests/state/StateTracker_test.cpp @@ -76,6 +76,23 @@ std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) { return event; } +// State with first uid in attribution chain as primary field - WakelockStateChanged +std::shared_ptr<LogEvent> buildPartialWakelockEvent(int uid, const std::string& tag, bool acquire) { + std::vector<AttributionNodeInternal> chain; + chain.push_back(AttributionNodeInternal()); + AttributionNodeInternal& attr = chain.back(); + attr.set_uid(uid); + + std::shared_ptr<LogEvent> event = + std::make_shared<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, 1000 /* timestamp */); + event->write(chain); + event->write((int32_t)1); // PARTIAL_WAKE_LOCK + event->write(tag); + event->write(acquire ? 1 : 0); + event->init(); + return event; +} + // State with multiple primary fields - OverlayStateChanged std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) { std::shared_ptr<LogEvent> event = @@ -134,6 +151,39 @@ void getOverlayKey(int uid, string packageName, HashableDimensionKey* key) { key->addValue(FieldValue(field1, value1)); key->addValue(FieldValue(field2, value2)); } + +void getPartialWakelockKey(int uid, const std::string& tag, HashableDimensionKey* key) { + int pos1[] = {1, 1, 1}; + int pos3[] = {2, 0, 0}; + int pos4[] = {3, 0, 0}; + + Field field1(10 /* atom id */, pos1, 2 /* depth */); + + Field field3(10 /* atom id */, pos3, 0 /* depth */); + Field field4(10 /* atom id */, pos4, 0 /* depth */); + + Value value1((int32_t)uid); + Value value3((int32_t)1 /*partial*/); + Value value4(tag); + + key->addValue(FieldValue(field1, value1)); + key->addValue(FieldValue(field3, value3)); + key->addValue(FieldValue(field4, value4)); +} + +void getPartialWakelockKey(int uid, HashableDimensionKey* key) { + int pos1[] = {1, 1, 1}; + int pos3[] = {2, 0, 0}; + + Field field1(10 /* atom id */, pos1, 2 /* depth */); + Field field3(10 /* atom id */, pos3, 0 /* depth */); + + Value value1((int32_t)uid); + Value value3((int32_t)1 /*partial*/); + + key->addValue(FieldValue(field1, value1)); + key->addValue(FieldValue(field3, value3)); +} // END: get primary key functions TEST(StateListenerTest, TestStateListenerWeakPointer) { @@ -247,7 +297,8 @@ TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY; - EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey)); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey)); } /** @@ -272,7 +323,46 @@ TEST(StateTrackerTest, TestStateChangeOnePrimaryField) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey; getUidProcessKey(1000 /* uid */, &queryKey); - EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey)); + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP, + getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey)); +} + +TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) { + sp<TestStateListener> listener1 = new TestStateListener(); + StateManager mgr; + mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener1); + + // Log event. + std::shared_ptr<LogEvent> event = + buildPartialWakelockEvent(1001 /* uid */, "tag1", false /* acquire */); + mgr.onLogEvent(*event); + + EXPECT_EQ(1, mgr.getStateTrackersCount()); + EXPECT_EQ(1, mgr.getListenersCount(android::util::WAKELOCK_STATE_CHANGED)); + + // Check listener was updated. + EXPECT_EQ(1, listener1->updates.size()); + EXPECT_EQ(3, listener1->updates[0].mKey.getValues().size()); + EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value); + EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value); + EXPECT_EQ("tag1", listener1->updates[0].mKey.getValues()[2].mValue.str_value); + EXPECT_EQ(WakelockStateChanged::RELEASE, listener1->updates[0].mState); + + // Check StateTracker was updated by querying for state. + HashableDimensionKey queryKey; + getPartialWakelockKey(1001 /* uid */, "tag1", &queryKey); + EXPECT_EQ(WakelockStateChanged::RELEASE, + getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey)); + + // No state stored for this query key. + HashableDimensionKey queryKey2; + getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2); + EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2)); + + // Partial query fails. + HashableDimensionKey queryKey3; + getPartialWakelockKey(1001 /* uid */, &queryKey3); + EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3)); } /** @@ -297,7 +387,8 @@ TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) { // check StateTracker was updated by querying for state HashableDimensionKey queryKey; getOverlayKey(1000 /* uid */, "package1", &queryKey); - EXPECT_EQ(1, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey)); + EXPECT_EQ(OverlayStateChanged::ENTERED, + getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey)); } /** @@ -326,10 +417,12 @@ TEST(StateTrackerTest, TestStateQuery) { sp<TestStateListener> listener1 = new TestStateListener(); sp<TestStateListener> listener2 = new TestStateListener(); sp<TestStateListener> listener3 = new TestStateListener(); + sp<TestStateListener> listener4 = new TestStateListener(); StateManager mgr; mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1); mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener2); mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener3); + mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener4); std::shared_ptr<LogEvent> event1 = buildUidProcessEvent( 1000, @@ -346,8 +439,12 @@ TEST(StateTrackerTest, TestStateQuery) { android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002 std::shared_ptr<LogEvent> event5 = buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON); - std::shared_ptr<LogEvent> event6 = buildOverlayEvent(1000, "package1", 1); - std::shared_ptr<LogEvent> event7 = buildOverlayEvent(1000, "package2", 2); + std::shared_ptr<LogEvent> event6 = + buildOverlayEvent(1000, "package1", OverlayStateChanged::ENTERED); + std::shared_ptr<LogEvent> event7 = + buildOverlayEvent(1000, "package2", OverlayStateChanged::EXITED); + std::shared_ptr<LogEvent> event8 = buildPartialWakelockEvent(1005, "tag1", true); + std::shared_ptr<LogEvent> event9 = buildPartialWakelockEvent(1005, "tag2", false); mgr.onLogEvent(*event1); mgr.onLogEvent(*event2); @@ -356,11 +453,14 @@ TEST(StateTrackerTest, TestStateQuery) { mgr.onLogEvent(*event5); mgr.onLogEvent(*event6); mgr.onLogEvent(*event7); + mgr.onLogEvent(*event8); + mgr.onLogEvent(*event9); // Query for UidProcessState of uid 1001 HashableDimensionKey queryKey1; getUidProcessKey(1001, &queryKey1); - EXPECT_EQ(1003, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); // Query for UidProcessState of uid 1004 - not in state map HashableDimensionKey queryKey2; @@ -370,15 +470,30 @@ TEST(StateTrackerTest, TestStateQuery) { // Query for UidProcessState of uid 1001 - after change in state mgr.onLogEvent(*event4); - EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP, + getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1)); // Query for ScreenState - EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY)); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, + getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY)); // Query for OverlayState of uid 1000, package name "package2" HashableDimensionKey queryKey3; getOverlayKey(1000, "package2", &queryKey3); - EXPECT_EQ(2, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3)); + EXPECT_EQ(OverlayStateChanged::EXITED, + getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3)); + + // Query for WakelockState of uid 1005, tag 2 + HashableDimensionKey queryKey4; + getPartialWakelockKey(1005, "tag2", &queryKey4); + EXPECT_EQ(WakelockStateChanged::RELEASE, + getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey4)); + + // Query for WakelockState of uid 1005, tag 1 + HashableDimensionKey queryKey5; + getPartialWakelockKey(1005, "tag1", &queryKey5); + EXPECT_EQ(WakelockStateChanged::ACQUIRE, + getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey5)); } } // namespace statsd diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 8fe2f12a1023..f2702a864c2f 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -25,6 +25,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.Size; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.UserHandleAware; import android.app.Activity; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -40,6 +41,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Parcelable; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; @@ -528,12 +530,9 @@ public class AccountManager { * authenticator known to the AccountManager service. Empty (never * null) if no authenticators are known. */ + @UserHandleAware public AuthenticatorDescription[] getAuthenticatorTypes() { - try { - return mService.getAuthenticatorTypes(UserHandle.getCallingUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getAuthenticatorTypesAsUser(mContext.getUserId()); } /** @@ -584,13 +583,10 @@ public class AccountManager { * @return An array of {@link Account}, one for each account. Empty (never null) if no accounts * have been added. */ + @UserHandleAware @NonNull public Account[] getAccounts() { - try { - return mService.getAccounts(null, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getAccountsAsUser(mContext.getUserId()); } /** @@ -708,6 +704,7 @@ public class AccountManager { * @return An array of {@link Account}, one per matching account. Empty (never null) if no * accounts of the specified type have been added. */ + @UserHandleAware @NonNull public Account[] getAccountsByType(String type) { return getAccountsByTypeAsUser(type, mContext.getUser()); @@ -1183,23 +1180,11 @@ public class AccountManager { * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)} * instead */ + @UserHandleAware @Deprecated public AccountManagerFuture<Boolean> removeAccount(final Account account, AccountManagerCallback<Boolean> callback, Handler handler) { - if (account == null) throw new IllegalArgumentException("account is null"); - return new Future2Task<Boolean>(handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.removeAccount(mResponse, account, false); - } - @Override - public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { - if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { - throw new AuthenticatorException("no result in response"); - } - return bundle.getBoolean(KEY_BOOLEAN_RESULT); - } - }.start(); + return removeAccountAsUser(account, callback, handler, mContext.getUser()); } /** @@ -1243,15 +1228,10 @@ public class AccountManager { * adding accounts (of this type) has been disabled by policy * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> removeAccount(final Account account, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { - if (account == null) throw new IllegalArgumentException("account is null"); - return new AmsTask(activity, handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.removeAccount(mResponse, account, activity != null); - } - }.start(); + return removeAccountAsUser(account, activity, callback, handler, mContext.getUser()); } /** @@ -1841,24 +1821,30 @@ public class AccountManager { * creating a new account, usually because of network trouble * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { - if (accountType == null) throw new IllegalArgumentException("accountType is null"); - final Bundle optionsIn = new Bundle(); - if (addAccountOptions != null) { - optionsIn.putAll(addAccountOptions); - } - optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); - - return new AmsTask(activity, handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.addAccount(mResponse, accountType, authTokenType, - requiredFeatures, activity != null, optionsIn); + if (Process.myUserHandle().equals(mContext.getUser())) { + if (accountType == null) throw new IllegalArgumentException("accountType is null"); + final Bundle optionsIn = new Bundle(); + if (addAccountOptions != null) { + optionsIn.putAll(addAccountOptions); } - }.start(); + optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); + + return new AmsTask(activity, handler, callback) { + @Override + public void doWork() throws RemoteException { + mService.addAccount(mResponse, accountType, authTokenType, + requiredFeatures, activity != null, optionsIn); + } + }.start(); + } else { + return addAccountAsUser(accountType, authTokenType, requiredFeatures, addAccountOptions, + activity, callback, handler, mContext.getUser()); + } } /** @@ -2002,6 +1988,7 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Bundle options, final Activity activity, @@ -3209,6 +3196,7 @@ public class AccountManager { * </ul> * @see #startAddAccountSession and #startUpdateCredentialsSession */ + @UserHandleAware public AccountManagerFuture<Bundle> finishSession( final Bundle sessionBundle, final Activity activity, diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 012713891d11..ce68e082cf4f 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -34,7 +34,6 @@ interface IAccountManager { String getPassword(in Account account); String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(int userId); - Account[] getAccounts(String accountType, String opPackageName); Account[] getAccountsForPackage(String packageName, int uid, String opPackageName); Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName); Account[] getAccountsAsUser(String accountType, int userId, String opPackageName); @@ -45,8 +44,6 @@ interface IAccountManager { void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features, String opPackageName); boolean addAccountExplicitly(in Account account, String password, in Bundle extras); - void removeAccount(in IAccountManagerResponse response, in Account account, - boolean expectActivityLaunch); void removeAccountAsUser(in IAccountManagerResponse response, in Account account, boolean expectActivityLaunch, int userId); boolean removeAccountExplicitly(in Account account); diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java index 0c5d15e178a3..c05c1bab06d2 100644 --- a/core/java/android/annotation/SystemService.java +++ b/core/java/android/annotation/SystemService.java @@ -19,14 +19,12 @@ package android.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; -import android.content.Context; - import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * Description of a system service available through - * {@link Context#getSystemService(Class)}. This is used to auto-generate + * {@link android.content.Context#getSystemService(Class)}. This is used to auto-generate * documentation explaining how to obtain a reference to the service. * * @hide @@ -36,9 +34,9 @@ import java.lang.annotation.Target; public @interface SystemService { /** * The string name of the system service that can be passed to - * {@link Context#getSystemService(String)}. + * {@link android.content.Context#getSystemService(String)}. * - * @see Context#getSystemServiceName(Class) + * @see android.content.Context#getSystemServiceName(Class) */ String value(); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index ca3d0d7065c9..a9be9ea33089 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -170,6 +170,7 @@ import android.service.persistentdata.IPersistentDataBlockService; import android.service.persistentdata.PersistentDataBlockManager; import android.service.vr.IVrManager; import android.telecom.TelecomManager; +import android.telephony.MmsManager; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyRegistryManager; import android.util.ArrayMap; @@ -345,6 +346,14 @@ public final class SystemServiceRegistry { } }); + registerService(Context.NETWORK_STACK_SERVICE, IBinder.class, + new StaticServiceFetcher<IBinder>() { + @Override + public IBinder createService() { + return ServiceManager.getService(Context.NETWORK_STACK_SERVICE); + } + }); + registerService(Context.TETHERING_SERVICE, TetheringManager.class, new CachedServiceFetcher<TetheringManager>() { @Override @@ -631,6 +640,13 @@ public final class SystemServiceRegistry { return new TelecomManager(ctx.getOuterContext()); }}); + registerService(Context.MMS_SERVICE, MmsManager.class, + new CachedServiceFetcher<MmsManager>() { + @Override + public MmsManager createService(ContextImpl ctx) { + return new MmsManager(ctx.getOuterContext()); + }}); + registerService(Context.UI_MODE_SERVICE, UiModeManager.class, new CachedServiceFetcher<UiModeManager>() { @Override diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 62b499ceb941..caaa686ecf08 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1411,6 +1411,16 @@ public class DevicePolicyManager { = "android.app.action.DEVICE_OWNER_CHANGED"; /** + * Broadcast action: sent when the factory reset protection (FRP) policy is changed. + * + * @see #setFactoryResetProtectionPolicy + * @hide + */ + @SystemApi + public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = + "android.app.action.RESET_PROTECTION_POLICY_CHANGED"; + + /** * The ComponentName of the administrator component. * * @see #ACTION_ADD_DEVICE_ADMIN @@ -1982,16 +1992,6 @@ public class DevicePolicyManager { public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; /** - * Result code for {@link #checkProvisioningPreCondition}. - * - * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when adding a managed profile is - * disallowed by {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}. - * - * @hide - */ - public static final int CODE_ADD_MANAGED_PROFILE_DISALLOWED = 15; - - /** * Result codes for {@link #checkProvisioningPreCondition} indicating all the provisioning pre * conditions. * @@ -2003,7 +2003,7 @@ public class DevicePolicyManager { CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED, CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE, CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED, - CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED + CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER }) public @interface ProvisioningPreCondition {} @@ -4329,6 +4329,60 @@ public class DevicePolicyManager { } /** + * Callable by device owner or profile owner of an organization-owned device, to set a + * factory reset protection (FRP) policy. When a new policy is set, the system + * notifies the FRP management agent of a policy change by broadcasting + * {@code ACTION_RESET_PROTECTION_POLICY_CHANGED}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param policy the new FRP policy, or {@code null} to clear the current policy. + * @throws SecurityException if {@code admin} is not a device owner or a profile owner of + * an organization-owned device. + * @throws UnsupportedOperationException if factory reset protection is not + * supported on the device. + */ + public void setFactoryResetProtectionPolicy(@NonNull ComponentName admin, + @Nullable FactoryResetProtectionPolicy policy) { + throwIfParentInstance("setFactoryResetProtectionPolicy"); + if (mService != null) { + try { + mService.setFactoryResetProtectionPolicy(admin, policy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Callable by device owner or profile owner of an organization-owned device, to retrieve + * the current factory reset protection (FRP) policy set previously by + * {@link #setFactoryResetProtectionPolicy}. + * <p> + * This method can also be called by the FRP management agent on device, in which case, + * it can pass {@code null} as the ComponentName. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with or + * {@code null} if called by the FRP management agent on device. + * @return The current FRP policy object or {@code null} if no policy is set. + * @throws SecurityException if {@code admin} is not a device owner, a profile owner of + * an organization-owned device or the FRP management agent. + * @throws UnsupportedOperationException if factory reset protection is not + * supported on the device. + */ + public @Nullable FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( + @Nullable ComponentName admin) { + throwIfParentInstance("getFactoryResetProtectionPolicy"); + if (mService != null) { + try { + return mService.getFactoryResetProtectionPolicy(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Called by an application that is administering the device to set the * global proxy and exclusion list. * <p> diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.aidl b/core/java/android/app/admin/FactoryResetProtectionPolicy.aidl new file mode 100644 index 000000000000..72e639a76d18 --- /dev/null +++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.app.admin; + +parcelable FactoryResetProtectionPolicy; diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java new file mode 100644 index 000000000000..ed7477936f9c --- /dev/null +++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2019 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.app.admin; + +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.TEXT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * The factory reset protection policy determines which accounts can unlock a device that + * has gone through untrusted factory reset. + * <p> + * Only a device owner or profile owner of an organization-owned device can set a factory + * reset protection policy for the device by calling the {@code DevicePolicyManager} method + * {@link DevicePolicyManager#setFactoryResetProtectionPolicy(ComponentName, + * FactoryResetProtectionPolicy)}}. + * + * @see DevicePolicyManager#setFactoryResetProtectionPolicy + * @see DevicePolicyManager#getFactoryResetProtectionPolicy + */ +public final class FactoryResetProtectionPolicy implements Parcelable { + + private static final String LOG_TAG = "FactoryResetProtectionPolicy"; + + private static final String KEY_FACTORY_RESET_PROTECTION_ACCOUNT = + "factory_reset_protection_account"; + private static final String KEY_FACTORY_RESET_PROTECTION_DISABLED = + "factory_reset_protection_disabled"; + private static final String ATTR_VALUE = "value"; + + private final List<String> mFactoryResetProtectionAccounts; + private final boolean mFactoryResetProtectionDisabled; + + private FactoryResetProtectionPolicy(List<String> factoryResetProtectionAccounts, + boolean factoryResetProtectionDisabled) { + mFactoryResetProtectionAccounts = factoryResetProtectionAccounts; + mFactoryResetProtectionDisabled = factoryResetProtectionDisabled; + } + + /** + * Get the list of accounts that can provision a device which has been factory reset. + */ + public @NonNull List<String> getFactoryResetProtectionAccounts() { + return mFactoryResetProtectionAccounts; + } + + /** + * Return whether factory reset protection for the device is disabled or not. + */ + public boolean isFactoryResetProtectionDisabled() { + return mFactoryResetProtectionDisabled; + } + + /** + * Builder class for {@link FactoryResetProtectionPolicy} objects. + */ + public static class Builder { + private List<String> mFactoryResetProtectionAccounts; + private boolean mFactoryResetProtectionDisabled; + + /** + * Initialize a new Builder to construct a {@link FactoryResetProtectionPolicy}. + */ + public Builder() { + }; + + /** + * Sets which accounts can unlock a device that has been factory reset. + * <p> + * Once set, the consumer unlock flow will be disabled and only accounts in this list + * can unlock factory reset protection after untrusted factory reset. + * <p> + * It's up to the FRP management agent to interpret the {@code String} as account it + * supports. Please consult their relevant documentation for details. + * + * @param factoryResetProtectionAccounts list of accounts. + * @return the same Builder instance. + */ + @NonNull + public Builder setFactoryResetProtectionAccounts( + @NonNull List<String> factoryResetProtectionAccounts) { + mFactoryResetProtectionAccounts = new ArrayList<>(factoryResetProtectionAccounts); + return this; + } + + /** + * Sets whether factory reset protection is disabled or not. + * <p> + * Once disabled, factory reset protection will not kick in all together when the device + * goes through untrusted factory reset. This applies to both the consumer unlock flow and + * the admin account overrides via {@link #setFactoryResetProtectionAccounts} + * + * @param factoryResetProtectionDisabled Whether the policy is disabled or not. + * @return the same Builder instance. + */ + @NonNull + public Builder setFactoryResetProtectionDisabled(boolean factoryResetProtectionDisabled) { + mFactoryResetProtectionDisabled = factoryResetProtectionDisabled; + return this; + } + + /** + * Combines all of the attributes that have been set on this {@code Builder} + * + * @return a new {@link FactoryResetProtectionPolicy} object. + */ + @NonNull + public FactoryResetProtectionPolicy build() { + return new FactoryResetProtectionPolicy(mFactoryResetProtectionAccounts, + mFactoryResetProtectionDisabled); + } + } + + @Override + public String toString() { + return "FactoryResetProtectionPolicy{" + + "mFactoryResetProtectionAccounts=" + mFactoryResetProtectionAccounts + + ", mFactoryResetProtectionDisabled=" + mFactoryResetProtectionDisabled + + '}'; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, @Nullable int flags) { + int accountsCount = mFactoryResetProtectionAccounts.size(); + dest.writeInt(accountsCount); + for (String account: mFactoryResetProtectionAccounts) { + dest.writeString(account); + } + dest.writeBoolean(mFactoryResetProtectionDisabled); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<FactoryResetProtectionPolicy> CREATOR = + new Creator<FactoryResetProtectionPolicy>() { + + @Override + public FactoryResetProtectionPolicy createFromParcel(Parcel in) { + List<String> factoryResetProtectionAccounts = new ArrayList<>(); + int accountsCount = in.readInt(); + for (int i = 0; i < accountsCount; i++) { + factoryResetProtectionAccounts.add(in.readString()); + } + boolean factoryResetProtectionDisabled = in.readBoolean(); + + return new FactoryResetProtectionPolicy(factoryResetProtectionAccounts, + factoryResetProtectionDisabled); + } + + @Override + public FactoryResetProtectionPolicy[] newArray(int size) { + return new FactoryResetProtectionPolicy[size]; + } + }; + + /** + * Restore a previously saved FactoryResetProtectionPolicy from XML. + * <p> + * No validation is required on the reconstructed policy since the XML was previously + * created by the system server from a validated policy. + * @hide + */ + @Nullable + public static FactoryResetProtectionPolicy readFromXml(@NonNull XmlPullParser parser) { + try { + boolean factoryResetProtectionDisabled = Boolean.parseBoolean( + parser.getAttributeValue(null, KEY_FACTORY_RESET_PROTECTION_DISABLED)); + + List<String> factoryResetProtectionAccounts = new ArrayList<>(); + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != END_DOCUMENT + && (type != END_TAG || parser.getDepth() > outerDepth)) { + if (type == END_TAG || type == TEXT) { + continue; + } + if (!parser.getName().equals(KEY_FACTORY_RESET_PROTECTION_ACCOUNT)) { + continue; + } + factoryResetProtectionAccounts.add( + parser.getAttributeValue(null, ATTR_VALUE)); + } + + return new FactoryResetProtectionPolicy(factoryResetProtectionAccounts, + factoryResetProtectionDisabled); + } catch (XmlPullParserException | IOException e) { + Log.w(LOG_TAG, "Reading from xml failed", e); + } + return null; + } + + /** + * @hide + */ + public void writeToXml(@NonNull XmlSerializer out) throws IOException { + out.attribute(null, KEY_FACTORY_RESET_PROTECTION_DISABLED, + Boolean.toString(mFactoryResetProtectionDisabled)); + for (String account : mFactoryResetProtectionAccounts) { + out.startTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT); + out.attribute(null, ATTR_VALUE, account); + out.endTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT); + } + } + +} diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 3eec46bd010e..21c9eb5c60ad 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -24,6 +24,7 @@ import android.app.admin.StartInstallingUpdateCallback; import android.app.admin.SystemUpdateInfo; import android.app.admin.SystemUpdatePolicy; import android.app.admin.PasswordMetrics; +import android.app.admin.FactoryResetProtectionPolicy; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -104,6 +105,9 @@ interface IDevicePolicyManager { void wipeDataWithReason(int flags, String wipeReasonForUser, boolean parent); + void setFactoryResetProtectionPolicy(in ComponentName who, in FactoryResetProtectionPolicy policy); + FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(in ComponentName who); + ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList); ComponentName getGlobalProxyAdmin(int userHandle); void setRecommendedGlobalProxy(in ComponentName admin, in ProxyInfo proxyInfo); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 44b2df691876..9ef95743b0c9 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3416,6 +3416,7 @@ public abstract class Context { TELEPHONY_SUBSCRIPTION_SERVICE, CARRIER_CONFIG_SERVICE, EUICC_SERVICE, + MMS_SERVICE, TELECOM_SERVICE, CLIPBOARD_SERVICE, INPUT_METHOD_SERVICE, @@ -3612,6 +3613,8 @@ public abstract class Context { * @see android.telephony.CarrierConfigManager * @see #EUICC_SERVICE * @see android.telephony.euicc.EuiccManager + * @see #MMS_SERVICE + * @see android.telephony.MmsManager * @see #INPUT_METHOD_SERVICE * @see android.view.inputmethod.InputMethodManager * @see #UI_MODE_SERVICE @@ -3950,10 +3953,12 @@ public abstract class Context { /** * Use with {@link android.os.ServiceManager.getService()} to retrieve a - * {@link NetworkStackClient} IBinder for communicating with the network stack + * {@link INetworkStackConnector} IBinder for communicating with the network stack * @hide * @see NetworkStackClient */ + @SystemApi + @TestApi public static final String NETWORK_STACK_SERVICE = "network_stack"; /** @@ -4288,6 +4293,15 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.telephony.MmsManager} to send/receive MMS messages. + * + * @see #getSystemService(String) + * @see android.telephony.MmsManager + */ + public static final String MMS_SERVICE = "mms"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.content.ClipboardManager} for accessing and modifying * the contents of the global clipboard. * diff --git a/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java b/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java index 07d2443ffacb..6ead64c02ef9 100644 --- a/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java @@ -25,9 +25,12 @@ import java.util.List; * A constrained high speed capture session for a {@link CameraDevice}, used for capturing high * speed images from the {@link CameraDevice} for high speed video recording use case. * <p> - * A CameraHighSpeedCaptureSession is created by providing a set of target output surfaces to - * {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, Once created, the session is - * active until a new session is created by the camera device, or the camera device is closed. + * A CameraConstrainedHighSpeedCaptureSession is created by providing a session configuration to + * {@link CameraDevice#createCaptureSession(SessionConfiguration)} with a type of + * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_HIGH_SPEED}. The + * CameraCaptureSession returned from {@link CameraCaptureSession.StateCallback} can then be cast to + * a CameraConstrainedHighSpeedCaptureSession. Once created, the session is active until a new + * session is created by the camera device, or the camera device is closed. * </p> * <p> * An active high speed capture session is a specialized capture session that is only targeted at @@ -37,8 +40,8 @@ import java.util.List; * accepts request lists created via {@link #createHighSpeedRequestList}, and the request list can * only be submitted to this session via {@link CameraCaptureSession#captureBurst captureBurst}, or * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}. See - * {@link CameraDevice#createConstrainedHighSpeedCaptureSession} for more details of the - * limitations. + * {@link CameraDevice#createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} + * for more details of the limitations. * </p> * <p> * Creating a session is an expensive operation and can take several hundred milliseconds, since it @@ -50,13 +53,6 @@ import java.util.List; * completed, then the {@link CameraCaptureSession.StateCallback#onConfigureFailed} is called, and * the session will not become active. * </p> - * <!-- - * <p> - * Any capture requests (repeating or non-repeating) submitted before the session is ready will be - * queued up and will begin capture once the session becomes ready. In case the session cannot be - * configured and {@link CameraCaptureSession.StateCallback#onConfigureFailed onConfigureFailed} is - * called, all queued capture requests are discarded. </p> - * --> * <p> * If a new session is created by the camera device, then the previous session is closed, and its * associated {@link CameraCaptureSession.StateCallback#onClosed onClosed} callback will be diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index fb1ece29a369..cc066812ba1f 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -16,24 +16,22 @@ package android.hardware.camera2; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; -import static android.hardware.camera2.ICameraDeviceUser.NORMAL_MODE; -import static android.hardware.camera2.ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE; import android.hardware.camera2.params.InputConfiguration; -import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; +import android.hardware.camera2.params.StreamConfigurationMap; import android.os.Handler; import android.view.Surface; -import java.util.List; -import java.util.Set; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Set; /** * <p>The CameraDevice class is a representation of a single camera connected to an @@ -220,6 +218,224 @@ public abstract class CameraDevice implements AutoCloseable { * <p>Create a new camera capture session by providing the target output set of Surfaces to the * camera device.</p> * + * @param outputs The new set of Surfaces that should be made available as + * targets for captured image data. + * @param callback The callback to notify about the status of the new capture session. + * @param handler The handler on which the callback should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * + * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, + * the callback is null, or the handler is null but the current + * thread has no looper. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see CameraCaptureSession + * @see StreamConfigurationMap#getOutputFormats() + * @see StreamConfigurationMap#getOutputSizes(int) + * @see StreamConfigurationMap#getOutputSizes(Class) + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + */ + @Deprecated + public abstract void createCaptureSession(@NonNull List<Surface> outputs, + @NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler) + throws CameraAccessException; + + /** + * <p>Create a new camera capture session by providing the target output set of Surfaces and + * its corresponding surface configuration to the camera device.</p> + * + * @see #createCaptureSession + * @see OutputConfiguration + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + */ + @Deprecated + public abstract void createCaptureSessionByOutputConfigurations( + List<OutputConfiguration> outputConfigurations, + CameraCaptureSession.StateCallback callback, @Nullable Handler handler) + throws CameraAccessException; + /** + * Create a new reprocessable camera capture session by providing the desired reprocessing + * input Surface configuration and the target output set of Surfaces to the camera device. + * + * @param inputConfig The configuration for the input {@link Surface} + * @param outputs The new set of Surfaces that should be made available as + * targets for captured image data. + * @param callback The callback to notify about the status of the new capture session. + * @param handler The handler on which the callback should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * + * @throws IllegalArgumentException if the input configuration is null or not supported, the set + * of output Surfaces do not meet the requirements, the + * callback is null, or the handler is null but the current + * thread has no looper. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see #createCaptureSession + * @see CameraCaptureSession + * @see StreamConfigurationMap#getInputFormats + * @see StreamConfigurationMap#getInputSizes + * @see StreamConfigurationMap#getValidOutputFormatsForInput + * @see StreamConfigurationMap#getOutputSizes + * @see android.media.ImageWriter + * @see android.media.ImageReader + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + */ + @Deprecated + public abstract void createReprocessableCaptureSession(@NonNull InputConfiguration inputConfig, + @NonNull List<Surface> outputs, @NonNull CameraCaptureSession.StateCallback callback, + @Nullable Handler handler) + throws CameraAccessException; + + /** + * Create a new reprocessable camera capture session by providing the desired reprocessing + * input configuration and output {@link OutputConfiguration} + * to the camera device. + * + * @see #createReprocessableCaptureSession + * @see OutputConfiguration + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + */ + @Deprecated + public abstract void createReprocessableCaptureSessionByConfigurations( + @NonNull InputConfiguration inputConfig, + @NonNull List<OutputConfiguration> outputs, + @NonNull CameraCaptureSession.StateCallback callback, + @Nullable Handler handler) + throws CameraAccessException; + + /** + * <p>Create a new constrained high speed capture session.</p> + * + * @param outputs The new set of Surfaces that should be made available as + * targets for captured high speed image data. + * @param callback The callback to notify about the status of the new capture session. + * @param handler The handler on which the callback should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * + * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, + * the callback is null, or the handler is null but the current + * thread has no looper, or the camera device doesn't support + * high speed video capability. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see #createCaptureSession + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE + * @see StreamConfigurationMap#getHighSpeedVideoSizes + * @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO + * @see CameraCaptureSession#captureBurst + * @see CameraCaptureSession#setRepeatingBurst + * @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + */ + @Deprecated + public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs, + @NonNull CameraCaptureSession.StateCallback callback, + @Nullable Handler handler) + throws CameraAccessException; + + /** + * Standard camera operation mode. + * + * @see #createCustomCaptureSession + * @hide + */ + @SystemApi + @TestApi + public static final int SESSION_OPERATION_MODE_NORMAL = + 0; // ICameraDeviceUser.NORMAL_MODE; + + /** + * Constrained high-speed operation mode. + * + * @see #createCustomCaptureSession + * @hide + */ + @SystemApi + @TestApi + public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = + 1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE; + + /** + * First vendor-specific operating mode + * + * @see #createCustomCaptureSession + * @hide + */ + @SystemApi + @TestApi + public static final int SESSION_OPERATION_MODE_VENDOR_START = + 0x8000; // ICameraDeviceUser.VENDOR_MODE_START; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"SESSION_OPERATION_MODE"}, value = + {SESSION_OPERATION_MODE_NORMAL, + SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED, + SESSION_OPERATION_MODE_VENDOR_START}) + public @interface SessionOperatingMode {}; + + /** + * Create a new camera capture session with a custom operating mode. + * + * @param inputConfig The configuration for the input {@link Surface} if a reprocessing session + * is desired, or {@code null} otherwise. + * @param outputs The new set of {@link OutputConfiguration OutputConfigurations} that should be + * made available as targets for captured image data. + * @param operatingMode The custom operating mode to use; a nonnegative value, either a custom + * vendor value or one of the SESSION_OPERATION_MODE_* values. + * @param callback The callback to notify about the status of the new capture session. + * @param handler The handler on which the callback should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * + * @throws IllegalArgumentException if the input configuration is null or not supported, the set + * of output Surfaces do not meet the requirements, the + * callback is null, or the handler is null but the current + * thread has no looper. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see #createCaptureSession + * @see #createReprocessableCaptureSession + * @see CameraCaptureSession + * @see OutputConfiguration + * @deprecated Please use @{link + * #createCaptureSession(android.hardware.camera2.params.SessionConfiguration)} for the + * full set of configuration options available. + * @hide + */ + @SystemApi + @TestApi + @Deprecated + public abstract void createCustomCaptureSession( + InputConfiguration inputConfig, + @NonNull List<OutputConfiguration> outputs, + @SessionOperatingMode int operatingMode, + @NonNull CameraCaptureSession.StateCallback callback, + @Nullable Handler handler) + throws CameraAccessException; + + /** + * <p>Create a new {@link CameraCaptureSession} using a {@link SessionConfiguration} helper + * object that aggregates all supported parameters.</p> * <p>The active capture session determines the set of potential output Surfaces for * the camera device for each capture request. A given request may use all * or only some of the outputs. Once the CameraCaptureSession is created, requests can be @@ -308,11 +524,15 @@ public abstract class CameraDevice implements AutoCloseable { * <p>Configuring a session with an empty or null list will close the current session, if * any. This can be used to release the current session's target surfaces for another use.</p> * + * <h3>Regular capture</h3> + * * <p>While any of the sizes from {@link StreamConfigurationMap#getOutputSizes} can be used when * a single output stream is configured, a given camera device may not be able to support all * combination of sizes, formats, and targets when multiple outputs are configured at once. The * tables below list the maximum guaranteed resolutions for combinations of streams and targets, - * given the capabilities of the camera device.</p> + * given the capabilities of the camera device. These are valid for when the + * {@link android.hardware.camera2.params.SessionConfiguration#setInputConfiguration + * input configuration} is not set and therefore no reprocessing is active.</p> * * <p>If an application tries to create a session using a set of targets that exceed the limits * described in the below tables, one of three possibilities may occur. First, the session may @@ -488,56 +708,22 @@ public abstract class CameraDevice implements AutoCloseable { * (either width or height) might not be supported, and capture session creation will fail if it * is not.</p> * - * @param outputs The new set of Surfaces that should be made available as - * targets for captured image data. - * @param callback The callback to notify about the status of the new capture session. - * @param handler The handler on which the callback should be invoked, or {@code null} to use - * the current thread's {@link android.os.Looper looper}. - * - * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, - * the callback is null, or the handler is null but the current - * thread has no looper. - * @throws CameraAccessException if the camera device is no longer connected or has - * encountered a fatal error - * @throws IllegalStateException if the camera device has been closed - * - * @see CameraCaptureSession - * @see StreamConfigurationMap#getOutputFormats() - * @see StreamConfigurationMap#getOutputSizes(int) - * @see StreamConfigurationMap#getOutputSizes(Class) - */ - public abstract void createCaptureSession(@NonNull List<Surface> outputs, - @NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler) - throws CameraAccessException; - - /** - * <p>Create a new camera capture session by providing the target output set of Surfaces and - * its corresponding surface configuration to the camera device.</p> - * - * @see #createCaptureSession - * @see OutputConfiguration - */ - public abstract void createCaptureSessionByOutputConfigurations( - List<OutputConfiguration> outputConfigurations, - CameraCaptureSession.StateCallback callback, @Nullable Handler handler) - throws CameraAccessException; - /** - * Create a new reprocessable camera capture session by providing the desired reprocessing - * input Surface configuration and the target output set of Surfaces to the camera device. + * <h3>Reprocessing</h3> * * <p>If a camera device supports YUV reprocessing * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING}) or PRIVATE * reprocessing - * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING}), besides - * the capture session created via {@link #createCaptureSession createCaptureSession}, the + * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING}), the * application can also create a reprocessable capture session to submit reprocess capture - * requests in addition to regular capture requests. A reprocess capture request takes the next - * available buffer from the session's input Surface, and sends it through the camera device's - * processing pipeline again, to produce buffers for the request's target output Surfaces. No - * new image data is captured for a reprocess request. However the input buffer provided by - * the application must be captured previously by the same camera device in the same session - * directly (e.g. for Zero-Shutter-Lag use case) or indirectly (e.g. combining multiple output - * images).</p> + * requests in addition to regular capture requests, by setting an + * {@link android.hardware.camera2.params.SessionConfiguration#setInputConfiguration + * input configuration} for the session. A reprocess capture request takes the next available + * buffer from the + * session's input Surface, and sends it through the camera device's processing pipeline again, + * to produce buffers for the request's target output Surfaces. No new image data is captured + * for a reprocess request. However the input buffer provided by the application must be + * captured previously by the same camera device in the same session directly (e.g. for + * Zero-Shutter-Lag use case) or indirectly (e.g. combining multiple output images).</p> * * <p>The active reprocessable capture session determines an input {@link Surface} and the set * of potential output Surfaces for the camera devices for each capture request. The application @@ -570,10 +756,7 @@ public abstract class CameraDevice implements AutoCloseable { * <p>Starting from API level 30, recreating a reprocessable capture session will flush all the * queued but not yet processed buffers from the input surface.</p> * - * <p>The guaranteed stream configurations listed in - * {@link #createCaptureSession createCaptureSession} are also guaranteed to work for - * {@link #createReprocessableCaptureSession createReprocessableCaptureSession}. In addition, - * the configurations in the tables below are also guaranteed for creating a reprocessable + * <p>The configurations in the tables below are guaranteed for creating a reprocessable * capture session if the camera device supports YUV reprocessing or PRIVATE reprocessing. * However, not all output targets used to create a reprocessable session may be used in a * {@link CaptureRequest} simultaneously. For devices that support only 1 output target in a @@ -602,7 +785,7 @@ public abstract class CameraDevice implements AutoCloseable { * <p>LIMITED-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices * support at least the following stream combinations for creating a reprocessable capture - * session in addition to those listed in {@link #createCaptureSession createCaptureSession} for + * session in addition to those listed earlier for regular captures for * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: * * <table> @@ -671,74 +854,30 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * - * <p>Clients can access the above mandatory stream combination tables via - * {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p> - * - * @param inputConfig The configuration for the input {@link Surface} - * @param outputs The new set of Surfaces that should be made available as - * targets for captured image data. - * @param callback The callback to notify about the status of the new capture session. - * @param handler The handler on which the callback should be invoked, or {@code null} to use - * the current thread's {@link android.os.Looper looper}. - * - * @throws IllegalArgumentException if the input configuration is null or not supported, the set - * of output Surfaces do not meet the requirements, the - * callback is null, or the handler is null but the current - * thread has no looper. - * @throws CameraAccessException if the camera device is no longer connected or has - * encountered a fatal error - * @throws IllegalStateException if the camera device has been closed - * - * @see #createCaptureSession - * @see CameraCaptureSession - * @see StreamConfigurationMap#getInputFormats - * @see StreamConfigurationMap#getInputSizes - * @see StreamConfigurationMap#getValidOutputFormatsForInput - * @see StreamConfigurationMap#getOutputSizes - * @see android.media.ImageWriter - * @see android.media.ImageReader - */ - public abstract void createReprocessableCaptureSession(@NonNull InputConfiguration inputConfig, - @NonNull List<Surface> outputs, @NonNull CameraCaptureSession.StateCallback callback, - @Nullable Handler handler) - throws CameraAccessException; - - /** - * Create a new reprocessable camera capture session by providing the desired reprocessing - * input configuration and output {@link OutputConfiguration} - * to the camera device. - * - * @see #createReprocessableCaptureSession - * @see OutputConfiguration + * <h3>Constrained high-speed recording</h3> * - */ - public abstract void createReprocessableCaptureSessionByConfigurations( - @NonNull InputConfiguration inputConfig, - @NonNull List<OutputConfiguration> outputs, - @NonNull CameraCaptureSession.StateCallback callback, - @Nullable Handler handler) - throws CameraAccessException; - - /** - * <p>Create a new constrained high speed capture session.</p> - * - * <p>The application can use normal capture session (created via {@link #createCaptureSession}) + * <p>The application can use a + * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_REGULAR + * normal capture session} * for high speed capture if the desired high speed FPS ranges are advertised by * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}, in which case all API * semantics associated with normal capture sessions applies.</p> * - * <p>The method creates a specialized capture session that is only targeted at high speed - * video recording (>=120fps) use case if the camera device supports high speed video - * capability (i.e., {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} contains - * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO}). - * Therefore, it has special characteristics compared with a normal capture session:</p> + * <p>A + * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_HIGH_SPEED + * high-speed capture session} + * can be use for high speed video recording (>=120fps) when the camera device supports high + * speed video capability (i.e., {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} + * contains {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO}). + * A constrained high-speed capture session has special limitations compared with a normal + * capture session:</p> * * <ul> * - * <li>In addition to the output target Surface requirements specified by the - * {@link #createCaptureSession} method, an active high speed capture session will support up - * to 2 output Surfaces, though the application might choose to configure just one Surface - * (e.g., preview only). All Surfaces must be either video encoder surfaces (acquired by + * <li>In addition to the output target Surface requirements specified above for regular + * captures, a high speed capture session will only support up to 2 output Surfaces, though + * the application might choose to configure just one Surface (e.g., preview only). All + * Surfaces must be either video encoder surfaces (acquired by * {@link android.media.MediaRecorder#getSurface} or * {@link android.media.MediaCodec#createInputSurface}) or preview surfaces (obtained from * {@link android.view.SurfaceView}, {@link android.graphics.SurfaceTexture} via @@ -774,116 +913,6 @@ public abstract class CameraDevice implements AutoCloseable { * * </ul> * - * @param outputs The new set of Surfaces that should be made available as - * targets for captured high speed image data. - * @param callback The callback to notify about the status of the new capture session. - * @param handler The handler on which the callback should be invoked, or {@code null} to use - * the current thread's {@link android.os.Looper looper}. - * - * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, - * the callback is null, or the handler is null but the current - * thread has no looper, or the camera device doesn't support - * high speed video capability. - * @throws CameraAccessException if the camera device is no longer connected or has - * encountered a fatal error - * @throws IllegalStateException if the camera device has been closed - * - * @see #createCaptureSession - * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE - * @see StreamConfigurationMap#getHighSpeedVideoSizes - * @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor - * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES - * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO - * @see CameraCaptureSession#captureBurst - * @see CameraCaptureSession#setRepeatingBurst - * @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList - */ - public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs, - @NonNull CameraCaptureSession.StateCallback callback, - @Nullable Handler handler) - throws CameraAccessException; - - /** - * Standard camera operation mode. - * - * @see #createCustomCaptureSession - * @hide - */ - @SystemApi - @TestApi - public static final int SESSION_OPERATION_MODE_NORMAL = - 0; // ICameraDeviceUser.NORMAL_MODE; - - /** - * Constrained high-speed operation mode. - * - * @see #createCustomCaptureSession - * @hide - */ - @SystemApi - @TestApi - public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = - 1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE; - - /** - * First vendor-specific operating mode - * - * @see #createCustomCaptureSession - * @hide - */ - @SystemApi - @TestApi - public static final int SESSION_OPERATION_MODE_VENDOR_START = - 0x8000; // ICameraDeviceUser.VENDOR_MODE_START; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"SESSION_OPERATION_MODE"}, value = - {SESSION_OPERATION_MODE_NORMAL, - SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED, - SESSION_OPERATION_MODE_VENDOR_START}) - public @interface SessionOperatingMode {}; - - /** - * Create a new camera capture session with a custom operating mode. - * - * @param inputConfig The configuration for the input {@link Surface} if a reprocessing session - * is desired, or {@code null} otherwise. - * @param outputs The new set of {@link OutputConfiguration OutputConfigurations} that should be - * made available as targets for captured image data. - * @param operatingMode The custom operating mode to use; a nonnegative value, either a custom - * vendor value or one of the SESSION_OPERATION_MODE_* values. - * @param callback The callback to notify about the status of the new capture session. - * @param handler The handler on which the callback should be invoked, or {@code null} to use - * the current thread's {@link android.os.Looper looper}. - * - * @throws IllegalArgumentException if the input configuration is null or not supported, the set - * of output Surfaces do not meet the requirements, the - * callback is null, or the handler is null but the current - * thread has no looper. - * @throws CameraAccessException if the camera device is no longer connected or has - * encountered a fatal error - * @throws IllegalStateException if the camera device has been closed - * - * @see #createCaptureSession - * @see #createReprocessableCaptureSession - * @see CameraCaptureSession - * @see OutputConfiguration - * @hide - */ - @SystemApi - @TestApi - public abstract void createCustomCaptureSession( - InputConfiguration inputConfig, - @NonNull List<OutputConfiguration> outputs, - @SessionOperatingMode int operatingMode, - @NonNull CameraCaptureSession.StateCallback callback, - @Nullable Handler handler) - throws CameraAccessException; - - /** - * <p>Create a new {@link CameraCaptureSession} using a {@link SessionConfiguration} helper - * object that aggregates all supported parameters.</p> * * @param config A session configuration (see {@link SessionConfiguration}). * @@ -997,7 +1026,7 @@ public abstract class CameraDevice implements AutoCloseable { * * @see CaptureRequest.Builder * @see TotalCaptureResult - * @see CameraDevice#createReprocessableCaptureSession + * @see CameraDevice#createCaptureSession(android.hardware.camera2.params.SessionConfiguration) * @see android.media.ImageWriter */ @NonNull @@ -1028,7 +1057,8 @@ public abstract class CameraDevice implements AutoCloseable { * <p>This method performs a runtime check of a given {@link SessionConfiguration}. The result * confirms whether or not the passed session configuration can be successfully used to * create a camera capture session using - * {@link CameraDevice#createCaptureSession(SessionConfiguration)}. + * {@link CameraDevice#createCaptureSession( + * android.hardware.camera2.params.SessionConfiguration)}. * </p> * * <p>The method can be called at any point before, during and after active capture session. diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 8e0a46d52dd6..ec13a36ca1d2 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1121,12 +1121,16 @@ public abstract class CameraMetadata<TKey> { // /** - * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in nanoseconds and monotonic, - * but can not be compared to timestamps from other subsystems - * (e.g. accelerometer, gyro etc.), or other instances of the same or different - * camera devices in the same system. Timestamps between streams and results for - * a single camera instance are comparable, and the timestamps for all buffers - * and the result metadata generated by a single capture are identical.</p> + * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in nanoseconds and monotonic, but can + * not be compared to timestamps from other subsystems (e.g. accelerometer, gyro etc.), + * or other instances of the same or different camera devices in the same system with + * accuracy. However, the timestamps are roughly in the same timebase as + * {@link android.os.SystemClock#uptimeMillis }. The accuracy is sufficient for tasks + * like A/V synchronization for video recording, at least, and the timestamps can be + * directly used together with timestamps from the audio subsystem for that task.</p> + * <p>Timestamps between streams and results for a single camera instance are comparable, + * and the timestamps for all buffers and the result metadata generated by a single + * capture are identical.</p> * * @see CaptureResult#SENSOR_TIMESTAMP * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE @@ -1137,6 +1141,14 @@ public abstract class CameraMetadata<TKey> { * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in the same timebase as * {@link android.os.SystemClock#elapsedRealtimeNanos }, * and they can be compared to other timestamps using that base.</p> + * <p>When buffers from a REALTIME device are passed directly to a video encoder from the + * camera, automatic compensation is done to account for differing timebases of the + * audio and camera subsystems. If the application is receiving buffers and then later + * sending them to a video encoder or other application where they are compared with + * audio subsystem timestamps or similar, this compensation is not present. In those + * cases, applications need to adjust the timestamps themselves. Since {@link android.os.SystemClock#elapsedRealtimeNanos } and {@link android.os.SystemClock#uptimeMillis } only diverge while the device is asleep, an + * offset between the two sources can be measured once per active session and applied + * to timestamps for sufficient accuracy for A/V sync.</p> * * @see CaptureResult#SENSOR_TIMESTAMP * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java index 555ff9aff184..47a897cb2c55 100644 --- a/core/java/android/hardware/camera2/params/SessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java @@ -17,10 +17,11 @@ package android.hardware.camera2.params; +import static com.android.internal.util.Preconditions.*; + import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.IntDef; +import android.annotation.NonNull; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; @@ -32,14 +33,12 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.ArrayList; import java.util.concurrent.Executor; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import static com.android.internal.util.Preconditions.*; /** * A helper class that aggregates all supported arguments for capture session initialization. @@ -61,6 +60,12 @@ public final class SessionConfiguration implements Parcelable { * A high speed session type that can only contain instances of {@link OutputConfiguration}. * The outputs can run using high speed FPS ranges. Calls to {@link #setInputConfiguration} * are not supported. + * <p> + * When using this type, the CameraCaptureSession returned by + * {@link android.hardware.camera2.CameraCaptureSession.StateCallback} can be cast to a + * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession} to access the extra + * methods for constrained high speed recording. + * </p> * * @see CameraDevice#createConstrainedHighSpeedCaptureSession */ diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 60e466e5f278..a5e0f04eb034 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -303,16 +303,20 @@ public class SoundTrigger { @NonNull public final UUID vendorUuid; + /** vendor specific version number of the model */ + public final int version; + /** Opaque data. For use by vendor implementation and enrollment application */ @UnsupportedAppUsage @NonNull public final byte[] data; public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, int type, - @Nullable byte[] data) { + @Nullable byte[] data, int version) { this.uuid = requireNonNull(uuid); this.vendorUuid = vendorUuid != null ? vendorUuid : new UUID(0, 0); this.type = type; + this.version = version; this.data = data != null ? data : new byte[0]; } @@ -320,6 +324,7 @@ public class SoundTrigger { public int hashCode() { final int prime = 31; int result = 1; + result = prime * result + version; result = prime * result + Arrays.hashCode(data); result = prime * result + type; result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); @@ -350,6 +355,8 @@ public class SoundTrigger { return false; if (!Arrays.equals(data, other.data)) return false; + if (version != other.version) + return false; return true; } } @@ -499,14 +506,19 @@ public class SoundTrigger { @NonNull public final Keyphrase[] keyphrases; // keyword phrases in model - @UnsupportedAppUsage public KeyphraseSoundModel( @NonNull UUID uuid, @NonNull UUID vendorUuid, @Nullable byte[] data, - @Nullable Keyphrase[] keyphrases) { - super(uuid, vendorUuid, TYPE_KEYPHRASE, data); + @Nullable Keyphrase[] keyphrases, int version) { + super(uuid, vendorUuid, TYPE_KEYPHRASE, data, version); this.keyphrases = keyphrases != null ? keyphrases : new Keyphrase[0]; } + @UnsupportedAppUsage + public KeyphraseSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid, + @Nullable byte[] data, @Nullable Keyphrase[] keyphrases) { + this(uuid, vendorUuid, data, keyphrases, -1); + } + public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR = new Parcelable.Creator<KeyphraseSoundModel>() { public KeyphraseSoundModel createFromParcel(Parcel in) { @@ -525,9 +537,10 @@ public class SoundTrigger { if (length >= 0) { vendorUuid = UUID.fromString(in.readString()); } + int version = in.readInt(); byte[] data = in.readBlob(); Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR); - return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases); + return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases, version); } @Override @@ -546,13 +559,16 @@ public class SoundTrigger { } dest.writeBlob(data); dest.writeTypedArray(keyphrases, flags); + dest.writeInt(version); } @Override public String toString() { return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases) + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid - + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]"; + + ", type=" + type + + ", data=" + (data == null ? 0 : data.length) + + ", version=" + version + "]"; } @Override @@ -598,10 +614,15 @@ public class SoundTrigger { } }; + public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid, + @Nullable byte[] data, int version) { + super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data, version); + } + @UnsupportedAppUsage public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid, @Nullable byte[] data) { - super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data); + this(uuid, vendorUuid, data, -1); } @Override @@ -617,7 +638,8 @@ public class SoundTrigger { vendorUuid = UUID.fromString(in.readString()); } byte[] data = in.readBlob(); - return new GenericSoundModel(uuid, vendorUuid, data); + int version = in.readInt(); + return new GenericSoundModel(uuid, vendorUuid, data, version); } @Override @@ -630,12 +652,15 @@ public class SoundTrigger { dest.writeString(vendorUuid.toString()); } dest.writeBlob(data); + dest.writeInt(version); } @Override public String toString() { return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid - + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]"; + + ", type=" + type + + ", data=" + (data == null ? 0 : data.length) + + ", version=" + version + "]"; } } diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index a66fcae7d4a2..fb35b4bde303 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -60,6 +60,18 @@ public class CaptivePortal implements Parcelable { @SystemApi @TestApi public static final int APP_RETURN_WANTED_AS_IS = 2; + /** Event offset of request codes from captive portal application. */ + private static final int APP_REQUEST_BASE = 100; + /** + * Request code from the captive portal application, indicating that the network condition may + * have changed and the network should be re-validated. + * @see ICaptivePortal#appRequest(int) + * @see android.net.INetworkMonitor#forceReevaluation(int) + * @hide + */ + @SystemApi + @TestApi + public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0; private final IBinder mBinder; @@ -136,6 +148,19 @@ public class CaptivePortal implements Parcelable { } /** + * Request that the system reevaluates the captive portal status. + * @hide + */ + @SystemApi + @TestApi + public void reevaluateNetwork() { + try { + ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED); + } catch (RemoteException e) { + } + } + + /** * Log a captive portal login event. * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto. * @param packageName captive portal application package name. diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4bf3e905697d..c523f6514c54 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -517,7 +517,7 @@ public class ConnectivityManager { * The absence of a connection type. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + @SystemApi public static final int TYPE_NONE = -1; /** @@ -3169,10 +3169,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config) { return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE); } @@ -3180,10 +3180,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { try { return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId); diff --git a/core/java/android/net/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl index 707b4f699873..fe21905c7002 100644 --- a/core/java/android/net/ICaptivePortal.aidl +++ b/core/java/android/net/ICaptivePortal.aidl @@ -21,6 +21,7 @@ package android.net; * @hide */ oneway interface ICaptivePortal { + void appRequest(int request); void appResponse(int response); void logEvent(int eventId, String packageName); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 7691beba3208..186196bd31c7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -152,7 +152,7 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkAgentConfig config, in int factorySerialNumber); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index fc72eecd4145..d28620433c21 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -44,9 +44,10 @@ import java.util.concurrent.atomic.AtomicBoolean; * @hide */ public abstract class NetworkAgent { - // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown - // an exception. - public final int netId; + // Guaranteed to be non-null, otherwise registerNetworkAgent() would have thrown + // an exception. Be careful in tests when mocking though. + @NonNull + public final Network network; private final Handler mHandler; private volatile AsyncChannel mAsyncChannel; @@ -246,7 +247,7 @@ public abstract class NetworkAgent { if (VDBG) log("Registering NetworkAgent"); ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); - netId = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni), + network = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, config, providerId); } diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java index 3a383a44cdc3..abc6b67efb11 100644 --- a/core/java/android/net/NetworkAgentConfig.java +++ b/core/java/android/net/NetworkAgentConfig.java @@ -18,22 +18,27 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; /** - * A grab-bag of information (metadata, policies, properties, etc) about a - * {@link Network}. Since this contains PII, it should not be sent outside the - * system. + * Allows a network transport to provide the system with policy and configuration information about + * a particular network when registering a {@link NetworkAgent}. This information cannot change once + * the agent is registered. * * @hide */ -public class NetworkAgentConfig implements Parcelable { +@SystemApi +public final class NetworkAgentConfig implements Parcelable { /** * If the {@link Network} is a VPN, whether apps are allowed to bypass the * VPN. This is set by a {@link VpnService} and used by * {@link ConnectivityManager} when creating a VPN. + * + * @hide */ public boolean allowBypass; @@ -43,6 +48,8 @@ public class NetworkAgentConfig implements Parcelable { * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to * connect to a particular access point is also explicit, though this may change in the future * as we want apps to use the multinetwork apis. + * + * @hide */ public boolean explicitlySelected; @@ -50,12 +57,16 @@ public class NetworkAgentConfig implements Parcelable { * Set if the user desires to use this network even if it is unvalidated. This field has meaning * only if {@link explicitlySelected} is true. If it is, this field must also be set to the * appropriate value based on previous user choice. + * + * @hide */ public boolean acceptUnvalidated; /** * Whether the user explicitly set that this network should be validated even if presence of * only partial internet connectivity. + * + * @hide */ public boolean acceptPartialConnectivity; @@ -65,29 +76,62 @@ public class NetworkAgentConfig implements Parcelable { * procedure, a carrier specific provisioning notification will be placed. * only one notification should be displayed. This field is set based on * which notification should be used for provisioning. + * + * @hide */ public boolean provisioningNotificationDisabled; /** + * + * @return whether the sign in to network notification is enabled by this configuration. + */ + public boolean isProvisioningNotificationEnabled() { + return !provisioningNotificationDisabled; + } + + /** * For mobile networks, this is the subscriber ID (such as IMSI). + * + * @hide */ public String subscriberId; /** + * @return the subscriber ID, or null if none. + */ + @Nullable + public String getSubscriberId() { + return subscriberId; + } + + /** * Set to skip 464xlat. This means the device will treat the network as IPv6-only and * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. + * + * @hide */ public boolean skip464xlat; /** + * @return whether NAT64 prefix detection is enabled. + */ + public boolean isNat64DetectionEnabled() { + return !skip464xlat; + } + + /** * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. + * + * @hide */ public boolean hasShownBroken; + /** @hide */ public NetworkAgentConfig() { } + /** @hide */ public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) { if (nac != null) { allowBypass = nac.allowBypass; @@ -99,13 +143,63 @@ public class NetworkAgentConfig implements Parcelable { } } + /** + * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. + */ + public static class Builder { + private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); + + /** + * Sets the subscriber ID for this network. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setSubscriberId(@Nullable String subscriberId) { + mConfig.subscriberId = subscriberId; + return this; + } + + /** + * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power + * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableNat64Detection() { + mConfig.skip464xlat = true; + return this; + } + + /** + * Disables the "Sign in to network" notification. Used if the network transport will + * perform its own carrier-specific provisioning procedure. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableProvisioningNotification() { + mConfig.provisioningNotificationDisabled = true; + return this; + } + + /** + * Returns the constructed {@link NetworkAgentConfig} object. + */ + @NonNull + public NetworkAgentConfig build() { + return mConfig; + } + } + @Override public int describeContents() { return 0; } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeInt(allowBypass ? 1 : 0); out.writeInt(explicitlySelected ? 1 : 0); out.writeInt(acceptUnvalidated ? 1 : 0); diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index b0c2546e0300..ac70b523bcc1 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -631,10 +631,12 @@ public final class BinderProxy implements IBinder { } } - private static void sendDeathNotice(DeathRecipient recipient) { - if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient); + private static void sendDeathNotice(DeathRecipient recipient, IBinder binderProxy) { + if (false) { + Log.v("JavaBinder", "sendDeathNotice to " + recipient + " for " + binderProxy); + } try { - recipient.binderDied(); + recipient.binderDied(binderProxy); } catch (RuntimeException exc) { Log.w("BinderNative", "Uncaught exception from death notification", exc); diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index f336fdab5941..f5fe9c3334bd 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -285,6 +285,13 @@ public interface IBinder { */ public interface DeathRecipient { public void binderDied(); + + /** + * @hide + */ + default void binderDied(IBinder who) { + binderDied(); + } } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a31c3d1749c6..548b1230d6e2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -510,28 +510,31 @@ public final class Settings { "android.settings.WIFI_IP_SETTINGS"; /** - * Activity Action: Show setting page to process an Easy Connect (Wi-Fi DPP) QR code and start + * Activity Action: Show setting page to process a Wi-Fi Easy Connect (aka DPP) URI and start * configuration. This intent should be used when you want to use this device to take on the - * configurator role for an IoT/other device. When provided with a valid DPP URI string Settings - * will open a wifi selection screen for the user to indicate which network they would like to - * configure the device specified in the DPP URI string for and carry them through the rest of - * the flow for provisioning the device. + * configurator role for an IoT/other device. When provided with a valid DPP URI + * string, Settings will open a Wi-Fi selection screen for the user to indicate which network + * they would like to configure the device specified in the DPP URI string and + * carry them through the rest of the flow for provisioning the device. * <p> - * In some cases, a matching Activity may not exist, so ensure you safeguard against this by - * checking WifiManager.isEasyConnectSupported(); + * In some cases, a matching Activity may not exist, so ensure to safeguard against this by + * checking {@link WifiManager#isEasyConnectSupported()}. * <p> * Input: The Intent's data URI specifies bootstrapping information for authenticating and - * provisioning the peer, with the "DPP" scheme. - * <p> - * Output: After {@code startActivityForResult}, the callback {@code onActivityResult} will have - * resultCode {@link android.app.Activity#RESULT_OK} if Wi-Fi Easy Connect configuration succeeded - * and the user tapped 'Done' button, or {@link android.app.Activity#RESULT_CANCELED} if operation - * failed and user tapped 'Cancel'. In case the operation has failed, a status code from {@link - * android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode} will be returned as - * Extra {@link #EXTRA_EASY_CONNECT_ERROR_CODE}. Easy Connect R2 Enrollees report additional - * details about the error they encountered, which will be provided in the {@link - * #EXTRA_EASY_CONNECT_ATTEMPTED_SSID}, {@link #EXTRA_EASY_CONNECT_CHANNEL_LIST}, and {@link - * #EXTRA_EASY_CONNECT_BAND_LIST}. + * provisioning the peer, and uses a "DPP" scheme. The URI should be attached to the intent + * using {@link Intent#setData(Uri)}. The calling app can obtain a DPP URI in any + * way, e.g. by scanning a QR code or other out-of-band methods. + * <p> + * Output: After calling {@link android.app.Activity#startActivityForResult}, the callback + * {@code onActivityResult} will have resultCode {@link android.app.Activity#RESULT_OK} if + * the Wi-Fi Easy Connect configuration succeeded and the user tapped the 'Done' button, or + * {@link android.app.Activity#RESULT_CANCELED} if the operation failed and user tapped the + * 'Cancel' button. In case the operation has failed, a status code from + * {@link android.net.wifi.EasyConnectStatusCallback} {@code EASY_CONNECT_EVENT_FAILURE_*} will + * be returned as an Extra {@link #EXTRA_EASY_CONNECT_ERROR_CODE}. Easy Connect R2 + * Enrollees report additional details about the error they encountered, which will be + * provided in the {@link #EXTRA_EASY_CONNECT_ATTEMPTED_SSID}, + * {@link #EXTRA_EASY_CONNECT_CHANNEL_LIST}, and {@link #EXTRA_EASY_CONNECT_BAND_LIST}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_URI = @@ -540,12 +543,15 @@ public final class Settings { /** * Activity Extra: The Easy Connect operation error code * <p> - * An extra returned on the result intent received when using the {@link - * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This - * extra contains the error code of the operation - one of - * {@link android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode}. - * If there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, + * An extra returned on the result intent received when using the + * {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. + * This extra contains the integer error code of the operation - one of + * {@link android.net.wifi.EasyConnectStatusCallback} {@code EASY_CONNECT_EVENT_FAILURE_*}. If + * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, * then this extra is not attached to the result intent. + * <p> + * Use the {@link Intent#hasExtra(String)} to determine whether the extra is attached and + * {@link Intent#getIntExtra(String, int)} to obtain the error code data. */ public static final String EXTRA_EASY_CONNECT_ERROR_CODE = "android.provider.extra.EASY_CONNECT_ERROR_CODE"; @@ -557,11 +563,13 @@ public final class Settings { * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This * extra contains the SSID of the Access Point that the remote Enrollee tried to connect to. * This value is populated only by remote R2 devices, and only for the following error codes: - * {@link android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK} - * {@link android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION}. + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK} + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION}. * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. If * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, then * this extra is not attached to the result intent. + * <p> + * Use the {@link Intent#getStringExtra(String)} to obtain the SSID. */ public static final String EXTRA_EASY_CONNECT_ATTEMPTED_SSID = "android.provider.extra.EASY_CONNECT_ATTEMPTED_SSID"; @@ -571,13 +579,15 @@ public final class Settings { * <p> * An extra returned on the result intent received when using the {@link * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This - * extra contains the list channels the Enrollee used to scan for a network. This value is + * extra contains the channel list that the Enrollee scanned for a network. This value is * populated only by remote R2 devices, and only for the following error code: {@link - * android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK}. + * android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK}. * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. If * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, then * this extra is not attached to the result intent. The list is JSON formatted, as an array * (Wi-Fi global operating classes) of arrays (Wi-Fi channels). + * <p> + * Use the {@link Intent#getStringExtra(String)} to obtain the list. */ public static final String EXTRA_EASY_CONNECT_CHANNEL_LIST = "android.provider.extra.EASY_CONNECT_CHANNEL_LIST"; @@ -588,14 +598,16 @@ public final class Settings { * An extra returned on the result intent received when using the {@link * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This * extra contains the bands the Enrollee supports, expressed as the Global Operating Class, - * see Table E-4 in IEEE Std 802.11-2016 -Global operating classes. This value is populated only + * see Table E-4 in IEEE Std 802.11-2016 Global operating classes. This value is populated only * by remote R2 devices, and only for the following error codes: {@link - * android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK} - * {@link android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION} - * {@link android.net.wifi.EasyConnectStatusCallback.EasyConnectFailureStatusCode#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION}. + * android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK} + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION} + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION}. * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. If * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, then * this extra is not attached to the result intent. + * <p> + * Use the {@link Intent#getIntArrayExtra(String)} to obtain the list. */ public static final String EXTRA_EASY_CONNECT_BAND_LIST = "android.provider.extra.EASY_CONNECT_BAND_LIST"; diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 2e7ac3f505fa..f3690648f35b 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -4142,7 +4142,6 @@ public final class Telephony { * <li>{@link #ENABLE_CMAS_PRESIDENTIAL_PREF}</li> * <li>{@link #ENABLE_ALERT_VIBRATION_PREF}</li> * <li>{@link #ENABLE_EMERGENCY_PERF}</li> - * <li>{@link #ENABLE_FULL_VOLUME_PREF}</li> * <li>{@link #ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF}</li> * </ul> * @hide @@ -4205,10 +4204,6 @@ public final class Telephony { public static final @NonNull String ENABLE_EMERGENCY_PERF = "enable_emergency_alerts"; - /** Preference to enable volume for alerts */ - public static final @NonNull String ENABLE_FULL_VOLUME_PREF = - "use_full_volume"; - /** Preference to enable receive alerts in second language */ public static final @NonNull String ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF = "receive_cmas_in_second_language"; diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index d827b30f27b6..262d9896df87 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -21,6 +21,7 @@ import static android.view.autofill.Helper.sDebug; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.IntentSender; import android.os.Parcel; import android.os.Parcelable; @@ -238,6 +239,7 @@ public final class Dataset implements Parcelable { public Builder(@NonNull RemoteViews presentation, @NonNull InlinePresentation inlinePresentation) { Preconditions.checkNotNull(presentation, "presentation must be non-null"); + Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null"); mPresentation = presentation; mInlinePresentation = inlinePresentation; } @@ -248,7 +250,8 @@ public final class Dataset implements Parcelable { * @param presentation The presentation used to visualize this dataset. */ public Builder(@NonNull RemoteViews presentation) { - this(presentation, null); + Preconditions.checkNotNull(presentation, "presentation must be non-null"); + mPresentation = presentation; } /** @@ -262,7 +265,9 @@ public final class Dataset implements Parcelable { * @hide */ @SystemApi + @TestApi public Builder(@NonNull InlinePresentation inlinePresentation) { + Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null"); mInlinePresentation = inlinePresentation; } @@ -576,6 +581,7 @@ public final class Dataset implements Parcelable { * @hide */ @SystemApi + @TestApi public @NonNull Builder setInlinePresentation(@NonNull AutofillId id, @Nullable AutofillValue value, @Nullable Pattern filter, @NonNull InlinePresentation inlinePresentation) { @@ -672,11 +678,13 @@ public final class Dataset implements Parcelable { // using specially crafted parcels. final RemoteViews presentation = parcel.readParcelable(null); final InlinePresentation inlinePresentation = parcel.readParcelable(null); - final Builder builder = presentation == null - ? new Builder(inlinePresentation) - : inlinePresentation == null + final Builder builder = presentation != null + ? inlinePresentation == null ? new Builder(presentation) - : new Builder(presentation, inlinePresentation); + : new Builder(presentation, inlinePresentation) + : inlinePresentation == null + ? new Builder() + : new Builder(inlinePresentation); final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR); final ArrayList<AutofillValue> values = diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 1b2db36c1335..9d22d304ad00 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -42,6 +42,8 @@ public class FeatureFlagUtils { public static final String DYNAMIC_SYSTEM = "settings_dynamic_system"; public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2"; public static final String SETTINGS_FUSE_FLAG = "settings_fuse"; + public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = + "settings_notif_convo_bypass_shortcut_req"; private static final Map<String, String> DEFAULT_FLAGS; @@ -60,6 +62,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_work_profile", "true"); DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false"); DEFAULT_FLAGS.put("settings_conditionals", "false"); + DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false"); } /** diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index fa994ba76fd7..0892c94d5bec 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -16,6 +16,8 @@ package android.util; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; @@ -25,172 +27,270 @@ import android.net.Network; import android.net.NetworkInfo; import android.net.SntpClient; import android.os.SystemClock; -import android.os.TimestampedValue; import android.provider.Settings; import android.text.TextUtils; +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; +import java.util.function.Supplier; + /** - * {@link TrustedTime} that connects with a remote NTP server as its trusted - * time source. + * A singleton that connects with a remote NTP server as its trusted time source. This class + * is thread-safe. The {@link #forceRefresh()} method is synchronous, i.e. it may occupy the + * current thread while performing an NTP request. All other threads calling {@link #forceRefresh()} + * will block during that request. * * @hide */ public class NtpTrustedTime implements TrustedTime { + + /** + * The result of a successful NTP query. + * + * @hide + */ + public static class TimeResult { + private final long mTimeMillis; + private final long mElapsedRealtimeMillis; + private final long mCertaintyMillis; + + public TimeResult(long timeMillis, long elapsedRealtimeMillis, long certaintyMillis) { + mTimeMillis = timeMillis; + mElapsedRealtimeMillis = elapsedRealtimeMillis; + mCertaintyMillis = certaintyMillis; + } + + public long getTimeMillis() { + return mTimeMillis; + } + + public long getElapsedRealtimeMillis() { + return mElapsedRealtimeMillis; + } + + public long getCertaintyMillis() { + return mCertaintyMillis; + } + + /** Calculates and returns the current time accounting for the age of this result. */ + public long currentTimeMillis() { + return mTimeMillis + getAgeMillis(); + } + + /** Calculates and returns the age of this result. */ + public long getAgeMillis() { + return SystemClock.elapsedRealtime() - mElapsedRealtimeMillis; + } + + @Override + public String toString() { + return "TimeResult{" + + "mTimeMillis=" + mTimeMillis + + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + + ", mCertaintyMillis=" + mCertaintyMillis + + '}'; + } + } + private static final String TAG = "NtpTrustedTime"; private static final boolean LOGD = false; private static NtpTrustedTime sSingleton; - private static Context sContext; - private final String mServer; - private final long mTimeout; + @NonNull + private final Context mContext; + + /** + * A supplier that returns the ConnectivityManager. The Supplier can return null if + * ConnectivityService isn't running yet. + */ + private final Supplier<ConnectivityManager> mConnectivityManagerSupplier = + new Supplier<ConnectivityManager>() { + private ConnectivityManager mConnectivityManager; - private ConnectivityManager mCM; + @Nullable + @Override + public synchronized ConnectivityManager get() { + // We can't do this at initialization time: ConnectivityService might not be running + // yet. + if (mConnectivityManager == null) { + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + } + return mConnectivityManager; + } + }; - private boolean mHasCache; - private long mCachedNtpTime; - private long mCachedNtpElapsedRealtime; - private long mCachedNtpCertainty; + // Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during + // forceRefresh(). + private volatile TimeResult mTimeResult; - private NtpTrustedTime(String server, long timeout) { - if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server); - mServer = server; - mTimeout = timeout; + private NtpTrustedTime(Context context) { + mContext = Objects.requireNonNull(context); } @UnsupportedAppUsage public static synchronized NtpTrustedTime getInstance(Context context) { if (sSingleton == null) { - final Resources res = context.getResources(); - final ContentResolver resolver = context.getContentResolver(); - - final String defaultServer = res.getString( - com.android.internal.R.string.config_ntpServer); - final long defaultTimeout = res.getInteger( - com.android.internal.R.integer.config_ntpTimeout); - - final String secureServer = Settings.Global.getString( - resolver, Settings.Global.NTP_SERVER); - final long timeout = Settings.Global.getLong( - resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout); - - final String server = secureServer != null ? secureServer : defaultServer; - sSingleton = new NtpTrustedTime(server, timeout); - sContext = context; + Context appContext = context.getApplicationContext(); + sSingleton = new NtpTrustedTime(appContext); } - return sSingleton; } - @Override @UnsupportedAppUsage public boolean forceRefresh() { - // We can't do this at initialization time: ConnectivityService might not be running yet. synchronized (this) { - if (mCM == null) { - mCM = sContext.getSystemService(ConnectivityManager.class); + NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); + if (connectionInfo == null) { + // missing server config, so no trusted time available + if (LOGD) Log.d(TAG, "forceRefresh: invalid server config"); + return false; } - } - final Network network = mCM == null ? null : mCM.getActiveNetwork(); - return forceRefresh(network); - } - - public boolean forceRefresh(Network network) { - if (TextUtils.isEmpty(mServer)) { - // missing server, so no trusted time available - return false; - } - - // We can't do this at initialization time: ConnectivityService might not be running yet. - synchronized (this) { - if (mCM == null) { - mCM = sContext.getSystemService(ConnectivityManager.class); + ConnectivityManager connectivityManager = mConnectivityManagerSupplier.get(); + if (connectivityManager == null) { + if (LOGD) Log.d(TAG, "forceRefresh: no ConnectivityManager"); + return false; + } + final Network network = connectivityManager.getActiveNetwork(); + final NetworkInfo ni = connectivityManager.getNetworkInfo(network); + if (ni == null || !ni.isConnected()) { + if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); + return false; } - } - - final NetworkInfo ni = mCM == null ? null : mCM.getNetworkInfo(network); - if (ni == null || !ni.isConnected()) { - if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); - return false; - } - - if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); - final SntpClient client = new SntpClient(); - if (client.requestTime(mServer, (int) mTimeout, network)) { - mHasCache = true; - mCachedNtpTime = client.getNtpTime(); - mCachedNtpElapsedRealtime = client.getNtpTimeReference(); - mCachedNtpCertainty = client.getRoundTripTime() / 2; - return true; - } else { - return false; + if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); + final SntpClient client = new SntpClient(); + final String serverName = connectionInfo.getServer(); + final int timeoutMillis = connectionInfo.getTimeoutMillis(); + if (client.requestTime(serverName, timeoutMillis, network)) { + long ntpCertainty = client.getRoundTripTime() / 2; + mTimeResult = new TimeResult( + client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty); + return true; + } else { + return false; + } } } - @Override + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public boolean hasCache() { - return mHasCache; + return mTimeResult != null; } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @Override public long getCacheAge() { - if (mHasCache) { - return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime; + TimeResult timeResult = mTimeResult; + if (timeResult != null) { + return SystemClock.elapsedRealtime() - timeResult.getElapsedRealtimeMillis(); } else { return Long.MAX_VALUE; } } - @Override - public long getCacheCertainty() { - if (mHasCache) { - return mCachedNtpCertainty; - } else { - return Long.MAX_VALUE; - } - } - - @Override + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long currentTimeMillis() { - if (!mHasCache) { + TimeResult timeResult = mTimeResult; + if (timeResult == null) { throw new IllegalStateException("Missing authoritative time source"); } if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit"); // current time is age after the last ntp cache; callers who - // want fresh values will hit makeAuthoritative() first. - return mCachedNtpTime + getCacheAge(); + // want fresh values will hit forceRefresh() first. + return timeResult.currentTimeMillis(); } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long getCachedNtpTime() { if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit"); - return mCachedNtpTime; + TimeResult timeResult = mTimeResult; + return timeResult == null ? 0 : timeResult.getTimeMillis(); } + /** + * Only kept for UnsupportedAppUsage. + * + * @deprecated Use {@link #getCachedTimeResult()} to obtain a {@link TimeResult} atomically. + */ + @Deprecated @UnsupportedAppUsage public long getCachedNtpTimeReference() { - return mCachedNtpElapsedRealtime; + TimeResult timeResult = mTimeResult; + return timeResult == null ? 0 : timeResult.getElapsedRealtimeMillis(); } /** - * Returns the combination of {@link #getCachedNtpTime()} and {@link - * #getCachedNtpTimeReference()} as a {@link TimestampedValue}. This method is useful when - * passing the time to another component that will adjust for elapsed time. - * - * @throws IllegalStateException if there is no cached value + * Returns an object containing the latest NTP information available. Can return {@code null} if + * no information is available. */ - public TimestampedValue<Long> getCachedNtpTimeSignal() { - if (!mHasCache) { - throw new IllegalStateException("Missing authoritative time source"); + @Nullable + public TimeResult getCachedTimeResult() { + return mTimeResult; + } + + private static class NtpConnectionInfo { + + @NonNull private final String mServer; + private final int mTimeoutMillis; + + NtpConnectionInfo(@NonNull String server, int timeoutMillis) { + mServer = Objects.requireNonNull(server); + mTimeoutMillis = timeoutMillis; } - if (LOGD) Log.d(TAG, "getCachedNtpTimeSignal() cache hit"); - return new TimestampedValue<>(mCachedNtpElapsedRealtime, mCachedNtpTime); + @NonNull + public String getServer() { + return mServer; + } + + int getTimeoutMillis() { + return mTimeoutMillis; + } } + @GuardedBy("this") + private NtpConnectionInfo getNtpConnectionInfo() { + final ContentResolver resolver = mContext.getContentResolver(); + + final Resources res = mContext.getResources(); + final String defaultServer = res.getString( + com.android.internal.R.string.config_ntpServer); + final int defaultTimeoutMillis = res.getInteger( + com.android.internal.R.integer.config_ntpTimeout); + + final String secureServer = Settings.Global.getString( + resolver, Settings.Global.NTP_SERVER); + final int timeoutMillis = Settings.Global.getInt( + resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis); + + final String server = secureServer != null ? secureServer : defaultServer; + return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis); + } } diff --git a/core/java/android/util/TrustedTime.java b/core/java/android/util/TrustedTime.java index 1360f874507f..f41fe85fa8bb 100644 --- a/core/java/android/util/TrustedTime.java +++ b/core/java/android/util/TrustedTime.java @@ -20,42 +20,48 @@ import android.compat.annotation.UnsupportedAppUsage; /** * Interface that provides trusted time information, possibly coming from an NTP - * server. Implementations may cache answers until {@link #forceRefresh()}. + * server. * * @hide + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ public interface TrustedTime { /** * Force update with an external trusted time source, returning {@code true} * when successful. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage public boolean forceRefresh(); /** * Check if this instance has cached a response from a trusted time source. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage - public boolean hasCache(); + boolean hasCache(); /** * Return time since last trusted time source contact, or * {@link Long#MAX_VALUE} if never contacted. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage public long getCacheAge(); /** - * Return certainty of cached trusted time in milliseconds, or - * {@link Long#MAX_VALUE} if never contacted. Smaller values are more - * precise. - */ - public long getCacheCertainty(); - - /** * Return current time similar to {@link System#currentTimeMillis()}, * possibly using a cached authoritative time source. + * + * @deprecated Only kept for UnsupportedAppUsage. Do not use. See {@link NtpTrustedTime} */ + @Deprecated @UnsupportedAppUsage - public long currentTimeMillis(); + long currentTimeMillis(); } diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java index 386c9cb9d14f..860ce90d5fc0 100644 --- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java +++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java @@ -17,6 +17,8 @@ package android.view.inputmethod; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityThread; import android.os.Parcelable; import android.view.inline.InlinePresentationSpec; @@ -49,6 +51,21 @@ public final class InlineSuggestionsRequest implements Parcelable { */ private final @NonNull List<InlinePresentationSpec> mPresentationSpecs; + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + private @NonNull String mHostPackageName; + + /** + * @hide + * @see {@link #mHostPackageName}. + */ + public void setHostPackageName(@NonNull String hostPackageName) { + mHostPackageName = hostPackageName; + } + private void onConstructed() { Preconditions.checkState(mMaxSuggestionCount >= mPresentationSpecs.size()); } @@ -57,9 +74,15 @@ public final class InlineSuggestionsRequest implements Parcelable { return SUGGESTION_COUNT_UNLIMITED; } + private static String defaultHostPackageName() { + return ActivityThread.currentPackageName(); + } + /** @hide */ abstract static class BaseBuilder { abstract Builder setPresentationSpecs(@NonNull List<InlinePresentationSpec> value); + + abstract Builder setHostPackageName(@Nullable String value); } @@ -80,11 +103,15 @@ public final class InlineSuggestionsRequest implements Parcelable { @DataClass.Generated.Member /* package-private */ InlineSuggestionsRequest( int maxSuggestionCount, - @NonNull List<InlinePresentationSpec> presentationSpecs) { + @NonNull List<InlinePresentationSpec> presentationSpecs, + @NonNull String hostPackageName) { this.mMaxSuggestionCount = maxSuggestionCount; this.mPresentationSpecs = presentationSpecs; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpecs); + this.mHostPackageName = hostPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostPackageName); onConstructed(); } @@ -108,6 +135,16 @@ public final class InlineSuggestionsRequest implements Parcelable { return mPresentationSpecs; } + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + @DataClass.Generated.Member + public @NonNull String getHostPackageName() { + return mHostPackageName; + } + @Override @DataClass.Generated.Member public String toString() { @@ -116,13 +153,14 @@ public final class InlineSuggestionsRequest implements Parcelable { return "InlineSuggestionsRequest { " + "maxSuggestionCount = " + mMaxSuggestionCount + ", " + - "presentationSpecs = " + mPresentationSpecs + + "presentationSpecs = " + mPresentationSpecs + ", " + + "hostPackageName = " + mHostPackageName + " }"; } @Override @DataClass.Generated.Member - public boolean equals(@android.annotation.Nullable Object o) { + public boolean equals(@Nullable Object o) { // You can override field equality logic by defining either of the methods like: // boolean fieldNameEquals(InlineSuggestionsRequest other) { ... } // boolean fieldNameEquals(FieldType otherValue) { ... } @@ -134,7 +172,8 @@ public final class InlineSuggestionsRequest implements Parcelable { //noinspection PointlessBooleanExpression return true && mMaxSuggestionCount == that.mMaxSuggestionCount - && java.util.Objects.equals(mPresentationSpecs, that.mPresentationSpecs); + && java.util.Objects.equals(mPresentationSpecs, that.mPresentationSpecs) + && java.util.Objects.equals(mHostPackageName, that.mHostPackageName); } @Override @@ -146,6 +185,7 @@ public final class InlineSuggestionsRequest implements Parcelable { int _hash = 1; _hash = 31 * _hash + mMaxSuggestionCount; _hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpecs); + _hash = 31 * _hash + java.util.Objects.hashCode(mHostPackageName); return _hash; } @@ -157,6 +197,7 @@ public final class InlineSuggestionsRequest implements Parcelable { dest.writeInt(mMaxSuggestionCount); dest.writeParcelableList(mPresentationSpecs, flags); + dest.writeString(mHostPackageName); } @Override @@ -173,11 +214,15 @@ public final class InlineSuggestionsRequest implements Parcelable { int maxSuggestionCount = in.readInt(); List<InlinePresentationSpec> presentationSpecs = new ArrayList<>(); in.readParcelableList(presentationSpecs, InlinePresentationSpec.class.getClassLoader()); + String hostPackageName = in.readString(); this.mMaxSuggestionCount = maxSuggestionCount; this.mPresentationSpecs = presentationSpecs; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpecs); + this.mHostPackageName = hostPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostPackageName); onConstructed(); } @@ -205,6 +250,7 @@ public final class InlineSuggestionsRequest implements Parcelable { private int mMaxSuggestionCount; private @NonNull List<InlinePresentationSpec> mPresentationSpecs; + private @NonNull String mHostPackageName; private long mBuilderFieldsSet = 0L; @@ -260,22 +306,40 @@ public final class InlineSuggestionsRequest implements Parcelable { return this; } + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + @DataClass.Generated.Member + @Override + @NonNull Builder setHostPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mHostPackageName = value; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull InlineSuggestionsRequest build() { checkNotUsed(); - mBuilderFieldsSet |= 0x4; // Mark builder used + mBuilderFieldsSet |= 0x8; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mMaxSuggestionCount = defaultMaxSuggestionCount(); } + if ((mBuilderFieldsSet & 0x4) == 0) { + mHostPackageName = defaultHostPackageName(); + } InlineSuggestionsRequest o = new InlineSuggestionsRequest( mMaxSuggestionCount, - mPresentationSpecs); + mPresentationSpecs, + mHostPackageName); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x4) != 0) { + if ((mBuilderFieldsSet & 0x8) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -283,10 +347,10 @@ public final class InlineSuggestionsRequest implements Parcelable { } @DataClass.Generated( - time = 1576637222199L, + time = 1578948035951L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java", - inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\npublic void setHostPackageName(java.lang.String)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/core/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java index c45a3a4b8b14..2bb3f1fed927 100644 --- a/core/java/com/android/ims/internal/uce/common/CapInfo.java +++ b/core/java/com/android/ims/internal/uce/common/CapInfo.java @@ -64,6 +64,20 @@ public class CapInfo implements Parcelable { private boolean mRcsIpVideoCallSupported = false; /** RCS IP Video call support . */ private boolean mRcsIpVideoOnlyCallSupported = false; + /** IP Geo location Push using SMS. */ + private boolean mGeoSmsSupported = false; + /** RCS call composer support. */ + private boolean mCallComposerSupported = false; + /** RCS post-call support. */ + private boolean mPostCallSupported = false; + /** Shared map support. */ + private boolean mSharedMapSupported = false; + /** Shared Sketch supported. */ + private boolean mSharedSketchSupported = false; + /** Chatbot communication support. */ + private boolean mChatbotSupported = false; + /** Chatbot role support. */ + private boolean mChatbotRoleSupported = false; /** List of supported extensions. */ private String[] mExts = new String[10]; /** Time used to compute when to query again. */ @@ -386,6 +400,104 @@ public class CapInfo implements Parcelable { this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported; } + /** + * Checks whether Geo Push via SMS is supported. + */ + public boolean isGeoSmsSupported() { + return mGeoSmsSupported; + } + + /** + * Sets Geolocation Push via SMS as supported or not supported. + */ + public void setGeoSmsSupported(boolean geoSmsSupported) { + this.mGeoSmsSupported = geoSmsSupported; + } + + /** + * Checks whether RCS call composer is supported. + */ + public boolean isCallComposerSupported() { + return mCallComposerSupported; + } + + /** + * Sets call composer as supported or not supported. + */ + public void setCallComposerSupported(boolean callComposerSupported) { + this.mCallComposerSupported = callComposerSupported; + } + + /** + * Checks whether post call is supported. + */ + public boolean isPostCallSupported(){ + return mPostCallSupported; + } + + /** + * Sets post call as supported or not supported. + */ + public void setPostCallSupported(boolean postCallSupported) { + this.mPostCallSupported = postCallSupported; + } + + /** + * Checks whether shared map is supported. + */ + public boolean isSharedMapSupported() { + return mSharedMapSupported; + } + + /** + * Sets shared map as supported or not supported. + */ + public void setSharedMapSupported(boolean sharedMapSupported) { + this.mSharedMapSupported = sharedMapSupported; + } + + /** + * Checks whether shared sketch is supported. + */ + public boolean isSharedSketchSupported() { + return mSharedSketchSupported; + } + + /** + * Sets shared sketch as supported or not supported. + */ + public void setSharedSketchSupported(boolean sharedSketchSupported) { + this.mSharedSketchSupported = sharedSketchSupported; + } + + /** + * Checks whether chatbot communication is supported. + */ + public boolean isChatbotSupported() { + return mChatbotSupported; + } + + /** + * Sets chatbot communication as supported or not supported. + */ + public void setChatbotSupported(boolean chatbotSupported) { + this.mChatbotSupported = chatbotSupported; + } + + /** + * Checks whether chatbot role is supported. + */ + public boolean isChatbotRoleSupported() { + return mChatbotRoleSupported; + } + + /** + * Sets chatbot role as supported or not supported. + */ + public void setChatbotRoleSupported(boolean chatbotRoleSupported) { + this.mChatbotRoleSupported = chatbotRoleSupported; + } + /** Gets the list of supported extensions. */ public String[] getExts() { return mExts; @@ -434,6 +546,13 @@ public class CapInfo implements Parcelable { dest.writeInt(mGeoPushSupported ? 1 : 0); dest.writeInt(mSmSupported ? 1 : 0); dest.writeInt(mFullSnFGroupChatSupported ? 1 : 0); + dest.writeInt(mGeoSmsSupported ? 1 : 0); + dest.writeInt(mCallComposerSupported ? 1 : 0); + dest.writeInt(mPostCallSupported ? 1 : 0); + dest.writeInt(mSharedMapSupported ? 1 : 0); + dest.writeInt(mSharedSketchSupported ? 1 : 0); + dest.writeInt(mChatbotSupported ? 1 : 0); + dest.writeInt(mChatbotRoleSupported ? 1 : 0); dest.writeInt(mRcsIpVoiceCallSupported ? 1 : 0); dest.writeInt(mRcsIpVideoCallSupported ? 1 : 0); @@ -476,6 +595,13 @@ public class CapInfo implements Parcelable { mGeoPushSupported = (source.readInt() == 0) ? false : true; mSmSupported = (source.readInt() == 0) ? false : true; mFullSnFGroupChatSupported = (source.readInt() == 0) ? false : true; + mGeoSmsSupported = (source.readInt() == 0) ? false : true; + mCallComposerSupported = (source.readInt() == 0) ? false : true; + mPostCallSupported = (source.readInt() == 0) ? false : true; + mSharedMapSupported = (source.readInt() == 0) ? false : true; + mSharedSketchSupported = (source.readInt() == 0) ? false : true; + mChatbotSupported = (source.readInt() == 0) ? false : true; + mChatbotRoleSupported = (source.readInt() == 0) ? false : true; mRcsIpVoiceCallSupported = (source.readInt() == 0) ? false : true; mRcsIpVideoCallSupported = (source.readInt() == 0) ? false : true; diff --git a/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java index a50a22f68fa0..fdff86f9669f 100644 --- a/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java +++ b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java @@ -47,6 +47,10 @@ public class PresPublishTriggerType implements Parcelable { public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN = 8; /** Trigger is unknown. */ public static final int UCE_PRES_PUBLISH_TRIGGER_UNKNOWN = 9; + /** Move to 5G NR with VoPS disabled. */ + public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; + /** Move to 5G NR with VoPS enabled. */ + public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; @@ -113,4 +117,4 @@ public class PresPublishTriggerType implements Parcelable { public void readFromParcel(Parcel source) { mPublishTriggerType = source.readInt(); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 9e23c28a0711..9fbc1b74c9ae 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -350,7 +350,12 @@ public final class SystemUiDeviceConfigFlags { * (boolean) Whether screenshot flow going to the corner (instead of shown in a notification) * is enabled. */ - public static final String SCREENSHOT_CORNER_FLOW = "screenshot_corner_flow"; + public static final String SCREENSHOT_CORNER_FLOW = "enable_screenshot_corner_flow"; + + /** + * (boolean) Whether scrolling screenshots are enabled. + */ + public static final String SCREENSHOT_SCROLLING_ENABLED = "enable_screenshot_scrolling"; private SystemUiDeviceConfigFlags() { } diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/ConnectivityUtil.java new file mode 100644 index 000000000000..799352b9ec15 --- /dev/null +++ b/core/java/com/android/internal/util/ConnectivityUtil.java @@ -0,0 +1,201 @@ +/* + * 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.internal.util; + +import android.Manifest; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + + +/** + * Utility methods for common functionality using by different networks. + * + * @hide + */ +public class ConnectivityUtil { + + private static final String TAG = "ConnectivityUtil"; + + private final Context mContext; + private final AppOpsManager mAppOps; + private final UserManager mUserManager; + + public ConnectivityUtil(Context context) { + mContext = context; + mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + + /** + * API to determine if the caller has fine/coarse location permission (depending on + * config/targetSDK level) and the location mode is enabled for the user. SecurityException is + * thrown if the caller has no permission or the location mode is disabled. + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid, + @Nullable String message) + throws SecurityException { + checkPackage(uid, pkgName); + + // Location mode must be enabled + if (!isLocationModeEnabled()) { + // Location mode is disabled, scan results cannot be returned + throw new SecurityException("Location mode is disabled for the device"); + } + + // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to + // location information. + boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, + uid, /* coarseForTargetSdkLessThanQ */ true, message); + + // If neither caller or app has location access, there is no need to check + // any other permissions. Deny access to scan results. + if (!canAppPackageUseLocation) { + throw new SecurityException("UID " + uid + " has no location permission"); + } + // If the User or profile is current, permission is granted + // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. + if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) { + throw new SecurityException("UID " + uid + " profile not permitted"); + } + } + + /** + * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or + * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level) + * and a corresponding app op is allowed for this package and uid. + * + * @param pkgName PackageName of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE + * else (false or targetSDK >= Q) then will check for FINE + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, + int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { + boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); + + String permissionType = Manifest.permission.ACCESS_FINE_LOCATION; + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + // Having FINE permission implies having COARSE permission (but not the reverse) + permissionType = Manifest.permission.ACCESS_COARSE_LOCATION; + } + if (getUidPermission(permissionType, uid) + == PackageManager.PERMISSION_DENIED) { + return false; + } + + // Always checking FINE - even if will not enforce. This will record the request for FINE + // so that a location request by the app is surfaced to the user. + boolean isFineLocationAllowed = noteAppOpAllowed( + AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); + if (isFineLocationAllowed) { + return true; + } + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid, + message); + } + return false; + } + + /** + * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. + */ + public boolean isLocationModeEnabled() { + LocationManager locationManager = + (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + try { + return locationManager.isLocationEnabledForUser(UserHandle.of( + getCurrentUser())); + } catch (Exception e) { + Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); + return false; + } + } + + private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { + long ident = Binder.clearCallingIdentity(); + try { + if (mContext.getPackageManager().getApplicationInfoAsUser( + packageName, 0, + UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion + < versionCode) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + // In case of exception, assume unknown app (more strict checking) + // Note: This case will never happen since checkPackage is + // called to verify validity before checking App's version. + } finally { + Binder.restoreCallingIdentity(ident); + } + return false; + } + + private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED; + } + + private void checkPackage(int uid, String pkgName) throws SecurityException { + if (pkgName == null) { + throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); + } + mAppOps.checkPackage(uid, pkgName); + } + + private boolean isCurrentProfile(int uid) { + UserHandle currentUser = UserHandle.of(getCurrentUser()); + UserHandle callingUser = UserHandle.getUserHandleForUid(uid); + return currentUser.equals(callingUser) + || mUserManager.isSameProfileGroup(currentUser, callingUser); + } + + private boolean checkInteractAcrossUsersFull(int uid) { + return getUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) + == PackageManager.PERMISSION_GRANTED; + } + + @VisibleForTesting + protected int getCurrentUser() { + return ActivityManager.getCurrentUser(); + } + + private int getUidPermission(String permissionType, int uid) { + // We don't care about pid, pass in -1 + return mContext.checkPermission(permissionType, -1, uid); + } +} diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java index 43a227a32346..d7a01c4762f1 100644 --- a/core/java/com/android/internal/widget/RecyclerView.java +++ b/core/java/com/android/internal/widget/RecyclerView.java @@ -2011,13 +2011,27 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro } if (!dispatchNestedPreFling(velocityX, velocityY)) { - final boolean canScroll = canScrollHorizontal || canScrollVertical; - dispatchNestedFling(velocityX, velocityY, canScroll); + final View firstChild = mLayout.getChildAt(0); + final View lastChild = mLayout.getChildAt(mLayout.getChildCount() - 1); + boolean consumed = false; + if (velocityY < 0) { + consumed = getChildAdapterPosition(firstChild) > 0 + || firstChild.getTop() < getPaddingTop(); + } + + if (velocityY > 0) { + consumed = getChildAdapterPosition(lastChild) < mAdapter.getItemCount() - 1 + || lastChild.getBottom() > getHeight() - getPaddingBottom(); + } + + dispatchNestedFling(velocityX, velocityY, consumed); if (mOnFlingListener != null && mOnFlingListener.onFling(velocityX, velocityY)) { return true; } + final boolean canScroll = canScrollHorizontal || canScrollVertical; + if (canScroll) { velocityX = Math.max(-mMaxFlingVelocity, Math.min(velocityX, mMaxFlingVelocity)); velocityY = Math.max(-mMaxFlingVelocity, Math.min(velocityY, mMaxFlingVelocity)); diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 0992bebb5be0..fb8e633fec12 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -537,9 +537,9 @@ public: LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this); if (mObject != NULL) { JNIEnv* env = javavm_to_jnienv(mVM); - + jobject jBinderProxy = javaObjectForIBinder(env, who.promote()); env->CallStaticVoidMethod(gBinderProxyOffsets.mClass, - gBinderProxyOffsets.mSendDeathNotice, mObject); + gBinderProxyOffsets.mSendDeathNotice, mObject, jBinderProxy); if (env->ExceptionCheck()) { jthrowable excep = env->ExceptionOccurred(); report_exception(env, excep, @@ -1532,8 +1532,9 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz); gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance", "(JJ)Landroid/os/BinderProxy;"); - gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice", - "(Landroid/os/IBinder$DeathRecipient;)V"); + gBinderProxyOffsets.mSendDeathNotice = + GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice", + "(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V"); gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J"); clazz = FindClassOrDie(env, "java/lang/Class"); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 4a7276c4f94e..b47080f787a1 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -263,7 +263,8 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz, status_t res = ScreenshotClient::capture(displayToken, dataspace, ui::PixelFormat::RGBA_8888, sourceCrop, width, height, - useIdentityTransform, rotation, captureSecureLayers, &buffer, capturedSecureLayers); + useIdentityTransform, ui::toRotation(rotation), + captureSecureLayers, &buffer, capturedSecureLayers); if (res != NO_ERROR) { return NULL; } @@ -724,7 +725,8 @@ static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz, { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - transaction->setDisplayProjection(token, orientation, layerStackRect, displayRect); + transaction->setDisplayProjection(token, static_cast<ui::Rotation>(orientation), + layerStackRect, displayRect); } } diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index 9054d5462da5..0fca1d19c0e5 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -154,4 +154,5 @@ enum EventId { SET_AUTO_TIME = 127; SET_AUTO_TIME_ZONE = 128; SET_PACKAGES_PROTECTED = 129; + SET_FACTORY_RESET_PROTECTION = 130; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 0e4cea1e784d..b78b18192f45 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -445,6 +445,7 @@ <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" /> <protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" /> + <protected-broadcast android:name="android.app.action.RESET_PROTECTION_POLICY_CHANGED" /> <protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" /> <protected-broadcast android:name="android.app.action.MANAGED_USER_CREATED" /> @@ -3385,6 +3386,14 @@ <permission android:name="android.permission.NOTIFY_TV_INPUTS" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an application to interact with tuner resources through + Tuner Resource Manager. + <p>Protection level: signature|privileged + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.TUNER_RESOURCE_ACCESS" + android:protectionLevel="signature|privileged" /> + <!-- Must be required by a {@link android.media.routing.MediaRouteService} to ensure that only the system can interact with it. @hide --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 6691d4c5955b..6f554f0264df 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1877,6 +1877,8 @@ <string name="config_defaultCallRedirection" translatable="false"></string> <!-- The name of the package that will hold the call screening role by default. --> <string name="config_defaultCallScreening" translatable="false"></string> + <!-- The name of the package that will hold the system gallery role. --> + <string name="config_systemGallery" translatable="false">com.android.gallery</string> <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 37c971021b2e..6cf6a6828237 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3030,6 +3030,8 @@ <public name="config_defaultCallRedirection" /> <!-- @hide @SystemApi --> <public name="config_defaultCallScreening" /> + <!-- @hide @SystemApi @TestApi --> + <public name="config_systemGallery" /> </public-group> <public-group type="bool" first-id="0x01110005"> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index caae9088e9b5..2df6d1ca0e2d 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -8,6 +8,7 @@ android_test { "EnabledTestApp/src/**/*.java", "BinderProxyCountingTestApp/src/**/*.java", "BinderProxyCountingTestService/src/**/*.java", + "BinderDeathRecipientHelperApp/src/**/*.java", "aidl/**/I*.aidl", ], @@ -59,7 +60,11 @@ android_test { resource_dirs: ["res"], resource_zips: [":FrameworksCoreTests_apks_as_resources"], - data: [":BstatsTestApp"], + data: [ + ":BstatsTestApp", + ":BinderDeathRecipientHelperApp1", + ":BinderDeathRecipientHelperApp2", + ], } // Rules to copy all the test apks to the intermediate raw resource directory diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 1aea98a93afe..b85a332e9000 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -95,6 +95,7 @@ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> <uses-permission android:name="android.permission.KILL_UID" /> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" /> <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml index b40aa87cb78b..ed9d3f54ef3d 100644 --- a/core/tests/coretests/AndroidTest.xml +++ b/core/tests/coretests/AndroidTest.xml @@ -21,6 +21,8 @@ <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksCoreTests.apk" /> <option name="test-file-name" value="BstatsTestApp.apk" /> + <option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" /> + <option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" /> </target_preparer> <option name="test-tag" value="FrameworksCoreTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp b/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp new file mode 100644 index 000000000000..25e4fc366124 --- /dev/null +++ b/core/tests/coretests/BinderDeathRecipientHelperApp/Android.bp @@ -0,0 +1,19 @@ +android_test_helper_app { + name: "BinderDeathRecipientHelperApp1", + + srcs: ["**/*.java"], + + sdk_version: "current", +} + +android_test_helper_app { + name: "BinderDeathRecipientHelperApp2", + + srcs: ["**/*.java"], + + sdk_version: "current", + + aaptflags: [ + "--rename-manifest-package com.android.frameworks.coretests.bdr_helper_app2", + ], +} diff --git a/core/tests/coretests/BinderDeathRecipientHelperApp/AndroidManifest.xml b/core/tests/coretests/BinderDeathRecipientHelperApp/AndroidManifest.xml new file mode 100644 index 000000000000..dbd1774b7d79 --- /dev/null +++ b/core/tests/coretests/BinderDeathRecipientHelperApp/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.coretests.bdr_helper_app1"> + + <application> + <receiver android:name="com.android.frameworks.coretests.bdr_helper_app.TestCommsReceiver" + android:exported="true"/> + + </application> +</manifest> diff --git a/core/tests/coretests/BinderDeathRecipientHelperApp/src/com/android/frameworks/coretests/bdr_helper_app/TestCommsReceiver.java b/core/tests/coretests/BinderDeathRecipientHelperApp/src/com/android/frameworks/coretests/bdr_helper_app/TestCommsReceiver.java new file mode 100644 index 000000000000..ab79e69d1351 --- /dev/null +++ b/core/tests/coretests/BinderDeathRecipientHelperApp/src/com/android/frameworks/coretests/bdr_helper_app/TestCommsReceiver.java @@ -0,0 +1,51 @@ +/* + * 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.frameworks.coretests.bdr_helper_app; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.util.Log; + +/** + * Receiver used to hand off a binder owned by this process to + * {@link android.os.BinderDeathRecipientTest}. + */ +public class TestCommsReceiver extends BroadcastReceiver { + private static final String TAG = TestCommsReceiver.class.getSimpleName(); + private static final String PACKAGE_NAME = "com.android.frameworks.coretests.bdr_helper_app"; + + public static final String ACTION_GET_BINDER = PACKAGE_NAME + ".action.GET_BINDER"; + public static final String EXTRA_KEY_BINDER = PACKAGE_NAME + ".EXTRA_BINDER"; + + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case ACTION_GET_BINDER: + final Bundle resultExtras = new Bundle(); + resultExtras.putBinder(EXTRA_KEY_BINDER, new Binder()); + setResult(Activity.RESULT_OK, null, resultExtras); + break; + default: + Log.e(TAG, "Unknown action " + intent.getAction()); + break; + } + } +} diff --git a/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java b/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java new file mode 100644 index 000000000000..2cce43f70774 --- /dev/null +++ b/core/tests/coretests/src/android/os/BinderDeathRecipientTest.java @@ -0,0 +1,162 @@ +/* + * 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 android.os; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.ArraySet; +import android.util.Log; +import android.util.Pair; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.frameworks.coretests.bdr_helper_app.TestCommsReceiver; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Set; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Tests functionality of {@link android.os.IBinder.DeathRecipient} callbacks. + */ +@RunWith(AndroidJUnit4.class) +public class BinderDeathRecipientTest { + private static final String TAG = BinderDeathRecipientTest.class.getSimpleName(); + private static final String TEST_PACKAGE_NAME_1 = + "com.android.frameworks.coretests.bdr_helper_app1"; + private static final String TEST_PACKAGE_NAME_2 = + "com.android.frameworks.coretests.bdr_helper_app2"; + + private Context mContext; + private Handler mHandler; + private ActivityManager mActivityManager; + private Set<Pair<IBinder, IBinder.DeathRecipient>> mLinkedDeathRecipients = new ArraySet<>(); + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getTargetContext(); + mActivityManager = mContext.getSystemService(ActivityManager.class); + mHandler = new Handler(Looper.getMainLooper()); + } + + private IBinder getNewRemoteBinder(String testPackage) throws InterruptedException { + final CountDownLatch resultLatch = new CountDownLatch(1); + final AtomicInteger resultCode = new AtomicInteger(Activity.RESULT_CANCELED); + final AtomicReference<Bundle> resultExtras = new AtomicReference<>(); + + final Intent intent = new Intent(TestCommsReceiver.ACTION_GET_BINDER) + .setClassName(testPackage, TestCommsReceiver.class.getName()); + mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + resultCode.set(getResultCode()); + resultExtras.set(getResultExtras(true)); + resultLatch.countDown(); + } + }, mHandler, Activity.RESULT_CANCELED, null, null); + + assertTrue("Request for binder timed out", resultLatch.await(5, TimeUnit.SECONDS)); + assertEquals(Activity.RESULT_OK, resultCode.get()); + return resultExtras.get().getBinder(TestCommsReceiver.EXTRA_KEY_BINDER); + } + + @Test + public void binderDied_noArgs() throws Exception { + final IBinder testAppBinder = getNewRemoteBinder(TEST_PACKAGE_NAME_1); + final CountDownLatch deathNotificationLatch = new CountDownLatch(1); + final IBinder.DeathRecipient simpleDeathRecipient = + () -> deathNotificationLatch.countDown(); + testAppBinder.linkToDeath(simpleDeathRecipient, 0); + mLinkedDeathRecipients.add(Pair.create(testAppBinder, simpleDeathRecipient)); + + mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_1); + assertTrue("Death notification did not arrive", + deathNotificationLatch.await(10, TimeUnit.SECONDS)); + } + + @Test + public void binderDied_iBinderArg() throws Exception { + final IBinder testApp1Binder = getNewRemoteBinder(TEST_PACKAGE_NAME_1); + final IBinder testApp2Binder = getNewRemoteBinder(TEST_PACKAGE_NAME_2); + final CyclicBarrier barrier = new CyclicBarrier(2); + + final AtomicReference<IBinder> binderThatDied = new AtomicReference<>(); + final IBinder.DeathRecipient sameDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.e(TAG, "Should not have been called!"); + } + + @Override + public void binderDied(IBinder who) { + binderThatDied.set(who); + try { + barrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + Log.e(TAG, "Unexpected exception while waiting on CyclicBarrier", e); + } + } + }; + testApp1Binder.linkToDeath(sameDeathRecipient, 0); + mLinkedDeathRecipients.add(Pair.create(testApp1Binder, sameDeathRecipient)); + + testApp2Binder.linkToDeath(sameDeathRecipient, 0); + mLinkedDeathRecipients.add(Pair.create(testApp2Binder, sameDeathRecipient)); + + mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_1); + try { + barrier.await(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + fail("Timed out while waiting for 1st death notification: " + e.getMessage()); + } + assertEquals("Different binder received", testApp1Binder, binderThatDied.get()); + + barrier.reset(); + mActivityManager.forceStopPackage(TEST_PACKAGE_NAME_2); + try { + barrier.await(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + fail("Timed out while waiting for 2nd death notification: " + e.getMessage()); + } + assertEquals("Different binder received", testApp2Binder, binderThatDied.get()); + } + + @After + public void tearDown() { + for (Pair<IBinder, IBinder.DeathRecipient> linkedPair : mLinkedDeathRecipients) { + linkedPair.first.unlinkToDeath(linkedPair.second, 0); + } + } +} diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java index b4116681e723..aa55e08dbcdc 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java @@ -19,7 +19,6 @@ package android.widget; import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemDisabled; import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemEnabled; import static android.widget.espresso.ContextMenuUtils.assertContextMenuIsNotDisplayed; -import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles; import static android.widget.espresso.DragHandleUtils.onHandleView; import static android.widget.espresso.TextViewActions.mouseClick; import static android.widget.espresso.TextViewActions.mouseClickOnTextAtIndex; @@ -64,7 +63,6 @@ import org.junit.runner.RunWith; */ @RunWith(AndroidJUnit4.class) @MediumTest -@Suppress // Consistently failing. b/29591177 public class TextViewActivityMouseTest { @Rule @@ -86,11 +84,8 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).perform(mouseClick()); onView(withId(R.id.textview)).perform(replaceText(helloWorld)); - assertNoSelectionHandles(); - onView(withId(R.id.textview)).perform( mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!"))); - onView(withId(R.id.textview)).check(hasSelection("llo wor")); onHandleView(com.android.internal.R.id.selection_start_handle) @@ -100,8 +95,6 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).perform(mouseClickOnTextAtIndex(helloWorld.indexOf("w"))); onView(withId(R.id.textview)).check(hasSelection("")); - - assertNoSelectionHandles(); } @Test @@ -196,11 +189,11 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).check(matches(withText("abc ghi.def"))); onView(withId(R.id.textview)).check(hasSelection("")); - assertNoSelectionHandles(); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length())); } @Test + @Suppress // Consistently failing. b/29591177 public void testDragAndDrop_longClick() { final String text = "abc def ghi."; onView(withId(R.id.textview)).perform(mouseClick()); @@ -213,7 +206,6 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).check(matches(withText("abc ghi.def"))); onView(withId(R.id.textview)).check(hasSelection("")); - assertNoSelectionHandles(); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length())); } diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java index abee7369414b..1928d2587f70 100644 --- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java +++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java @@ -70,6 +70,8 @@ public final class MouseUiController implements UiController { event.setSource(InputDevice.SOURCE_MOUSE); if (event.getActionMasked() != MotionEvent.ACTION_UP) { event.setButtonState(mButton); + } else { + event.setButtonState(0); } return mUiController.injectMotionEvent(event); } diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java new file mode 100644 index 000000000000..0809f693ddd5 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java @@ -0,0 +1,287 @@ +/* + * 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.internal.util; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; + +/** Unit tests for {@link ConnectivityUtil}. */ +public class ConnectivityUtilTest { + + public static final String TAG = "ConnectivityUtilTest"; + + // Mock objects for testing + @Mock private Context mMockContext; + @Mock private PackageManager mMockPkgMgr; + @Mock private ApplicationInfo mMockApplInfo; + @Mock private AppOpsManager mMockAppOps; + @Mock private UserManager mMockUserManager; + @Mock private LocationManager mLocationManager; + + private static final String TEST_PKG_NAME = "com.google.somePackage"; + private static final String TEST_FEATURE_ID = "com.google.someFeature"; + private static final int MANAGED_PROFILE_UID = 1100000; + private static final int OTHER_USER_UID = 1200000; + + private final String mInteractAcrossUsersFullPermission = + "android.permission.INTERACT_ACROSS_USERS_FULL"; + private final String mManifestStringCoarse = + Manifest.permission.ACCESS_COARSE_LOCATION; + private final String mManifestStringFine = + Manifest.permission.ACCESS_FINE_LOCATION; + + // Test variables + private int mWifiScanAllowApps; + private int mUid; + private int mCoarseLocationPermission; + private int mAllowCoarseLocationApps; + private int mFineLocationPermission; + private int mAllowFineLocationApps; + private int mCurrentUser; + private boolean mIsLocationEnabled; + private boolean mThrowSecurityException; + private Answer<Integer> mReturnPermission; + private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>(); + + private class TestConnectivityUtil extends ConnectivityUtil { + + TestConnectivityUtil(Context context) { + super(context); + } + + @Override + protected int getCurrentUser() { + return mCurrentUser; + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + initTestVars(); + } + + private void setupMocks() throws Exception { + when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any())) + .thenReturn(mMockApplInfo); + when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr); + when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME, + TEST_FEATURE_ID, null)).thenReturn(mWifiScanAllowApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) + .thenReturn(mAllowCoarseLocationApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) + .thenReturn(mAllowFineLocationApps); + if (mThrowSecurityException) { + doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong" + + " to application bound to user " + mUid)) + .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME); + } + when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)) + .thenReturn(mMockAppOps); + when(mMockContext.getSystemService(Context.USER_SERVICE)) + .thenReturn(mMockUserManager); + when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + } + + private void setupTestCase() throws Exception { + setupMocks(); + setupMockInterface(); + } + + private void initTestVars() { + mPermissionsList.clear(); + mReturnPermission = createPermissionAnswer(); + mWifiScanAllowApps = AppOpsManager.MODE_ERRORED; + mUid = OTHER_USER_UID; + mThrowSecurityException = true; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M; + mIsLocationEnabled = false; + mCurrentUser = UserHandle.USER_SYSTEM; + mCoarseLocationPermission = PackageManager.PERMISSION_DENIED; + mFineLocationPermission = PackageManager.PERMISSION_DENIED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + } + + private void setupMockInterface() { + Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid()); + doAnswer(mReturnPermission).when(mMockContext).checkPermission( + anyString(), anyInt(), anyInt()); + when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM, + UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID))) + .thenReturn(true); + when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid)) + .thenReturn(mCoarseLocationPermission); + when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) + .thenReturn(mFineLocationPermission); + when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); + } + + private Answer<Integer> createPermissionAnswer() { + return new Answer<Integer>() { + @Override + public Integer answer(InvocationOnMock invocation) { + int myUid = (int) invocation.getArguments()[1]; + String myPermission = (String) invocation.getArguments()[0]; + mPermissionsList.get(myPermission); + if (mPermissionsList.containsKey(myPermission)) { + int uid = mPermissionsList.get(myPermission); + if (myUid == uid) { + return PackageManager.PERMISSION_GRANTED; + } + } + return PackageManager.PERMISSION_DENIED; + } + }; + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mUid = mCurrentUser; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception { + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mThrowSecurityException = false; + mUid = mCurrentUser; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception { + mThrowSecurityException = true; + mIsLocationEnabled = true; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = true; + setupTestCase(); + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception { + mThrowSecurityException = false; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mUid = MANAGED_PROFILE_UID; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString()); + } + + @Test + public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception { + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); + mIsLocationEnabled = false; + + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { + try { + r.run(); + Assert.fail("Expected " + exceptionClass + " to be thrown."); + } catch (Exception exception) { + assertTrue(exceptionClass.isInstance(exception)); + } + } +} diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp index 0a54aca4970d..e075d806126b 100644 --- a/libs/hwui/tests/common/TestContext.cpp +++ b/libs/hwui/tests/common/TestContext.cpp @@ -25,16 +25,16 @@ namespace test { static const int IDENT_DISPLAYEVENT = 1; static android::DisplayInfo DUMMY_DISPLAY{ - 1080, // w - 1920, // h - 320.0, // xdpi - 320.0, // ydpi - 60.0, // fps - 2.0, // density - 0, // orientation - false, // secure? - 0, // appVsyncOffset - 0, // presentationDeadline + 1080, // w + 1920, // h + 320.0, // xdpi + 320.0, // ydpi + 60.0, // fps + 2.0, // density + ui::ROTATION_0, // orientation + false, // secure? + 0, // appVsyncOffset + 0, // presentationDeadline }; DisplayInfo getInternalDisplay() { diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index 938ffcd5f731..dd4dac223a86 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -44,6 +44,7 @@ import com.android.internal.app.ISoundTriggerService; import com.android.internal.util.Preconditions; import java.util.HashMap; +import java.util.Objects; import java.util.UUID; /** @@ -175,19 +176,40 @@ public final class SoundTriggerManager { * Factory constructor to create a SoundModel instance for use with methods in this * class. */ - public static Model create(UUID modelUuid, UUID vendorUuid, byte[] data) { - return new Model(new SoundTrigger.GenericSoundModel(modelUuid, - vendorUuid, data)); + @NonNull + public static Model create(@NonNull UUID modelUuid, @NonNull UUID vendorUuid, + @Nullable byte[] data, int version) { + Objects.requireNonNull(modelUuid); + Objects.requireNonNull(vendorUuid); + return new Model(new SoundTrigger.GenericSoundModel(modelUuid, vendorUuid, data, + version)); } + /** + * Factory constructor to create a SoundModel instance for use with methods in this + * class. + */ + @NonNull + public static Model create(@NonNull UUID modelUuid, @NonNull UUID vendorUuid, + @Nullable byte[] data) { + return create(modelUuid, vendorUuid, data, -1); + } + + @NonNull public UUID getModelUuid() { return mGenericSoundModel.uuid; } + @NonNull public UUID getVendorUuid() { return mGenericSoundModel.vendorUuid; } + public int getVersion() { + return mGenericSoundModel.version; + } + + @Nullable public byte[] getModelData() { return mGenericSoundModel.data; } diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index b076bb67738f..b5e9d1b2939f 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -60,6 +60,7 @@ interface ITvInputManager { void createSession(in ITvInputClient client, in String inputId, boolean isRecordingSession, int seq, int userId); void releaseSession(in IBinder sessionToken, int userId); + int getClientPid(in String sessionId); void setMainSession(in IBinder sessionToken, int userId); void setSurface(in IBinder sessionToken, in Surface surface, int userId); diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl index f90c50491129..8ccf13ae2d72 100755 --- a/media/java/android/media/tv/ITvInputService.aidl +++ b/media/java/android/media/tv/ITvInputService.aidl @@ -30,8 +30,9 @@ oneway interface ITvInputService { void registerCallback(in ITvInputServiceCallback callback); void unregisterCallback(in ITvInputServiceCallback callback); void createSession(in InputChannel channel, in ITvInputSessionCallback callback, - in String inputId); - void createRecordingSession(in ITvInputSessionCallback callback, in String inputId); + in String inputId, in String sessionId); + void createRecordingSession(in ITvInputSessionCallback callback, in String inputId, + in String sessionId); // For hardware TvInputService void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 854ea43f17c3..630d8191eff0 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -266,6 +266,15 @@ public final class TvInputManager { public static final int INPUT_STATE_DISCONNECTED = 2; /** + * An unknown state of the client pid gets from the TvInputManager. Client gets this value when + * query through {@link getClientPid(String sessionId)} fails. + * + * @hide + */ + @SystemApi + public static final int UNKNOWN_CLIENT_PID = -1; + + /** * Broadcast intent action when the user blocked content ratings change. For use with the * {@link #isRatingBlocked}. */ @@ -1484,6 +1493,21 @@ public final class TvInputManager { } /** + * Get a the client pid when creating the session with the session id provided. + * + * @param sessionId a String of session id that is used to query the client pid. + * @return the client pid when created the session. Returns {@link #UNKNOWN_CLIENT_PID} + * if the call fails. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) + public int getClientPid(@NonNull String sessionId) { + return getClientPidInternal(sessionId); + }; + + /** * Creates a recording {@link Session} for a given TV input. * * <p>The number of sessions that can be created at the same time is limited by the capability @@ -1516,6 +1540,17 @@ public final class TvInputManager { } } + private int getClientPidInternal(String sessionId) { + Preconditions.checkNotNull(sessionId); + int clientPid = UNKNOWN_CLIENT_PID; + try { + clientPid = mService.getClientPid(sessionId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return clientPid; + } + /** * Returns the TvStreamConfig list of the given TV input. * diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 7fbb3376d5fb..629dc7ce7819 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -124,7 +124,7 @@ public abstract class TvInputService extends Service { @Override public void createSession(InputChannel channel, ITvInputSessionCallback cb, - String inputId) { + String inputId, String sessionId) { if (channel == null) { Log.w(TAG, "Creating session without input channel"); } @@ -135,17 +135,20 @@ public abstract class TvInputService extends Service { args.arg1 = channel; args.arg2 = cb; args.arg3 = inputId; + args.arg4 = sessionId; mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget(); } @Override - public void createRecordingSession(ITvInputSessionCallback cb, String inputId) { + public void createRecordingSession(ITvInputSessionCallback cb, String inputId, + String sessionId) { if (cb == null) { return; } SomeArgs args = SomeArgs.obtain(); args.arg1 = cb; args.arg2 = inputId; + args.arg3 = sessionId; mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_RECORDING_SESSION, args) .sendToTarget(); } @@ -208,6 +211,37 @@ public abstract class TvInputService extends Service { } /** + * Returns a concrete implementation of {@link Session}. + * + * <p>For any apps that needs sessionId to request tuner resources from TunerResourceManager, + * it needs to override this method to get the sessionId passed. When no overriding, this method + * calls {@link #onCreateSession(String)} defaultly. + * + * @param inputId The ID of the TV input associated with the session. + * @param sessionId the unique sessionId created by TIF when session is created. + */ + @Nullable + public Session onCreateSession(@NonNull String inputId, @NonNull String sessionId) { + return onCreateSession(inputId); + } + + /** + * Returns a concrete implementation of {@link RecordingSession}. + * + * <p>For any apps that needs sessionId to request tuner resources from TunerResourceManager, + * it needs to override this method to get the sessionId passed. When no overriding, this method + * calls {@link #onCreateRecordingSession(String)} defaultly. + * + * @param inputId The ID of the TV input associated with the recording session. + * @param sessionId the unique sessionId created by TIF when session is created. + */ + @Nullable + public RecordingSession onCreateRecordingSession( + @NonNull String inputId, @NonNull String sessionId) { + return onCreateRecordingSession(inputId); + } + + /** * Returns a new {@link TvInputInfo} object if this service is responsible for * {@code hardwareInfo}; otherwise, return {@code null}. Override to modify default behavior of * ignoring all hardware input. @@ -2032,8 +2066,9 @@ public abstract class TvInputService extends Service { InputChannel channel = (InputChannel) args.arg1; ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2; String inputId = (String) args.arg3; + String sessionId = (String) args.arg4; args.recycle(); - Session sessionImpl = onCreateSession(inputId); + Session sessionImpl = onCreateSession(inputId, sessionId); if (sessionImpl == null) { try { // Failed to create a session. @@ -2103,8 +2138,10 @@ public abstract class TvInputService extends Service { SomeArgs args = (SomeArgs) msg.obj; ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg1; String inputId = (String) args.arg2; + String sessionId = (String) args.arg3; args.recycle(); - RecordingSession recordingSessionImpl = onCreateRecordingSession(inputId); + RecordingSession recordingSessionImpl = + onCreateRecordingSession(inputId, sessionId); if (recordingSessionImpl == null) { try { // Failed to create a recording session. diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 862489f4ed8d..e3dfaeb10948 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -16,6 +16,7 @@ package android.media.tv.tuner; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -32,11 +33,13 @@ import android.media.tv.tuner.filter.TimeFilter; import android.media.tv.tuner.frontend.FrontendCallback; import android.media.tv.tuner.frontend.FrontendInfo; import android.media.tv.tuner.frontend.FrontendStatus; +import android.media.tv.tuner.frontend.ScanCallback; import android.os.Handler; import android.os.Looper; import android.os.Message; import java.util.List; +import java.util.concurrent.Executor; /** * This class is used to interact with hardware tuners devices. @@ -70,6 +73,10 @@ public final class Tuner implements AutoCloseable { private List<Integer> mLnbIds; private Lnb mLnb; + @Nullable + private ScanCallback mScanCallback; + @Nullable + private Executor mScanCallbackExecutor; /** * Constructs a Tuner instance. @@ -231,29 +238,6 @@ public final class Tuner implements AutoCloseable { private Frontend(int id) { mId = id; } - - public void setCallback(@Nullable FrontendCallback callback, @Nullable Handler handler) { - mCallback = callback; - - if (mCallback == null) { - return; - } - - if (handler == null) { - // use default looper if handler is null - if (mHandler == null) { - mHandler = createEventHandler(); - } - return; - } - - Looper looper = handler.getLooper(); - if (mHandler != null && mHandler.getLooper() == looper) { - // the same looper. reuse mHandler - return; - } - mHandler = new EventHandler(looper); - } } /** @@ -286,18 +270,32 @@ public final class Tuner implements AutoCloseable { * Scan channels. * @hide */ - public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType) { + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType, + @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { + mScanCallback = scanCallback; + mScanCallbackExecutor = executor; return nativeScan(settings.getType(), settings, scanType); } /** * Stops a previous scanning. * - * If the method completes successfully, the frontend stop previous scanning. + * <p> + * The {@link ScanCallback} and it's {@link Executor} will be removed. + * + * <p> + * If the method completes successfully, the frontend stopped previous scanning. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int stopScan() { - return nativeStopScan(); + TunerUtils.checkTunerPermission(mContext); + int retVal = nativeStopScan(); + mScanCallback = null; + mScanCallbackExecutor = null; + return retVal; } /** diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index c2d6c58c6558..4532122034ed 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -1015,10 +1015,13 @@ public final class TunerConstants { Constants.FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET; /** @hide */ - @IntDef({FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S, FRONTEND_DVBS_STANDARD_S2, - FRONTEND_DVBS_STANDARD_S2X}) + @IntDef(prefix = "FRONTEND_DVBS_STANDARD", + value = {FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S, + FRONTEND_DVBS_STANDARD_S2, + FRONTEND_DVBS_STANDARD_S2X}) @Retention(RetentionPolicy.SOURCE) - public @interface FrontendDvbsStandard {} + public @interface FrontendDvbsStandard { + } /** @hide */ public static final int FRONTEND_DVBS_STANDARD_AUTO = Constants.FrontendDvbsStandard.AUTO; /** @hide */ @@ -1210,6 +1213,20 @@ public final class TunerConstants { Constants.FrontendDvbtGuardInterval.INTERVAL_19_256; /** @hide */ + @IntDef(prefix = "FRONTEND_DVBT_STANDARD", + value = {FRONTEND_DVBT_STANDARD_AUTO, FRONTEND_DVBT_STANDARD_T, + FRONTEND_DVBT_STANDARD_T2} + ) + @Retention(RetentionPolicy.SOURCE) + public @interface FrontendDvbtStandard {} + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_AUTO = Constants.FrontendDvbtStandard.AUTO; + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_T = Constants.FrontendDvbtStandard.T; + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_T2 = Constants.FrontendDvbtStandard.T2; + + /** @hide */ @IntDef({FRONTEND_ISDBS_CODERATE_UNDEFINED, FRONTEND_ISDBS_CODERATE_AUTO, FRONTEND_ISDBS_CODERATE_1_2, FRONTEND_ISDBS_CODERATE_2_3, FRONTEND_ISDBS_CODERATE_3_4, FRONTEND_ISDBS_CODERATE_5_6, FRONTEND_ISDBS_CODERATE_7_8}) diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java index 99b10cde34f9..6496627cd1d4 100644 --- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java @@ -18,6 +18,7 @@ package android.media.tv.tuner.filter; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; import java.lang.annotation.Retention; @@ -28,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi public abstract class FilterConfiguration { /** @hide */ @@ -57,7 +59,7 @@ public abstract class FilterConfiguration { public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP; @Nullable - private final Settings mSettings; + /* package */ final Settings mSettings; /* package */ FilterConfiguration(Settings settings) { mSettings = settings; diff --git a/media/java/android/media/tv/tuner/filter/PesSettings.java b/media/java/android/media/tv/tuner/filter/PesSettings.java index f38abf12e120..bfa1f8c67d97 100644 --- a/media/java/android/media/tv/tuner/filter/PesSettings.java +++ b/media/java/android/media/tv/tuner/filter/PesSettings.java @@ -17,6 +17,9 @@ package android.media.tv.tuner.filter; import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; import android.media.tv.tuner.TunerConstants; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.FilterConfiguration.FilterType; @@ -26,6 +29,7 @@ import android.media.tv.tuner.filter.FilterConfiguration.FilterType; * * @hide */ +@SystemApi public class PesSettings extends Settings { private final int mStreamId; private final boolean mIsRaw; @@ -37,12 +41,32 @@ public class PesSettings extends Settings { } /** + * Gets stream ID. + */ + public int getStreamId() { + return mStreamId; + } + + /** + * Returns whether the data is raw. + * + * @return {@code true} if the data is raw. Filter sends onFilterStatus callback + * instead of onFilterEvent for raw data. {@code false} otherwise. + */ + public boolean isRaw() { + return mIsRaw; + } + + /** * Creates a builder for {@link PesSettings}. * * @param mainType the filter main type of the settings. + * @param context the context of the caller. */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @NonNull - public static Builder newBuilder(@FilterType int mainType) { + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); return new Builder(mainType); } @@ -70,13 +94,13 @@ public class PesSettings extends Settings { } /** - * Sets whether it's raw. + * Sets whether the data is raw. * * @param isRaw {@code true} if the data is raw. Filter sends onFilterStatus callback * instead of onFilterEvent for raw data. {@code false} otherwise. */ @NonNull - public Builder setIsRaw(boolean isRaw) { + public Builder setRaw(boolean isRaw) { mIsRaw = isRaw; return this; } diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java index 146aca74ce0e..91559260031c 100644 --- a/media/java/android/media/tv/tuner/filter/Settings.java +++ b/media/java/android/media/tv/tuner/filter/Settings.java @@ -16,11 +16,14 @@ package android.media.tv.tuner.filter; +import android.annotation.SystemApi; + /** * Settings for filters of different subtypes. * * @hide */ +@SystemApi public abstract class Settings { private final int mType; diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java index d0241b6aba09..5c38cfa70eb3 100644 --- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java @@ -17,12 +17,18 @@ package android.media.tv.tuner.filter; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; /** * Filter configuration for a TS filter. * * @hide */ +@SystemApi public class TsFilterConfiguration extends FilterConfiguration { private final int mTpid; @@ -37,10 +43,28 @@ public class TsFilterConfiguration extends FilterConfiguration { } /** + * Gets the {@link Settings} object of this filter configuration. + */ + @Nullable + public Settings getSettings() { + return mSettings; + } + /** + * Gets Tag Protocol ID. + */ + public int getTpid() { + return mTpid; + } + + /** * Creates a builder for {@link TsFilterConfiguration}. + * + * @param context the context of the caller. */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @NonNull - public static Builder newBuilder() { + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); return new Builder(); } @@ -51,6 +75,9 @@ public class TsFilterConfiguration extends FilterConfiguration { private Settings mSettings; private int mTpid; + private Builder() { + } + /** * Sets filter settings. * diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java index 0992eb665330..9c4f4606a9bc 100644 --- a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java +++ b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java @@ -27,10 +27,4 @@ public interface FrontendCallback { * Invoked when there is a frontend event. */ void onEvent(int frontendEventType); - - /** - * Invoked when there is a scan message. - * @param msg - */ - void onScanMessage(ScanMessage msg); } diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java new file mode 100644 index 000000000000..8118fcc0e900 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java @@ -0,0 +1,80 @@ +/* + * 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 android.media.tv.tuner.frontend; + +import android.media.tv.tuner.TunerConstants; + +/** + * Scan callback. + * + * @hide + */ +public interface ScanCallback { + /** Scan locked the signal. */ + void onLocked(boolean isLocked); + + /** Scan stopped. */ + void onEnd(boolean isEnd); + + /** scan progress percent (0..100) */ + void onProgress(int percent); + + /** Signal frequency in Hertz */ + void onFrequencyReport(int frequency); + + /** Symbols per second */ + void onSymbolRate(int rate); + + /** Locked Plp Ids for DVBT2 frontend. */ + void onPlpIds(int[] plpIds); + + /** Locked group Ids for DVBT2 frontend. */ + void onGroupIds(int[] groupIds); + + /** Stream Ids. */ + void onInputStreamIds(int[] inputStreamIds); + + /** Locked signal standard. */ + void onDvbsStandard(@TunerConstants.FrontendDvbsStandard int dvbsStandandard); + + /** Locked signal standard. */ + void onDvbtStandard(@TunerConstants.FrontendDvbtStandard int dvbtStandard); + + /** PLP status in a tuned frequency band for ATSC3 frontend. */ + void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos); + + /** PLP information for ATSC3. */ + class Atsc3PlpInfo { + private final int mPlpId; + private final boolean mLlsFlag; + + private Atsc3PlpInfo(int plpId, boolean llsFlag) { + mPlpId = plpId; + mLlsFlag = llsFlag; + } + + /** Gets PLP IDs. */ + public int getPlpId() { + return mPlpId; + } + + /** Gets LLS flag. */ + public boolean getLlsFlag() { + return mLlsFlag; + } + } +} diff --git a/media/java/android/media/tv/tuner/frontend/ScanMessage.java b/media/java/android/media/tv/tuner/frontend/ScanMessage.java deleted file mode 100644 index dd687dd2959c..000000000000 --- a/media/java/android/media/tv/tuner/frontend/ScanMessage.java +++ /dev/null @@ -1,172 +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 android.media.tv.tuner.frontend; - -import android.annotation.IntDef; -import android.hardware.tv.tuner.V1_0.Constants; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Message from frontend during scan operations. - * - * @hide - */ -public class ScanMessage { - - /** @hide */ - @IntDef({ - LOCKED, - END, - PROGRESS_PERCENT, - FREQUENCY, - SYMBOL_RATE, - PLP_IDS, - GROUP_IDS, - INPUT_STREAM_IDS, - STANDARD, - ATSC3_PLP_INFO - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Type {} - /** @hide */ - public static final int LOCKED = Constants.FrontendScanMessageType.LOCKED; - /** @hide */ - public static final int END = Constants.FrontendScanMessageType.END; - /** @hide */ - public static final int PROGRESS_PERCENT = Constants.FrontendScanMessageType.PROGRESS_PERCENT; - /** @hide */ - public static final int FREQUENCY = Constants.FrontendScanMessageType.FREQUENCY; - /** @hide */ - public static final int SYMBOL_RATE = Constants.FrontendScanMessageType.SYMBOL_RATE; - /** @hide */ - public static final int PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS; - /** @hide */ - public static final int GROUP_IDS = Constants.FrontendScanMessageType.GROUP_IDS; - /** @hide */ - public static final int INPUT_STREAM_IDS = Constants.FrontendScanMessageType.INPUT_STREAM_IDS; - /** @hide */ - public static final int STANDARD = Constants.FrontendScanMessageType.STANDARD; - /** @hide */ - public static final int ATSC3_PLP_INFO = Constants.FrontendScanMessageType.ATSC3_PLP_INFO; - - private final int mType; - private final Object mValue; - - private ScanMessage(int type, Object value) { - mType = type; - mValue = value; - } - - /** Gets scan message type. */ - @Type - public int getMessageType() { - return mType; - } - /** Message indicates whether frontend is locked or not. */ - public boolean getIsLocked() { - if (mType != LOCKED) { - throw new IllegalStateException(); - } - return (Boolean) mValue; - } - /** Message indicates whether the scan has reached the end or not. */ - public boolean getIsEnd() { - if (mType != END) { - throw new IllegalStateException(); - } - return (Boolean) mValue; - } - /** Progress message in percent. */ - public int getProgressPercent() { - if (mType != PROGRESS_PERCENT) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets frequency. */ - public int getFrequency() { - if (mType != FREQUENCY) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets symbol rate. */ - public int getSymbolRate() { - if (mType != SYMBOL_RATE) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets PLP IDs. */ - public int[] getPlpIds() { - if (mType != PLP_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets group IDs. */ - public int[] getGroupIds() { - if (mType != GROUP_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets Input stream IDs. */ - public int[] getInputStreamIds() { - if (mType != INPUT_STREAM_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets the DVB-T or DVB-S standard. */ - public int getStandard() { - if (mType != STANDARD) { - throw new IllegalStateException(); - } - return (int) mValue; - } - - /** Gets PLP information for ATSC3. */ - public Atsc3PlpInfo[] getAtsc3PlpInfos() { - if (mType != ATSC3_PLP_INFO) { - throw new IllegalStateException(); - } - return (Atsc3PlpInfo[]) mValue; - } - - /** PLP information for ATSC3. */ - public static class Atsc3PlpInfo { - private final int mPlpId; - private final boolean mLlsFlag; - - private Atsc3PlpInfo(int plpId, boolean llsFlag) { - mPlpId = plpId; - mLlsFlag = llsFlag; - } - - /** Gets PLP IDs. */ - public int getPlpId() { - return mPlpId; - } - /** Gets LLS flag. */ - public boolean getLlsFlag() { - return mLlsFlag; - } - } -} diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java index 65542673a607..cf55eba6e5ba 100644 --- a/mms/java/android/telephony/MmsManager.java +++ b/mms/java/android/telephony/MmsManager.java @@ -16,8 +16,12 @@ package android.telephony; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemService; import android.app.ActivityThread; import android.app.PendingIntent; +import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; @@ -27,22 +31,18 @@ import com.android.internal.telephony.IMms; /** * Manages MMS operations such as sending multimedia messages. - * Get this object by calling the static method {@link #getInstance()}. - * @hide + * Get this object by calling Context#getSystemService(Context#MMS_SERVICE). */ +@SystemService(Context.MMS_SERVICE) public class MmsManager { private static final String TAG = "MmsManager"; - - /** Singleton object constructed during class initialization. */ - private static final MmsManager sInstance = new MmsManager(); + private final Context mContext; /** - * Get the MmsManager singleton instance. - * - * @return the {@link MmsManager} singleton instance. + * @hide */ - public static MmsManager getInstance() { - return sInstance; + public MmsManager(@NonNull Context context) { + mContext = context; } /** @@ -56,8 +56,9 @@ public class MmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message * is successfully sent, or failed */ - public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl, - Bundle configOverrides, PendingIntent sentIntent) { + public void sendMultimediaMessage(int subId, @NonNull Uri contentUri, + @Nullable String locationUrl, @Nullable Bundle configOverrides, + @Nullable PendingIntent sentIntent) { try { final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); if (iMms == null) { @@ -84,8 +85,9 @@ public class MmsManager { * broadcast when the message is downloaded, or the download is failed * @throws IllegalArgumentException if locationUrl or contentUri is empty */ - public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri, - Bundle configOverrides, PendingIntent downloadedIntent) { + public void downloadMultimediaMessage(int subId, @NonNull String locationUrl, + @NonNull Uri contentUri, @Nullable Bundle configOverrides, + @Nullable PendingIntent downloadedIntent) { try { final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); if (iMms == null) { diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java index 642dc82c4d28..41a9b24afa03 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java @@ -36,6 +36,7 @@ import android.net.http.SslError; import android.os.Bundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; @@ -49,7 +50,6 @@ import android.widget.ProgressBar; import android.widget.TextView; import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.ArrayUtils; import com.android.internal.util.TrafficStatsConstants; @@ -203,7 +203,7 @@ public class CaptivePortalLoginActivity extends Activity { } private URL getUrlForCaptivePortal() { - String url = getIntent().getStringExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY); + String url = getIntent().getStringExtra(TelephonyManager.EXTRA_REDIRECTION_URL); if (TextUtils.isEmpty(url)) url = mCm.getCaptivePortalServerUrl(); final CarrierConfigManager configManager = getApplicationContext() .getSystemService(CarrierConfigManager.class); diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java index 46b1d5fe27be..c7f5e9a5ceec 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java @@ -19,10 +19,10 @@ import android.content.Context; import android.content.Intent; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; @@ -50,7 +50,7 @@ public class CustomConfigLoader { * @param intent passing signal for config match * @return a list of carrier action for the given signal based on the carrier config. * - * Example: input intent TelephonyIntent.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED + * Example: input intent TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED * This intent allows fined-grained matching based on both intent type & extra values: * apnType and errorCode. * apnType read from passing intent is "default" and errorCode is 0x26 for example and @@ -78,25 +78,25 @@ public class CustomConfigLoader { String arg1 = null; String arg2 = null; switch (intent.getAction()) { - case TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED: + case TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED: configs = b.getStringArray(CarrierConfigManager .KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY); break; - case TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: + case TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED: configs = b.getStringArray(CarrierConfigManager .KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY); - arg1 = intent.getStringExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY); - arg2 = intent.getStringExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY); + arg1 = intent.getStringExtra(TelephonyManager.EXTRA_APN_TYPE); + arg2 = intent.getStringExtra(TelephonyManager.EXTRA_ERROR_CODE); break; - case TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET: + case TelephonyManager.ACTION_CARRIER_SIGNAL_RESET: configs = b.getStringArray(CarrierConfigManager .KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET); break; - case TelephonyIntents.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: + case TelephonyManager.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE: configs = b.getStringArray(CarrierConfigManager .KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE); - arg1 = String.valueOf(intent.getBooleanExtra(TelephonyIntents - .EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY, false)); + arg1 = String.valueOf(intent.getBooleanExtra(TelephonyManager + .EXTRA_DEFAULT_NETWORK_AVAILABLE, false)); break; default: Log.e(TAG, "load carrier config failure with un-configured key: " diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java index 3e34f0aa6124..78a02d71fc9f 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java @@ -27,10 +27,9 @@ import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.Log; -import com.android.internal.telephony.TelephonyIntents; - /** * Service to run {@link android.app.job.JobScheduler} job. * Service to monitor when there is a change to conent URI @@ -93,7 +92,7 @@ public class ProvisionObserver extends JobService { } int jobId; switch(intent.getAction()) { - case TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED: + case TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED: jobId = PROVISION_OBSERVER_REEVALUATION_JOB_ID; break; default: diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java index 1928ad9add3e..086a287fd243 100644 --- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java +++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java @@ -15,6 +15,11 @@ */ package com.android.carrierdefaultapp; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -25,7 +30,6 @@ import android.telephony.TelephonyManager; import android.test.InstrumentationTestCase; import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; import org.junit.After; import org.junit.Before; @@ -34,10 +38,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; public class CarrierDefaultReceiverTest extends InstrumentationTestCase { @Mock @@ -87,7 +87,7 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase { .KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY, new String[]{"4,1"}); doReturn(b).when(mCarrierConfigMgr).getConfig(); - Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED); + Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED); intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mReceiver.onReceive(mContext, intent); diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml index bc1233828b4d..0f9deaa3c569 100644 --- a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml +++ b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml @@ -57,15 +57,5 @@ android:textColor="@color/global_actions_text" android:textAppearance="?android:attr/textAppearanceSmall" /> - - <TextView - android:visibility="gone" - android:id="@*android:id/status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textColor="@color/global_actions_text" - android:textAppearance="?android:attr/textAppearanceSmall" - /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml index 4404c87432fe..31c7cbf6ff1b 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_item.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml @@ -56,15 +56,5 @@ android:textColor="@color/global_actions_text" android:textAppearance="?android:attr/textAppearanceSmall" /> - - <TextView - android:visibility="gone" - android:id="@*android:id/status" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textColor="@color/global_actions_text" - android:textAppearance="?android:attr/textAppearanceSmall" - /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index fc19fa0c55fc..91bb80c60e3f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1166,13 +1166,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, TextView messageView = (TextView) v.findViewById(R.id.message); messageView.setSelected(true); // necessary for marquee to work - TextView statusView = (TextView) v.findViewById(R.id.status); - final String status = getStatus(); - if (!TextUtils.isEmpty(status)) { - statusView.setText(status); - } else { - statusView.setVisibility(View.GONE); - } if (mIcon != null) { icon.setImageDrawable(mIcon); icon.setScaleType(ScaleType.CENTER_CROP); @@ -1257,32 +1250,26 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, LayoutInflater inflater) { willCreate(); - View v = inflater.inflate(R - .layout.global_actions_item, parent, false); + View v = inflater.inflate(com.android.systemui.R + .layout.global_actions_grid_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); - TextView statusView = (TextView) v.findViewById(R.id.status); final boolean enabled = isEnabled(); + boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (messageView != null) { - messageView.setText(mMessageResId); + messageView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); messageView.setEnabled(enabled); messageView.setSelected(true); // necessary for marquee to work } - boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (icon != null) { icon.setImageDrawable(context.getDrawable( (on ? mEnabledIconResId : mDisabledIconResid))); icon.setEnabled(enabled); } - if (statusView != null) { - statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); - statusView.setVisibility(View.VISIBLE); - statusView.setEnabled(enabled); - } v.setEnabled(enabled); return v; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 91d5457c790c..9f2bbc680897 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -16,9 +16,11 @@ package com.android.systemui.screenshot; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.animation.Animator; @@ -48,6 +50,7 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; @@ -540,13 +543,16 @@ public class GlobalScreenshot { }); mActionsView.addView(actionChip); } - TextView scrollChip = (TextView) inflater.inflate( - R.layout.global_screenshot_action_chip, mActionsView, false); - Toast scrollNotImplemented = Toast.makeText( - mContext, "Not implemented", Toast.LENGTH_SHORT); - scrollChip.setText("Scroll"); // TODO (mkephart): add resource and translate - scrollChip.setOnClickListener(v -> scrollNotImplemented.show()); - mActionsView.addView(scrollChip); + + if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) { + TextView scrollChip = (TextView) inflater.inflate( + R.layout.global_screenshot_action_chip, mActionsView, false); + Toast scrollNotImplemented = Toast.makeText( + mContext, "Not implemented", Toast.LENGTH_SHORT); + scrollChip.setText("Scroll"); // TODO (mkephart): add resource and translate + scrollChip.setOnClickListener(v -> scrollNotImplemented.show()); + mActionsView.addView(scrollChip); + } ValueAnimator animator = ValueAnimator.ofFloat(0, 1); mActionsView.setY(mDisplayMetrics.heightPixels); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt index 78eaf3ee10a4..452d1eb95aab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt @@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.people import android.app.Notification +import android.content.Context import android.service.notification.StatusBarNotification +import android.util.FeatureFlagUtils import javax.inject.Inject import javax.inject.Singleton @@ -27,10 +29,16 @@ interface PeopleNotificationIdentifier { @Singleton class PeopleNotificationIdentifierImpl @Inject constructor( - private val personExtractor: NotificationPersonExtractor + private val personExtractor: NotificationPersonExtractor, + private val context: Context ) : PeopleNotificationIdentifier { override fun isPeopleNotification(sbn: StatusBarNotification) = - sbn.notification.notificationStyle == Notification.MessagingStyle::class.java || + (sbn.notification.notificationStyle == Notification.MessagingStyle::class.java && + (sbn.notification.shortcutId != null || + FeatureFlagUtils.isEnabled( + context, + FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ + ))) || personExtractor.isPersonNotification(sbn) }
\ No newline at end of file diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index e99c2c529bd2..5a71eb23abad 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -32,6 +32,7 @@ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.MANAGE_USB" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index c29e6784b5e6..ca290c637773 100644 --- a/packages/Tethering/res/values/config.xml +++ b/packages/Tethering/res/values/config.xml @@ -49,6 +49,9 @@ <item>"bt-pan"</item> </string-array> + <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. --> + <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool> + <!-- Dhcp range (min, max) to use for tethering purposes --> <string-array translatable="false" name="config_tether_dhcp_range"> </string-array> diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml index cc7980ba73fe..e089d9d19950 100644 --- a/packages/Tethering/res/values/overlayable.xml +++ b/packages/Tethering/res/values/overlayable.xml @@ -21,6 +21,7 @@ <item type="array" name="config_tether_wifi_p2p_regexs"/> <item type="array" name="config_tether_bluetooth_regexs"/> <item type="array" name="config_tether_dhcp_range"/> + <item type="bool" name="config_tether_enable_legacy_dhcp_server"/> <item type="array" name="config_tether_upstream_types"/> <item type="bool" name="config_tether_upstream_automatic"/> <!-- Configuration values for tethering entitlement check --> diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index 397ba8ada551..dbe789288c6f 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -21,7 +21,7 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.internal.R.array.config_mobile_hotspot_provision_app; import static com.android.internal.R.array.config_tether_bluetooth_regexs; @@ -33,13 +33,13 @@ import static com.android.internal.R.array.config_tether_wifi_regexs; import static com.android.internal.R.bool.config_tether_upstream_automatic; import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period; import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; +import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; -import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.TetheringConfigurationParcel; import android.net.util.SharedLog; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -84,6 +84,12 @@ public class TetheringConfiguration { private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + /** + * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. + */ + public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = + "tether_enable_legacy_dhcp_server"; + public final String[] tetherableUsbRegexs; public final String[] tetherableWifiRegexs; public final String[] tetherableWifiP2pRegexs; @@ -122,7 +128,7 @@ public class TetheringConfiguration { legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); - enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx); + enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app); provisioningAppNoUi = getProvisioningAppNoUi(res); @@ -332,10 +338,14 @@ public class TetheringConfiguration { } } - private static boolean getEnableLegacyDhcpServer(Context ctx) { - final ContentResolver cr = ctx.getContentResolver(); - final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); - return intVal != 0; + private boolean getEnableLegacyDhcpServer(final Resources res) { + return getResourceBoolean(res, config_tether_enable_legacy_dhcp_server) + || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); + } + + @VisibleForTesting + protected boolean getDeviceConfigBoolean(final String name) { + return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */); } private Resources getResources(Context ctx, int subId) { diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index 5692a6fc5c80..2875f71e5ed2 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -23,6 +23,8 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -215,19 +217,28 @@ public class UpstreamNetworkMonitor { mLog.e("registerMobileNetworkRequest() already registered"); return; } - // The following use of the legacy type system cannot be removed until - // after upstream selection no longer finds networks by legacy type. - // See also http://b/34364553 . - final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; - final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder() - .setCapabilities(networkCapabilitiesForType(legacyType)) - .build(); + final NetworkRequest mobileUpstreamRequest; + if (mDunRequired) { + mobileUpstreamRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_DUN) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .addTransportType(TRANSPORT_CELLULAR).build(); + } else { + mobileUpstreamRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_CELLULAR).build(); + } // The existing default network and DUN callbacks will be notified. // Therefore, to avoid duplicate notifications, we only register a no-op. mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST); + // The following use of the legacy type system cannot be removed until + // upstream selection no longer finds networks by legacy type. + // See also http://b/34364553 . + final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; + // TODO: Change the timeout from 0 (no onUnavailable callback) to some // moderate callback timeout. This might be useful for updating some UI. // Additionally, we log a message to aid in any subsequent debugging. diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 66eba9ae3b7a..79bba7f6e663 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -22,10 +22,12 @@ import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,7 +41,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.util.SharedLog; @@ -49,9 +50,8 @@ import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.SystemProperties; import android.os.test.TestLooper; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.CarrierConfigManager; -import android.test.mock.MockContentResolver; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -60,7 +60,6 @@ import com.android.internal.R; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.internal.util.test.FakeSettingsProvider; import org.junit.After; import org.junit.Before; @@ -94,7 +93,6 @@ public final class EntitlementManagerTest { private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final TestLooper mLooper = new TestLooper(); private Context mMockContext; - private MockContentResolver mContentResolver; private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; @@ -110,11 +108,6 @@ public final class EntitlementManagerTest { public Resources getResources() { return mResources; } - - @Override - public ContentResolver getContentResolver() { - return mContentResolver; - } } public class WrappedEntitlementManager extends EntitlementManager { @@ -151,13 +144,17 @@ public final class EntitlementManagerTest { MockitoAnnotations.initMocks(this); mMockingSession = mockitoSession() .initMocks(this) - .spyStatic(SystemProperties.class) + .mockStatic(SystemProperties.class) + .mockStatic(DeviceConfig.class) .strictness(Strictness.WARN) .startMocking(); // Don't disable tethering provisioning unless requested. doReturn(false).when( () -> SystemProperties.getBoolean( eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean())); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); @@ -169,10 +166,9 @@ public final class EntitlementManagerTest { .thenReturn(new String[0]); when(mResources.getIntArray(R.array.config_tether_upstream_types)) .thenReturn(new int[0]); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); when(mLog.forSubComponent(anyString())).thenReturn(mLog); - mContentResolver = new MockContentResolver(); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 7799da4b94a7..ef97ad418245 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -21,40 +21,44 @@ import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.internal.R.array.config_mobile_hotspot_provision_app; import static com.android.internal.R.array.config_tether_bluetooth_regexs; import static com.android.internal.R.array.config_tether_dhcp_range; import static com.android.internal.R.array.config_tether_upstream_types; import static com.android.internal.R.array.config_tether_usb_regexs; import static com.android.internal.R.array.config_tether_wifi_regexs; +import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.util.SharedLog; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.telephony.TelephonyManager; -import android.test.mock.MockContentResolver; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.internal.util.test.FakeSettingsProvider; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.util.Arrays; import java.util.Iterator; @@ -69,9 +73,10 @@ public class TetheringConfigurationTest { @Mock private TelephonyManager mTelephonyManager; @Mock private Resources mResources; @Mock private Resources mResourcesForSubId; - private MockContentResolver mContentResolver; private Context mMockContext; private boolean mHasTelephonyManager; + private boolean mEnableLegacyDhcpServer; + private MockitoSession mMockingSession; private class MockTetheringConfiguration extends TetheringConfiguration { MockTetheringConfiguration(Context ctx, SharedLog log, int id) { @@ -101,16 +106,20 @@ public class TetheringConfigurationTest { } return super.getSystemService(name); } - - @Override - public ContentResolver getContentResolver() { - return mContentResolver; - } } @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); + // TODO: use a dependencies class instead of mock statics. + mMockingSession = mockitoSession() + .initMocks(this) + .mockStatic(DeviceConfig.class) + .strictness(Strictness.WARN) + .startMocking(); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + when(mResources.getStringArray(config_tether_dhcp_range)).thenReturn(new String[0]); when(mResources.getStringArray(config_tether_usb_regexs)).thenReturn(new String[0]); when(mResources.getStringArray(config_tether_wifi_regexs)) @@ -119,10 +128,15 @@ public class TetheringConfigurationTest { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); when(mResources.getStringArray(config_mobile_hotspot_provision_app)) .thenReturn(new String[0]); - mContentResolver = new MockContentResolver(); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); + mEnableLegacyDhcpServer = false; + } + + @After + public void tearDown() throws Exception { + mMockingSession.finishMocking(); } private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { @@ -268,19 +282,35 @@ public class TetheringConfigurationTest { @Test public void testNewDhcpServerDisabled() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); - - final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - assertTrue(cfg.enableLegacyDhcpServer); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(true); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration enableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByRes.enableLegacyDhcpServer); + + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + doReturn(true).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration enableByDevConfig = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByDevConfig.enableLegacyDhcpServer); } @Test public void testNewDhcpServerEnabled() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + doReturn(false).when( + () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + + final TetheringConfiguration cfg = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); - final TetheringConfiguration cfg = new TetheringConfiguration( - mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertFalse(cfg.enableLegacyDhcpServer); } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 271769e155ca..e1fe3bfda4a8 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -35,9 +35,10 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; -import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -270,6 +271,11 @@ public class TetheringTest { } @Override + protected boolean getDeviceConfigBoolean(final String name) { + return false; + } + + @Override protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) { return mResources; } @@ -428,6 +434,7 @@ public class TetheringTest { .thenReturn(new int[0]); when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) .thenReturn(false); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); when(mNetd.interfaceGetList()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME}); @@ -440,7 +447,6 @@ public class TetheringTest { when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0); mIntents = new Vector<>(); mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -692,7 +698,7 @@ public class TetheringTest { @Test public void workingMobileUsbTethering_IPv4LegacyDhcp() { - Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1); + when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(true); sendConfigurationChanged(); final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); diff --git a/proto/Android.bp b/proto/Android.bp index 65bccbb4aac8..7cf6ce740969 100644 --- a/proto/Android.bp +++ b/proto/Android.bp @@ -27,3 +27,8 @@ java_library_static { srcs: ["src/metrics_constants/metrics_constants.proto"], sdk_version: "system_current", } + +filegroup { + name: "system-messages-proto-src", + srcs: ["src/system_messages.proto"], +} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index f34b5e71ad7b..7d354d20cb67 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -162,6 +162,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** uid the session is for */ public final int uid; + /** user id the session is for */ + public final int userId; + /** ID of the task associated with this session's activity */ public final int taskId; @@ -613,7 +616,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState int newState, int flags) { if (isInlineSuggestionsEnabled()) { mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(); - mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( + mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(userId, mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback); } @@ -759,6 +762,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mFlags = flags; this.taskId = taskId; this.uid = uid; + this.userId = userId; mStartTime = SystemClock.elapsedRealtime(); mService = service; mLock = lock; diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 73b6c7a570ed..0f2fb9252c29 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -208,6 +208,7 @@ class AlarmManagerService extends SystemService { AppWakeupHistory mAppWakeupHistory; ClockReceiver mClockReceiver; final DeliveryTracker mDeliveryTracker = new DeliveryTracker(); + IBinder.DeathRecipient mListenerDeathRecipient; Intent mTimeTickIntent; IAlarmListener mTimeTickTrigger; PendingIntent mDateChangeSender; @@ -1447,6 +1448,18 @@ class AlarmManagerService extends SystemService { public void onStart() { mInjector.init(); + mListenerDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + } + + @Override + public void binderDied(IBinder who) { + final IAlarmListener listener = IAlarmListener.Stub.asInterface(who); + removeImpl(null, listener); + } + }; + synchronized (mLock) { mHandler = new AlarmHandler(); mConstants = new Constants(mHandler); @@ -1653,6 +1666,15 @@ class AlarmManagerService extends SystemService { return; } + if (directReceiver != null) { + try { + directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0); + } catch (RemoteException e) { + Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag); + return; + } + } + // Sanity check the window length. This will catch people mistakenly // trying to pass an end-of-window timestamp rather than a duration. if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { @@ -2079,8 +2101,9 @@ class AlarmManagerService extends SystemService { @Override public long currentNetworkTimeMillis() { final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext()); - if (time.hasCache()) { - return time.currentTimeMillis(); + NtpTrustedTime.TimeResult ntpResult = time.getCachedTimeResult(); + if (ntpResult != null) { + return ntpResult.currentTimeMillis(); } else { throw new ParcelableException(new DateTimeException("Missing NTP fix")); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 26c12c141e19..5435cbad870f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3617,14 +3617,29 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceSettingsPermission(); } + final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork); + if (nm == null) return; + nm.notifyCaptivePortalAppFinished(response); + } + + @Override + public void appRequest(final int request) { + final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork); + if (nm == null) return; + + if (request == CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED) { + nm.forceReevaluation(Binder.getCallingUid()); + } + } + + @Nullable + private NetworkMonitorManager getNetworkMonitorManager(final Network network) { // getNetworkAgentInfoForNetwork is thread-safe - final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(mNetwork); - if (nai == null) return; + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) return null; // nai.networkMonitor() is thread-safe - final NetworkMonitorManager nm = nai.networkMonitor(); - if (nm == null) return; - nm.notifyCaptivePortalAppFinished(response); + return nai.networkMonitor(); } @Override @@ -5490,7 +5505,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // changes that would conflict throughout the automerger graph. Having this method temporarily // helps with the process of going through with all these dependent changes across the entire // tree. - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + /** + * Register a new agent. {@see #registerNetworkAgent} below. + */ + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig) { return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, @@ -5511,8 +5529,9 @@ public class ConnectivityService extends IConnectivityManager.Stub * {@link NetworkAgentInfo#getCurrentScore}. * @param networkAgentConfig metadata about the network. This is never updated. * @param providerId the ID of the provider owning this NetworkAgent. + * @return the network created for this agent. */ - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { enforceNetworkFactoryPermission(); @@ -5545,7 +5564,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If the network disconnects or sends any other event before that, messages are deferred by // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the // registration. - return nai.network.netId; + return nai.network; } private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java index d20936c2d217..7894788cb0b6 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java @@ -154,17 +154,20 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU private void onPollNetworkTimeUnderWakeLock(int event) { // Force an NTP fix when outdated - if (mTime.getCacheAge() >= mPollingIntervalMs) { + NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); + if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); mTime.forceRefresh(); + cachedNtpResult = mTime.getCachedTimeResult(); } - if (mTime.getCacheAge() < mPollingIntervalMs) { + if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { // Obtained fresh fix; schedule next normal update resetAlarm(mPollingIntervalMs); // Suggest the time to the time detector. It may choose use it to set the system clock. - TimestampedValue<Long> timeSignal = mTime.getCachedNtpTimeSignal(); + TimestampedValue<Long> timeSignal = new TimestampedValue<>( + cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateServiceImpl. event=" + event); mTimeDetector.suggestNetworkTime(timeSuggestion); @@ -275,8 +278,11 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); pw.println("\nTryAgainCounter: " + mTryAgainCounter); - pw.println("NTP cache age: " + mTime.getCacheAge()); - pw.println("NTP cache certainty: " + mTime.getCacheCertainty()); + NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); + pw.println("NTP cache result: " + ntpResult); + if (ntpResult != null) { + pw.println("NTP result age: " + ntpResult.getAgeMillis()); + } pw.println(); } } diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java index 190fff1f669c..21fa9f9a9401 100644 --- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java +++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java @@ -46,4 +46,7 @@ public interface PersistentDataBlockManagerInternal { /** Update the OEM unlock enabled bit, bypassing user restriction checks. */ void forceOemUnlockEnabled(boolean enabled); + + /** Retrieves the UID that can access the persistent data partition. */ + int getAllowedUid(); } diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 73c852083cfd..00d8b0f1bed4 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -680,6 +680,11 @@ public class PersistentDataBlockService extends SystemService { writeDataBuffer(getTestHarnessModeDataOffset(), ByteBuffer.allocate(size)); } + @Override + public int getAllowedUid() { + return mAllowedUid; + } + private void writeInternal(byte[] data, long offset, int dataLength) { checkArgument(data == null || data.length > 0, "data must be null or non-empty"); checkArgument( diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index c27b0da780b7..ed3bab97ca19 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -218,7 +218,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up // resources, even for binder death or unwanted calls. synchronized (mTestNetworkTracker) { - mTestNetworkTracker.remove(netId); + mTestNetworkTracker.remove(network.netId); } } } @@ -337,7 +337,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { callingUid, binder); - mTestNetworkTracker.put(agent.netId, agent); + mTestNetworkTracker.put(agent.network.netId, agent); } } catch (SocketException e) { throw new UncheckedIOException(e); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index a372fca07728..debc2a116934 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2129,16 +2129,6 @@ public class AccountManagerService } @Override - public void removeAccount(IAccountManagerResponse response, Account account, - boolean expectActivityLaunch) { - removeAccountAsUser( - response, - account, - expectActivityLaunch, - UserHandle.getCallingUserId()); - } - - @Override public void removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId) { final int callingUid = Binder.getCallingUid(); @@ -4454,12 +4444,6 @@ public class AccountManagerService @Override @NonNull - public Account[] getAccounts(String type, String opPackageName) { - return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName); - } - - @Override - @NonNull public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) { int callingUid = Binder.getCallingUid(); if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 2b207827a5ef..8ae18ff68b66 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1645,10 +1645,9 @@ class UserController implements Handler.Callback { final boolean allow; final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, targetUserId); if (mInjector.isCallerRecents(callingUid) - && callingUserId == getCurrentUserId() - && isSameProfileGroup) { - // If the caller is Recents and it is running in the current user, we then allow it - // to access its profiles. + && isSameProfileGroup(callingUserId, targetUserId)) { + // If the caller is Recents and the caller has ownership of the profile group, + // we then allow it to access its profiles. allow = true; } else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid, callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a7593c7a43ec..e3b761e0773d 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1759,8 +1759,9 @@ public class AppOpsService extends IAppOpsService.Stub { ? opNames.toArray(new String[opNames.size()]) : null; // Must not hold the appops lock - mHistoricalRegistry.getHistoricalOps(uid, packageName, featureId, opNamesArray, filter, - beginTimeMillis, endTimeMillis, flags, callback); + mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps, + mHistoricalRegistry, uid, packageName, featureId, opNamesArray, filter, + beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse()); } @Override @@ -1778,8 +1779,9 @@ public class AppOpsService extends IAppOpsService.Stub { ? opNames.toArray(new String[opNames.size()]) : null; // Must not hold the appops lock - mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, featureId, opNamesArray, - filter, beginTimeMillis, endTimeMillis, flags, callback); + mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw, + mHistoricalRegistry, uid, packageName, featureId, opNamesArray, + filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse()); } @Override diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index f15d999e1006..8d261762a19b 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -367,6 +367,8 @@ final class CompatConfig { CompatConfig config = new CompatConfig(androidBuildClassifier, context); config.initConfigFromLib(Environment.buildPath( Environment.getRootDirectory(), "etc", "compatconfig")); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); return config; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 476f3f823def..1d2a9059c453 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -848,7 +848,7 @@ public class Vpn { } public int getNetId() { - return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; + return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET; } private LinkProperties makeLinkProperties() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 2c3c70fc3da2..9c421524d723 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -68,8 +68,9 @@ public abstract class InputMethodManagerInternal { * @param autofillId {@link AutofillId} of currently focused field. * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object. */ - public abstract void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb); + public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb); /** * Force switch to the enabled input method by {@code imeId} for current user. If the input @@ -107,8 +108,9 @@ public abstract class InputMethodManagerInternal { } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest(int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb) { } @Override diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d4b13faf3195..0bf65bd6f739 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -111,6 +111,7 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionInspector; @@ -142,6 +143,7 @@ import com.android.internal.os.TransferPipe; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; import com.android.internal.view.IInputMethodClient; @@ -1790,15 +1792,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback callback) { - + private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback callback) { final InputMethodInfo imi = mMethodMap.get(mCurMethodId); try { - if (imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { + if (userId == mSettings.getCurrentUserId() && imi != null + && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, - componentName, autofillId, callback)); + componentName, autofillId, + new InlineSuggestionsRequestCallbackDecorator(callback, + imi.getPackageName()))); } else { callback.onInlineSuggestionsUnsupported(); } @@ -1808,6 +1813,42 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } /** + * The decorator which validates the host package name in the + * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. + */ + private static final class InlineSuggestionsRequestCallbackDecorator + extends IInlineSuggestionsRequestCallback.Stub { + @NonNull + private final IInlineSuggestionsRequestCallback mCallback; + @NonNull + private final String mImePackageName; + + InlineSuggestionsRequestCallbackDecorator( + @NonNull IInlineSuggestionsRequestCallback callback, + @NonNull String imePackageName) { + mCallback = callback; + mImePackageName = imePackageName; + } + + @Override + public void onInlineSuggestionsUnsupported() throws RemoteException { + mCallback.onInlineSuggestionsUnsupported(); + } + + @Override + public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, + IInlineSuggestionsResponseCallback callback) throws RemoteException { + if (!mImePackageName.equals(request.getHostPackageName())) { + throw new SecurityException( + "Host package name in the provide request=[" + request.getHostPackageName() + + "] doesn't match the IME package name=[" + mImePackageName + + "]."); + } + mCallback.onInlineSuggestionsRequest(request, callback); + } + } + + /** * @param imiId if null, returns enabled subtypes for the current imi * @return enabled subtypes of the specified imi */ @@ -4471,10 +4512,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - private void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback callback) { + private void onCreateInlineSuggestionsRequest(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback callback) { synchronized (mMethodMap) { - onCreateInlineSuggestionsRequestLocked(componentName, autofillId, callback); + onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback); } } @@ -4542,9 +4584,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, + public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName, AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { - mService.onCreateInlineSuggestionsRequest(componentName, autofillId, cb); + mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb); } @Override diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 20d7955e0c77..f09795fbea01 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -191,8 +191,9 @@ public final class MultiClientInputMethodManagerService { } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest(int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb) { try { //TODO(b/137800469): support multi client IMEs. cb.onInlineSuggestionsUnsupported(); diff --git a/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java b/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java index e555e3e5746e..4bf8fe8d93b6 100644 --- a/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java +++ b/services/core/java/com/android/server/integrity/model/BitTrackedInputStream.java @@ -27,30 +27,37 @@ import java.io.InputStream; */ public class BitTrackedInputStream extends BitInputStream { - private static int sReadBitsCount; + private int mReadBitsCount; /** Constructor with byte array. */ public BitTrackedInputStream(byte[] inputStream) { super(inputStream); - sReadBitsCount = 0; + mReadBitsCount = 0; } /** Constructor with input stream. */ public BitTrackedInputStream(InputStream inputStream) { super(inputStream); - sReadBitsCount = 0; + mReadBitsCount = 0; } /** Obtains an integer value of the next {@code numOfBits}. */ @Override public int getNext(int numOfBits) throws IOException { - sReadBitsCount += numOfBits; + mReadBitsCount += numOfBits; return super.getNext(numOfBits); } /** Returns the current cursor position showing the number of bits that are read. */ public int getReadBitsCount() { - return sReadBitsCount; + return mReadBitsCount; + } + + /** + * Returns true if we can read more rules by checking whether the end index is not reached yet. + */ + public boolean canReadMoreRules(int endIndexBytes) { + return mReadBitsCount < endIndexBytes * 8; } /** @@ -59,11 +66,11 @@ public class BitTrackedInputStream extends BitInputStream { * Note that the integer parameter specifies the location in bytes -- not bits. */ public void setCursorToByteLocation(int byteLocation) throws IOException { - int bitCountToRead = byteLocation * 8 - sReadBitsCount; + int bitCountToRead = byteLocation * 8 - mReadBitsCount; if (bitCountToRead < 0) { throw new IllegalStateException("The byte position is already read."); } super.getNext(bitCountToRead); - sReadBitsCount = byteLocation * 8; + mReadBitsCount = byteLocation * 8; } } diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index e744326c49db..2f285631b982 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -105,8 +105,7 @@ public class RuleBinaryParser implements RuleParser { bitTrackedInputStream.setCursorToByteLocation(range.getStartIndex()); // Read the rules until we reach the end index. - while (bitTrackedInputStream.hasNext() - && bitTrackedInputStream.getReadBitsCount() < range.getEndIndex()) { + while (bitTrackedInputStream.canReadMoreRules(range.getEndIndex())) { if (bitTrackedInputStream.getNext(SIGNAL_BIT) == 1) { parsedRules.add(parseRule(bitTrackedInputStream)); } diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java index 8c8450e5fdc4..453fa5d84053 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java +++ b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java @@ -23,28 +23,28 @@ import android.annotation.Nullable; * RuleIndexingController}. */ public class RuleIndexRange { - private static int sStartIndex; - private static int sEndIndex; + private int mStartIndex; + private int mEndIndex; /** Constructor with start and end indexes. */ public RuleIndexRange(int startIndex, int endIndex) { - this.sStartIndex = startIndex; - this.sEndIndex = endIndex; + this.mStartIndex = startIndex; + this.mEndIndex = endIndex; } /** Returns the startIndex. */ public int getStartIndex() { - return sStartIndex; + return mStartIndex; } /** Returns the end index. */ public int getEndIndex() { - return sEndIndex; + return mEndIndex; } @Override public boolean equals(@Nullable Object object) { - return sStartIndex == ((RuleIndexRange) object).getStartIndex() - && sEndIndex == ((RuleIndexRange) object).getEndIndex(); + return mStartIndex == ((RuleIndexRange) object).getStartIndex() + && mEndIndex == ((RuleIndexRange) object).getEndIndex(); } } diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java index c9713220d6e8..03392abf478f 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java +++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java @@ -56,7 +56,7 @@ public class RuleIndexingController { * read and evaluated. */ public List<RuleIndexRange> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) { - ArrayList<RuleIndexRange> indexRanges = new ArrayList(); + List<RuleIndexRange> indexRanges = new ArrayList<>(); // Add the range for package name indexes rules. indexRanges.add( @@ -102,7 +102,7 @@ public class RuleIndexingController { .collect(Collectors.toCollection(TreeSet::new)); String minIndex = keyTreeSet.floor(searchedKey); - String maxIndex = keyTreeSet.ceiling(searchedKey); + String maxIndex = keyTreeSet.higher(searchedKey); return new RuleIndexRange( indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex), diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index d3588d38d976..8f53be7d87af 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -52,7 +52,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; +import java.util.stream.Collectors; /** A helper class to serialize rules from the {@link Rule} model to Binary representation. */ public class RuleBinarySerializer implements RuleSerializer { @@ -80,21 +80,24 @@ public class RuleBinarySerializer implements RuleSerializer { throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. - Map<Integer, TreeMap<String, List<Rule>>> indexedRules = + Map<Integer, Map<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Serialize the rules. ByteTrackedOutputStream ruleFileByteTrackedOutputStream = new ByteTrackedOutputStream(rulesFileOutputStream); serializeRuleFileMetadata(formatVersion, ruleFileByteTrackedOutputStream); - Map<String, Integer> packageNameIndexes = - serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), + LinkedHashMap<String, Integer> packageNameIndexes = + serializeRuleList( + indexedRules.get(PACKAGE_NAME_INDEXED), ruleFileByteTrackedOutputStream); - Map<String, Integer> appCertificateIndexes = - serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), + LinkedHashMap<String, Integer> appCertificateIndexes = + serializeRuleList( + indexedRules.get(APP_CERTIFICATE_INDEXED), ruleFileByteTrackedOutputStream); - Map<String, Integer> unindexedRulesIndexes = - serializeRuleList(indexedRules.get(NOT_INDEXED), + LinkedHashMap<String, Integer> unindexedRulesIndexes = + serializeRuleList( + indexedRules.get(NOT_INDEXED), ruleFileByteTrackedOutputStream); // Serialize their indexes. @@ -104,6 +107,9 @@ public class RuleBinarySerializer implements RuleSerializer { true); serializeIndexGroup(unindexedRulesIndexes, indexingBitOutputStream, /* isIndexed= */ false); + // TODO(b/147609625): This dummy bit is set for fixing the padding issue. Remove when + // the issue is fixed and correct the tests that does this padding too. + indexingBitOutputStream.setNext(); indexingFileOutputStream.write(indexingBitOutputStream.toByteArray()); } catch (Exception e) { throw new RuleSerializeException(e.getMessage(), e); @@ -120,24 +126,25 @@ public class RuleBinarySerializer implements RuleSerializer { outputStream.write(bitOutputStream.toByteArray()); } - private Map<String, Integer> serializeRuleList(TreeMap<String, List<Rule>> rulesMap, - ByteTrackedOutputStream outputStream) + private LinkedHashMap<String, Integer> serializeRuleList( + Map<String, List<Rule>> rulesMap, ByteTrackedOutputStream outputStream) throws IOException { Preconditions.checkArgument(rulesMap != null, "serializeRuleList should never be called with null rule list."); BitOutputStream bitOutputStream = new BitOutputStream(); - Map<String, Integer> indexMapping = new LinkedHashMap(); - int indexTracker = 0; - + LinkedHashMap<String, Integer> indexMapping = new LinkedHashMap(); indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount()); - for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { + + List<String> sortedKeys = rulesMap.keySet().stream().sorted().collect(Collectors.toList()); + int indexTracker = 0; + for (String key : sortedKeys) { if (indexTracker >= INDEXING_BLOCK_SIZE) { - indexMapping.put(entry.getKey(), outputStream.getWrittenBytesCount()); + indexMapping.put(key, outputStream.getWrittenBytesCount()); indexTracker = 0; } - for (Rule rule : entry.getValue()) { + for (Rule rule : rulesMap.get(key)) { bitOutputStream.clear(); serializeRule(rule, bitOutputStream); outputStream.write(bitOutputStream.toByteArray()); @@ -222,11 +229,13 @@ public class RuleBinarySerializer implements RuleSerializer { } private void serializeIndexGroup( - Map<String, Integer> indexes, BitOutputStream bitOutputStream, boolean isIndexed) { + LinkedHashMap<String, Integer> indexes, + BitOutputStream bitOutputStream, + boolean isIndexed) { // Output the starting location of this indexing group. - serializeStringValue(START_INDEXING_KEY, /* isHashedValue= */false, - bitOutputStream); + serializeStringValue( + START_INDEXING_KEY, /* isHashedValue= */false, bitOutputStream); serializeIntValue(indexes.get(START_INDEXING_KEY), bitOutputStream); // If the group is indexed, output the locations of the indexes. @@ -244,9 +253,6 @@ public class RuleBinarySerializer implements RuleSerializer { // Output the end location of this indexing group. serializeStringValue(END_INDEXING_KEY, /*isHashedValue= */ false, bitOutputStream); serializeIntValue(indexes.get(END_INDEXING_KEY), bitOutputStream); - - // This dummy bit is set for fixing the padding issue. songpan@ will fix it and remove it. - bitOutputStream.setNext(); } private void serializeStringValue( diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java index dd871e2bbe6c..2cbd4ede5214 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java @@ -28,6 +28,8 @@ class RuleIndexingDetails { static final int PACKAGE_NAME_INDEXED = 1; static final int APP_CERTIFICATE_INDEXED = 2; + static final String DEFAULT_RULE_KEY = "N/A"; + /** Represents which indexed file the rule should be located. */ @IntDef( value = { @@ -45,7 +47,7 @@ class RuleIndexingDetails { /** Constructor without a ruleKey for {@code NOT_INDEXED}. */ RuleIndexingDetails(@IndexType int indexType) { this.mIndexType = indexType; - this.mRuleKey = null; + this.mRuleKey = DEFAULT_RULE_KEY; } /** Constructor with a ruleKey for indexed rules. */ diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java index cbc365e2c250..7d9a90188983 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java @@ -30,30 +30,27 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; /** A helper class for identifying the indexing type and key of a given rule. */ class RuleIndexingDetailsIdentifier { - private static final String DEFAULT_RULE_KEY = "N/A"; - /** * Splits a given rule list into three indexing categories. Each rule category is returned as a * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for * NOT_INDEXED rules. */ - public static Map<Integer, TreeMap<String, List<Rule>>> splitRulesIntoIndexBuckets( + public static Map<Integer, Map<String, List<Rule>>> splitRulesIntoIndexBuckets( List<Rule> rules) { if (rules == null) { throw new IllegalArgumentException( "Index buckets cannot be created for null rule list."); } - Map<Integer, TreeMap<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); - typeOrganizedRuleMap.put(NOT_INDEXED, new TreeMap()); - typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new TreeMap()); - typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new TreeMap()); + Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); + typeOrganizedRuleMap.put(NOT_INDEXED, new HashMap()); + typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new HashMap<>()); + typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new HashMap<>()); // Split the rules into the appropriate indexed pattern. The Tree Maps help us to keep the // entries sorted by their index key. @@ -66,21 +63,14 @@ class RuleIndexingDetailsIdentifier { String.format("Malformed rule identified. [%s]", rule.toString())); } - String ruleKey = - indexingDetails.getIndexType() != NOT_INDEXED - ? indexingDetails.getRuleKey() - : DEFAULT_RULE_KEY; + int ruleIndexType = indexingDetails.getIndexType(); + String ruleKey = indexingDetails.getRuleKey(); - if (!typeOrganizedRuleMap.get(indexingDetails.getIndexType()).containsKey(ruleKey)) { - typeOrganizedRuleMap - .get(indexingDetails.getIndexType()) - .put(ruleKey, new ArrayList()); + if (!typeOrganizedRuleMap.get(ruleIndexType).containsKey(ruleKey)) { + typeOrganizedRuleMap.get(ruleIndexType).put(ruleKey, new ArrayList()); } - typeOrganizedRuleMap - .get(indexingDetails.getIndexType()) - .get(ruleKey) - .add(rule); + typeOrganizedRuleMap.get(ruleIndexType).get(ruleKey).add(rule); } return typeOrganizedRuleMap; diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java index 4194432375b8..8f164e645434 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -35,7 +35,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; +import java.util.stream.Collectors; /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */ public class RuleXmlSerializer implements RuleSerializer { @@ -90,7 +90,7 @@ public class RuleXmlSerializer implements RuleSerializer { throws RuleSerializeException { try { // Determine the indexing groups and the order of the rules within each indexed group. - Map<Integer, TreeMap<String, List<Rule>>> indexedRules = + Map<Integer, Map<String, List<Rule>>> indexedRules = RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); // Write the XML formatted rules in order. @@ -107,11 +107,12 @@ public class RuleXmlSerializer implements RuleSerializer { } } - private void serializeRuleList(TreeMap<String, List<Rule>> rulesMap, - XmlSerializer xmlSerializer) + private void serializeRuleList(Map<String, List<Rule>> rulesMap, XmlSerializer xmlSerializer) throws IOException { - for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) { - for (Rule rule : entry.getValue()) { + List<String> sortedKeyList = + rulesMap.keySet().stream().sorted().collect(Collectors.toList()); + for (String key : sortedKeyList) { + for (Rule rule : rulesMap.get(key)) { serializeRule(rule, xmlSerializer); } } diff --git a/services/core/java/com/android/server/location/NtpTimeHelper.java b/services/core/java/com/android/server/location/NtpTimeHelper.java index 67841aca1605..d2296ea27913 100644 --- a/services/core/java/com/android/server/location/NtpTimeHelper.java +++ b/services/core/java/com/android/server/location/NtpTimeHelper.java @@ -130,7 +130,8 @@ class NtpTimeHelper { // force refresh NTP cache when outdated boolean refreshSuccess = true; - if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { + NtpTrustedTime.TimeResult ntpResult = mNtpTime.getCachedTimeResult(); + if (ntpResult == null || ntpResult.getAgeMillis() >= NTP_INTERVAL) { // Blocking network operation. refreshSuccess = mNtpTime.forceRefresh(); } @@ -140,17 +141,17 @@ class NtpTimeHelper { // only update when NTP time is fresh // If refreshSuccess is false, cacheAge does not drop down. - if (mNtpTime.getCacheAge() < NTP_INTERVAL) { - long time = mNtpTime.getCachedNtpTime(); - long timeReference = mNtpTime.getCachedNtpTimeReference(); - long certainty = mNtpTime.getCacheCertainty(); + ntpResult = mNtpTime.getCachedTimeResult(); + if (ntpResult != null && ntpResult.getAgeMillis() < NTP_INTERVAL) { + long time = ntpResult.getTimeMillis(); + long timeReference = ntpResult.getElapsedRealtimeMillis(); + long certainty = ntpResult.getCertaintyMillis(); if (DEBUG) { long now = System.currentTimeMillis(); Log.d(TAG, "NTP server returned: " - + time + " (" + new Date(time) - + ") reference: " + timeReference - + " certainty: " + certainty + + time + " (" + new Date(time) + ")" + + " ntpResult: " + ntpResult + " system time offset: " + (time - now)); } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index c4bcf809a67d..3e760962da87 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -449,6 +449,7 @@ public class AppsFilter { } final PackageSetting callingPkgSetting; final ArraySet<PackageSetting> callingSharedPkgSettings; + Trace.beginSection("callingSetting instanceof"); if (callingSetting instanceof PackageSetting) { callingPkgSetting = (PackageSetting) callingSetting; callingSharedPkgSettings = null; @@ -456,6 +457,7 @@ public class AppsFilter { callingPkgSetting = null; callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; } + Trace.endSection(); if (callingPkgSetting != null) { if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) { @@ -485,6 +487,7 @@ public class AppsFilter { return true; } final String targetName = targetPkg.getPackageName(); + Trace.beginSection("getAppId"); final int callingAppId; if (callingPkgSetting != null) { callingAppId = callingPkgSetting.appId; @@ -492,6 +495,7 @@ public class AppsFilter { callingAppId = callingSharedPkgSettings.valueAt(0).appId; // all should be the same } final int targetAppId = targetPkgSetting.appId; + Trace.endSection(); if (callingAppId == targetAppId) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "same app id"); @@ -499,38 +503,64 @@ public class AppsFilter { return false; } - if (callingSetting.getPermissionsState().hasPermission( - Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "has query-all permission"); + try { + Trace.beginSection("hasPermission"); + if (callingSetting.getPermissionsState().hasPermission( + Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "has query-all permission"); + } + return false; } - return false; + } finally { + Trace.endSection(); } - if (mForceQueryable.contains(targetAppId)) { - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "force queryable"); + try { + Trace.beginSection("mForceQueryable"); + if (mForceQueryable.contains(targetAppId)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "force queryable"); + } + return false; } - return false; + } finally { + Trace.endSection(); } - if (mQueriesViaPackage.contains(callingAppId, targetAppId)) { - // the calling package has explicitly declared the target package; allow - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "queries package"); + try { + Trace.beginSection("mQueriesViaPackage"); + if (mQueriesViaPackage.contains(callingAppId, targetAppId)) { + // the calling package has explicitly declared the target package; allow + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "queries package"); + } + return false; } - return false; - } else if (mQueriesViaIntent.contains(callingAppId, targetAppId)) { - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "queries intent"); + } finally { + Trace.endSection(); + } + try { + Trace.beginSection("mQueriesViaIntent"); + if (mQueriesViaIntent.contains(callingAppId, targetAppId)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "queries intent"); + } + return false; } - return false; + } finally { + Trace.endSection(); } - final int targetUid = UserHandle.getUid(userId, targetAppId); - if (mImplicitlyQueryable.contains(callingUid, targetUid)) { - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "implicitly queryable for user"); + try { + Trace.beginSection("mImplicitlyQueryable"); + final int targetUid = UserHandle.getUid(userId, targetAppId); + if (mImplicitlyQueryable.contains(callingUid, targetUid)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "implicitly queryable for user"); + } + return false; } - return false; + } finally { + Trace.endSection(); } if (callingPkgSetting != null) { if (callingPkgInstruments(callingPkgSetting, targetPkgSetting, targetName)) { @@ -576,17 +606,22 @@ public class AppsFilter { private static boolean callingPkgInstruments(PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, String targetName) { - final List<ComponentParseUtils.ParsedInstrumentation> inst = - callingPkgSetting.pkg.getInstrumentations(); - for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { - if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) { - if (DEBUG_LOGGING) { - log(callingPkgSetting, targetPkgSetting, "instrumentation"); + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingPkgInstruments"); + final List<ComponentParseUtils.ParsedInstrumentation> inst = + callingPkgSetting.pkg.getInstrumentations(); + for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { + if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) { + if (DEBUG_LOGGING) { + log(callingPkgSetting, targetPkgSetting, "instrumentation"); + } + return true; } - return true; } + return false; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - return false; } private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting, diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 6d6ec250e4cc..46893b25de9a 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -592,12 +592,6 @@ public final class DefaultPermissionGrantPolicy { getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId), userId, ALWAYS_LOCATION_PERMISSIONS); - // Gallery - grantPermissionsToSystemPackage( - getDefaultSystemHandlerActivityPackageForCategory( - Intent.CATEGORY_APP_GALLERY, userId), - userId, STORAGE_PERMISSIONS); - // Email grantPermissionsToSystemPackage( getDefaultSystemHandlerActivityPackageForCategory( diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS index 8d7f8822f78e..fc7fd220b26a 100644 --- a/services/core/java/com/android/server/stats/OWNERS +++ b/services/core/java/com/android/server/stats/OWNERS @@ -1,9 +1,8 @@ -bookatz@google.com -cjyu@google.com -dwchen@google.com +jeffreyhuang@google.com joeo@google.com +muhammadq@google.com +ruchirr@google.com singhtejinder@google.com -stlafon@google.com +tsaichristine@google.com yaochen@google.com -yanglu@google.com -yro@google.com
\ No newline at end of file +yro@google.com diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java index a75f1c210bc0..5ee7eff20e24 100644 --- a/services/core/java/com/android/server/stats/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java @@ -186,6 +186,12 @@ public class StatsPullAtomService extends SystemService { private static final String TAG = "StatsPullAtomService"; private static final boolean DEBUG = true; + private static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; + /** + * How long to wait on an individual subsystem to return its stats. + */ + private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; + private final Object mNetworkStatsLock = new Object(); @GuardedBy("mNetworkStatsLock") private INetworkStatsService mNetworkStatsService; @@ -327,11 +333,12 @@ public class StatsPullAtomService extends SystemService { } private void registerWifiBytesTransfer() { int tagId = StatsLog.WIFI_BYTES_TRANSFER; - PullAtomMetadata metaData = PullAtomMetadata.newBuilder() - .setAdditiveFields(new int[] {2, 3, 4, 5}).build(); + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3, 4, 5}) + .build(); mStatsManager.registerPullAtomCallback( tagId, - metaData, + metadata, (atomTag, data) -> pullWifiBytesTransfer(atomTag, data), Executors.newSingleThreadExecutor() ); @@ -356,6 +363,7 @@ public class StatsPullAtomService extends SystemService { addNetworkStats(atomTag, pulledData, stats, false); } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); + return StatsManager.PULL_SKIP; } finally { Binder.restoreCallingIdentity(token); } @@ -382,36 +390,224 @@ public class StatsPullAtomService extends SystemService { } } + /** + * Allows rollups per UID but keeping the set (foreground/background) slicing. + * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java + */ + private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { + final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); + + final NetworkStats.Entry entry = new NetworkStats.Entry(); + entry.iface = NetworkStats.IFACE_ALL; + entry.tag = NetworkStats.TAG_NONE; + entry.metered = NetworkStats.METERED_ALL; + entry.roaming = NetworkStats.ROAMING_ALL; + + int size = stats.size(); + NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values + for (int i = 0; i < size; i++) { + stats.getValues(i, recycle); + + // Skip specific tags, since already counted in TAG_NONE + if (recycle.tag != NetworkStats.TAG_NONE) continue; + + entry.set = recycle.set; // Allows slicing by background/foreground + entry.uid = recycle.uid; + entry.rxBytes = recycle.rxBytes; + entry.rxPackets = recycle.rxPackets; + entry.txBytes = recycle.txBytes; + entry.txPackets = recycle.txPackets; + // Operations purposefully omitted since we don't use them for statsd. + ret.combineValues(entry); + } + return ret; + } + private void registerWifiBytesTransferBackground() { - // No op. + int tagId = StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {3, 4, 5, 6}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullWifiBytesTransferBackground(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullWifiBytesTransferBackground() { - // No op. + private int pullWifiBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getWifiIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + NetworkStats stats = rollupNetworkStatsByFGBG( + networkStatsService.getDetailedUidStats(ifaces)); + addNetworkStats(atomTag, pulledData, stats, true); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerMobileBytesTransfer() { - // No op. + int tagId = StatsLog.MOBILE_BYTES_TRANSFER; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3, 4, 5}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullMobileBytesTransfer(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullMobileBytesTransfer() { - // No op. + private int pullMobileBytesTransfer(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getMobileIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + // Combine all the metrics per Uid into one record. + NetworkStats stats = networkStatsService.getDetailedUidStats(ifaces).groupedByUid(); + addNetworkStats(atomTag, pulledData, stats, false); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerMobileBytesTransferBackground() { - // No op. + int tagId = StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {3, 4, 5, 6}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullMobileBytesTransferBackground(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullMobileBytesTransferBackground() { - // No op. + private int pullMobileBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getMobileIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + NetworkStats stats = rollupNetworkStatsByFGBG( + networkStatsService.getDetailedUidStats(ifaces)); + addNetworkStats(atomTag, pulledData, stats, true); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerBluetoothBytesTransfer() { - // No op. + int tagId = StatsLog.BLUETOOTH_BYTES_TRANSFER; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullBluetoothBytesTransfer(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullBluetoothBytesTransfer() { - // No op. + /** + * Helper method to extract the Parcelable controller info from a + * SynchronousResultReceiver. + */ + private static <T extends Parcelable> T awaitControllerInfo( + @Nullable SynchronousResultReceiver receiver) { + if (receiver == null) { + return null; + } + + try { + final SynchronousResultReceiver.Result result = + receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); + if (result.bundle != null) { + // This is the final destination for the Bundle. + result.bundle.setDefusable(true); + + final T data = result.bundle.getParcelable(RESULT_RECEIVER_CONTROLLER_KEY); + if (data != null) { + return data; + } + } + Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); + } catch (TimeoutException e) { + Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); + } + return null; + } + + private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { + // TODO: Investigate whether the synchronized keyword is needed. + final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( + "bluetooth"); + adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); + return awaitControllerInfo(bluetoothReceiver); + } else { + Slog.e(TAG, "Failed to get bluetooth adapter!"); + return null; + } + } + + private int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) { + BluetoothActivityEnergyInfo info = fetchBluetoothData(); + if (info == null || info.getUidTraffic() == null) { + return StatsManager.PULL_SKIP; + } + for (UidTraffic traffic : info.getUidTraffic()) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(traffic.getUid()) + .writeLong(traffic.getRxBytes()) + .writeLong(traffic.getTxBytes()) + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; } private void registerKernelWakelock() { @@ -479,11 +675,31 @@ public class StatsPullAtomService extends SystemService { } private void registerBluetoothActivityInfo() { - // No op. + int tagId = StatsLog.BLUETOOTH_ACTIVITY_INFO; + mStatsManager.registerPullAtomCallback( + tagId, + /* metadata */ null, + (atomTag, data) -> pullBluetoothActivityInfo(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullBluetoothActivityInfo() { - // No op. + private int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) { + BluetoothActivityEnergyInfo info = fetchBluetoothData(); + if (info == null) { + return StatsManager.PULL_SKIP; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeLong(info.getTimeStamp()) + .writeInt(info.getBluetoothStackState()) + .writeLong(info.getControllerTxTimeMillis()) + .writeLong(info.getControllerRxTimeMillis()) + .writeLong(info.getControllerIdleTimeMillis()) + .writeLong(info.getControllerEnergyUsed()) + .build(); + pulledData.add(e); + return StatsManager.PULL_SUCCESS; } private void registerSystemElapsedRealtime() { @@ -695,11 +911,26 @@ public class StatsPullAtomService extends SystemService { } private void registerPowerProfile() { - // No op. + int tagId = StatsLog.POWER_PROFILE; + mStatsManager.registerPullAtomCallback( + tagId, + /* PullAtomMetadata */ null, + (atomTag, data) -> pullPowerProfile(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullPowerProfile() { - // No op. + private int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) { + PowerProfile powerProfile = new PowerProfile(mContext); + ProtoOutputStream proto = new ProtoOutputStream(); + powerProfile.dumpDebug(proto); + proto.flush(); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeByteArray(proto.getBytes()) + .build(); + pulledData.add(e); + return StatsManager.PULL_SUCCESS; } private void registerProcessCpuTime() { diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 5b58199aec4f..eb7c5caa62aa 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -127,6 +127,9 @@ public final class TvInputManagerService extends SystemService { // A map from user id to UserState. private final SparseArray<UserState> mUserStates = new SparseArray<>(); + // A map from session id to session state saved in userstate + private final Map<String, SessionState> mSessionIdToSessionStateMap = new HashMap<>(); + private final WatchLogHandler mWatchLogHandler; public TvInputManagerService(Context context) { @@ -632,7 +635,8 @@ public final class TvInputManagerService extends SystemService { UserState userState = getOrCreateUserStateLocked(userId); SessionState sessionState = userState.sessionStateMap.get(sessionToken); if (DEBUG) { - Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.inputId + ")"); + Slog.d(TAG, "createSessionInternalLocked(inputId=" + + sessionState.inputId + ", sessionId=" + sessionState.sessionId + ")"); } InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString()); @@ -643,9 +647,11 @@ public final class TvInputManagerService extends SystemService { // Create a session. When failed, send a null token immediately. try { if (sessionState.isRecordingSession) { - service.createRecordingSession(callback, sessionState.inputId); + service.createRecordingSession( + callback, sessionState.inputId, sessionState.sessionId); } else { - service.createSession(channels[1], callback, sessionState.inputId); + service.createSession( + channels[1], callback, sessionState.inputId, sessionState.sessionId); } } catch (RemoteException e) { Slog.e(TAG, "error in createSession", e); @@ -715,6 +721,8 @@ public final class TvInputManagerService extends SystemService { } } + mSessionIdToSessionStateMap.remove(sessionState.sessionId); + ServiceState serviceState = userState.serviceStateMap.get(sessionState.componentName); if (serviceState != null) { serviceState.sessionTokens.remove(sessionToken); @@ -1156,9 +1164,11 @@ public final class TvInputManagerService extends SystemService { public void createSession(final ITvInputClient client, final String inputId, boolean isRecordingSession, int seq, int userId) { final int callingUid = Binder.getCallingUid(); - final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + final int callingPid = Binder.getCallingPid(); + final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, "createSession"); final long identity = Binder.clearCallingIdentity(); + StringBuilder sessionId = new StringBuilder(); try { synchronized (mLock) { if (userId != mCurrentUserId && !isRecordingSession) { @@ -1187,15 +1197,21 @@ public final class TvInputManagerService extends SystemService { return; } + // Create a unique session id with pid, uid and resolved user id + sessionId.append(callingUid).append(callingPid).append(resolvedUserId); + // Create a new session token and a session state. IBinder sessionToken = new Binder(); SessionState sessionState = new SessionState(sessionToken, info.getId(), info.getComponent(), isRecordingSession, client, seq, callingUid, - resolvedUserId); + callingPid, resolvedUserId, sessionId.toString()); // Add them to the global session state map of the current user. userState.sessionStateMap.put(sessionToken, sessionState); + // Map the session id to the sessionStateMap in the user state + mSessionIdToSessionStateMap.put(sessionId.toString(), sessionState); + // Also, add them to the session state map of the current service. serviceState.sessionTokens.add(sessionToken); @@ -2003,6 +2019,43 @@ public final class TvInputManagerService extends SystemService { } @Override + public int getClientPid(String sessionId) { + ensureTunerResourceAccessPermission(); + final long identity = Binder.clearCallingIdentity(); + + int clientPid = TvInputManager.UNKNOWN_CLIENT_PID; + try { + synchronized (mLock) { + try { + clientPid = getClientPidLocked(sessionId); + } catch (ClientPidNotFoundException e) { + Slog.e(TAG, "error in getClientPid", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + return clientPid; + } + + private int getClientPidLocked(String sessionId) + throws IllegalStateException { + if (mSessionIdToSessionStateMap.get(sessionId) == null) { + throw new IllegalStateException("Client Pid not found with sessionId " + + sessionId); + } + return mSessionIdToSessionStateMap.get(sessionId).callingPid; + } + + private void ensureTunerResourceAccessPermission() { + if (mContext.checkCallingPermission( + android.Manifest.permission.TUNER_RESOURCE_ACCESS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires TUNER_RESOURCE_ACCESS permission"); + } + } + + @Override @SuppressWarnings("resource") protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -2094,9 +2147,11 @@ public final class TvInputManagerService extends SystemService { pw.increaseIndent(); pw.println("inputId: " + session.inputId); + pw.println("sessionId: " + session.sessionId); pw.println("client: " + session.client); pw.println("seq: " + session.seq); pw.println("callingUid: " + session.callingUid); + pw.println("callingPid: " + session.callingPid); pw.println("userId: " + session.userId); pw.println("sessionToken: " + session.sessionToken); pw.println("session: " + session.session); @@ -2226,11 +2281,13 @@ public final class TvInputManagerService extends SystemService { private final class SessionState implements IBinder.DeathRecipient { private final String inputId; + private final String sessionId; private final ComponentName componentName; private final boolean isRecordingSession; private final ITvInputClient client; private final int seq; private final int callingUid; + private final int callingPid; private final int userId; private final IBinder sessionToken; private ITvInputSession session; @@ -2240,7 +2297,7 @@ public final class TvInputManagerService extends SystemService { private SessionState(IBinder sessionToken, String inputId, ComponentName componentName, boolean isRecordingSession, ITvInputClient client, int seq, int callingUid, - int userId) { + int callingPid, int userId, String sessionId) { this.sessionToken = sessionToken; this.inputId = inputId; this.componentName = componentName; @@ -2248,7 +2305,9 @@ public final class TvInputManagerService extends SystemService { this.client = client; this.seq = seq; this.callingUid = callingUid; + this.callingPid = callingPid; this.userId = userId; + this.sessionId = sessionId; } @Override @@ -2962,4 +3021,10 @@ public final class TvInputManagerService extends SystemService { super(name); } } + + private static class ClientPidNotFoundException extends IllegalArgumentException { + public ClientPidNotFoundException(String name) { + super(name); + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 26d76a8d6e28..320be2d7cdbd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5934,7 +5934,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAnimationBoundsLayer = createAnimationBoundsLayer(t); // Crop to stack bounds. - t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); + if (!WindowManagerService.sHierarchicalAnimations) { + // For Hierarchical animation, we don't need to set window crop since the leash + // surface size has already same as the animating container. + t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); + } t.setLayer(mAnimationBoundsLayer, layer); // Reparent leash to animation bounds layer. @@ -5982,9 +5986,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } clearThumbnail(); + final Transaction transaction = getAnimatingContainer().getPendingTransaction(); mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, - getPendingTransaction(), this, thumbnailHeader); - mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader)); + transaction, getAnimatingContainer(), thumbnailHeader); + mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader)); } /** @@ -6011,13 +6016,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (thumbnail == null) { return; } + final Transaction transaction = getAnimatingContainer().getPendingTransaction(); mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, - getPendingTransaction(), this, thumbnail); + transaction, getAnimatingContainer(), thumbnail); final Animation animation = getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked( win.getFrameLw()); - mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left, - frame.top)); + mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top)); } private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f3880fa5dd09..c38868a2af84 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -42,6 +42,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.logWithStack; +import static com.android.server.wm.WindowManagerService.sHierarchicalAnimations; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import android.annotation.CallSuper; @@ -1855,7 +1856,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // TODO: Remove this and use #getBounds() instead once we set an app transition animation // on TaskStack. Rect getAnimationBounds(int appStackClipMode) { - return getBounds(); + return getDisplayedBounds(); } /** @@ -1929,7 +1930,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // Separate position and size for use in animators. mTmpRect.set(getAnimationBounds(appStackClipMode)); - mTmpPoint.set(mTmpRect.left, mTmpRect.top); + if (sHierarchicalAnimations) { + getRelativeDisplayedPosition(mTmpPoint); + } else { + mTmpPoint.set(mTmpRect.left, mTmpRect.top); + } mTmpRect.offsetTo(0, 0); final RemoteAnimationController controller = diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index acb6bea53a62..00436bb8ca70 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -204,6 +204,7 @@ struct GnssDeathRecipient : virtual public hidl_death_recipient // Must match the value from GnssMeasurement.java static const uint32_t ADR_STATE_HALF_CYCLE_REPORTED = (1<<4); +static const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1<<4); sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr; sp<IGnss_V1_0> gnssHal = nullptr; @@ -634,6 +635,16 @@ private: template<class T> Return<void> gnssSvStatusCbImpl(const T& svStatus); + template<class T> + uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) { + return 0; + } + + template<class T> + double getBasebandCn0DbHz(const T& svStatus, size_t i) { + return 0.0; + } + uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) { return svStatus.numSvs; } @@ -658,8 +669,6 @@ private: const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex( const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) { - // TODO(b/144850155): fill baseband CN0 after it's available in Java object. - ALOGD("getGnssSvInfoOfIndex %d: baseband C/N0: %f", (int) i, svInfoList[i].basebandCN0DbHz); return svInfoList[i].v2_0.v1_0; } @@ -721,6 +730,18 @@ Return<void> GnssCallback::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValu return Void(); } +template<> +uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& + svStatus) { + return SVID_FLAGS_HAS_BASEBAND_CN0; +} + +template<> +double GnssCallback::getBasebandCn0DbHz(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, + size_t i) { + return svInfoList[i].basebandCN0DbHz; +} + template<class T> Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { JNIEnv* env = getJniEnv(); @@ -758,8 +779,8 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { elev[i] = info.elevationDegrees; azim[i] = info.azimuthDegrees; carrierFreq[i] = info.carrierFrequencyHz; - // TODO(b/144850155): fill svidWithFlags with hasBasebandCn0DbHz based on HAL versions - basebandCn0s[i] = 0.0; + svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus); + basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i); } env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0); @@ -1185,8 +1206,8 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement const IGnssMeasurementCallback_V2_1::GnssMeasurement* measurement_V2_1, JavaObject& object) { translateSingleGnssMeasurement(&(measurement_V2_1->v2_0), object); - // TODO(b/144850155): fill baseband CN0 after it's available in Java object - ALOGD("baseband CN0DbHz = %f\n", measurement_V2_1->basebandCN0DbHz); + + SET(BasebandCn0DbHz, measurement_V2_1->basebandCN0DbHz); } template<class T> diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 4696dd0bb88b..0275f3ea32f7 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -33,7 +33,6 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" -using android::bpf::Stats; using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 3592e5f1200a..24d3bb63fe7e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -23,7 +23,6 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; -import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER; @@ -129,6 +128,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DeviceStateCache; +import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; import android.app.admin.PasswordPolicy; @@ -268,6 +268,7 @@ import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.PasswordValidationError; import com.android.server.LocalServices; import com.android.server.LockGuard; +import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.SystemServerInitThreadPool; import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; @@ -1006,6 +1007,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL = "cross-profile-calendar-packages-null"; private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages"; + private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = + "factory_reset_protection_policy"; DeviceAdminInfo info; @@ -1016,6 +1019,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @NonNull PasswordPolicy mPasswordPolicy = new PasswordPolicy(); + @Nullable + FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null; + static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; @@ -1351,6 +1357,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mCrossProfileCalendarPackages); } writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages); + if (mFactoryResetProtectionPolicy != null) { + out.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + mFactoryResetProtectionPolicy.writeToXml(out); + out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + } } void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { @@ -1584,6 +1595,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mCrossProfileCalendarPackages = null; } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) { mCrossProfilePackages = readPackageList(parser, tag); + } else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) { + mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml( + parser); } else { Slog.w(LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -2036,6 +2050,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE)); } + PersistentDataBlockManagerInternal getPersistentDataBlockManagerInternal() { + return LocalServices.getService(PersistentDataBlockManagerInternal.class); + } + LockSettingsInternal getLockSettingsInternal() { return LocalServices.getService(LockSettingsInternal.class); } @@ -4099,6 +4117,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); } + // When a device owner is set, the system automatically restricts adding a managed profile. + // Remove this restriction when the device owner is cleared. + if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, userHandle)) { + mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false, + userHandle); + } } /** @@ -6736,6 +6760,67 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public void setFactoryResetProtectionPolicy(ComponentName who, + @Nullable FactoryResetProtectionPolicy policy) { + if (!mHasFeature) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + + final int frpManagementAgentUid = getFrpManagementAgentUidOrThrow(); + final int userId = mInjector.userHandleGetCallingUserId(); + synchronized (getLockObject()) { + ActiveAdmin admin = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER); + admin.mFactoryResetProtectionPolicy = policy; + saveSettingsLocked(userId); + } + + mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser( + new Intent(DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), + UserHandle.getUserHandleForUid(frpManagementAgentUid))); + + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION) + .setAdmin(who) + .write(); + } + + @Override + public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy( + @Nullable ComponentName who) { + if (!mHasFeature) { + return null; + } + + final int frpManagementAgentUid = getFrpManagementAgentUidOrThrow(); + ActiveAdmin admin; + synchronized (getLockObject()) { + if (who == null) { + if ((frpManagementAgentUid != mInjector.binderGetCallingUid())) { + throw new SecurityException( + "Must be called by the FRP management agent on device"); + } + admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked( + UserHandle.getUserId(frpManagementAgentUid)); + } else { + admin = getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER); + } + } + return admin != null ? admin.mFactoryResetProtectionPolicy : null; + } + + private int getFrpManagementAgentUidOrThrow() { + PersistentDataBlockManagerInternal pdb = mInjector.getPersistentDataBlockManagerInternal(); + if ((pdb == null) || (pdb.getAllowedUid() == -1)) { + throw new UnsupportedOperationException( + "The persistent data block service is not supported on this device"); + } + return pdb.getAllowedUid(); + } + + @Override public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) { if (!mHasFeature) { return; @@ -7976,10 +8061,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updateDeviceOwnerLocked(); setDeviceOwnerSystemPropertyLocked(); - // TODO Send to system too? - mInjector.binderWithCleanCallingIdentity( - () -> sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, - userId)); + mInjector.binderWithCleanCallingIdentity(() -> { + // Restrict adding a managed profile when a device owner is set on the device. + // That is to prevent the co-existence of a managed profile and a device owner + // on the same device. + // Instead, the device may be provisioned with an organization-owned managed + // profile, such that the admin on that managed profile has extended management + // capabilities that can affect the entire device (but not access private data + // on the primary profile). + mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true, + UserHandle.of(userId)); + // TODO Send to system too? + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId); + }); mDeviceAdminServiceController.startServiceForOwner( admin.getPackageName(), userId, "set-device-owner"); @@ -8131,6 +8225,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } + ActiveAdmin getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(int userId) { + ActiveAdmin admin = getDeviceOwnerAdminLocked(); + if (admin == null) { + admin = getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); + } + return admin; + } + @Override public void clearDeviceOwner(String packageName) { Objects.requireNonNull(packageName, "packageName is null"); @@ -8234,6 +8336,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new IllegalArgumentException("Not active admin: " + who); } + UserInfo parentUser = mUserManager.getProfileParent(userHandle); + // When trying to set a profile owner on a new user, it may be that this user is + // a profile - but it may not be a managed profile if there's a restriction on the + // parent to add managed profiles (e.g. if the device has a device owner). + if (parentUser != null && mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserHandle.of(parentUser.id))) { + Slog.i(LOG_TAG, "Cannot set profile owner because of restriction."); + return false; + } + if (isAdb()) { // Log profile owner provisioning was started using adb. MetricsLogger.action(mContext, PROVISIONING_ENTRY_POINT_ADB, LOG_TAG_PROFILE_OWNER); @@ -12299,25 +12412,41 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long ident = mInjector.binderClearCallingIdentity(); try { final UserHandle callingUserHandle = UserHandle.of(callingUserId); - final ComponentName ownerAdmin = getOwnerComponent(packageName, callingUserId); - if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, - callingUserHandle)) { - // An admin can initiate provisioning if it has set the restriction. - if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin, - UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) { - return CODE_ADD_MANAGED_PROFILE_DISALLOWED; - } - } - boolean canRemoveProfile = true; - if (mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, - callingUserHandle)) { - // We can remove a profile if the admin itself has set the restriction. - if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin, - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, - callingUserId)) { - canRemoveProfile = false; - } + final boolean hasDeviceOwner; + synchronized (getLockObject()) { + hasDeviceOwner = getDeviceOwnerAdminLocked() != null; + } + + final boolean addingProfileRestricted = mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle); + + UserInfo parentUser = mUserManager.getProfileParent(callingUserId); + final boolean addingProfileRestrictedOnParent = (parentUser != null) + && mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserHandle.of(parentUser.id)); + + Slog.i(LOG_TAG, String.format( + "When checking for managed profile provisioning: Has device owner? %b, adding" + + " profile restricted? %b, adding profile restricted on parent? %b", + hasDeviceOwner, addingProfileRestricted, addingProfileRestrictedOnParent)); + + // If there's a device owner, the restriction on adding a managed profile must be set + // somewhere. + if (hasDeviceOwner && !addingProfileRestricted && !addingProfileRestrictedOnParent) { + Slog.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile."); + } + + // Do not allow adding a managed profile if there's a restriction, either on the current + // user or its parent user. + if (addingProfileRestricted || addingProfileRestrictedOnParent) { + return CODE_CANNOT_ADD_MANAGED_PROFILE; } + // If there's a restriction on removing the managed profile then we have to take it + // into account when checking whether more profiles can be added. + boolean canRemoveProfile = + !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, + callingUserHandle); if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) { return CODE_CANNOT_ADD_MANAGED_PROFILE; } diff --git a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java b/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java index a8a258fc5ff7..9c5d4ad6ceeb 100644 --- a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java +++ b/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java @@ -3,6 +3,7 @@ package com.android.server.location; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import android.os.Looper; import android.os.SystemClock; @@ -52,8 +53,10 @@ public class NtpTimeHelperTest { @Test public void handleInjectNtpTime_cachedAgeLow_injectTime() throws InterruptedException { - doReturn(NtpTimeHelper.NTP_INTERVAL - 1).when(mMockNtpTrustedTime).getCacheAge(); - doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime(); + NtpTrustedTime.TimeResult result = mock(NtpTrustedTime.TimeResult.class); + doReturn(NtpTimeHelper.NTP_INTERVAL - 1).when(result).getAgeMillis(); + doReturn(MOCK_NTP_TIME).when(result).getTimeMillis(); + doReturn(result).when(mMockNtpTrustedTime).getCachedTimeResult(); mNtpTimeHelper.retrieveAndInjectNtpTime(); @@ -64,7 +67,9 @@ public class NtpTimeHelperTest { @Test public void handleInjectNtpTime_injectTimeFailed_injectTimeDelayed() throws InterruptedException { - doReturn(NtpTimeHelper.NTP_INTERVAL + 1).when(mMockNtpTrustedTime).getCacheAge(); + NtpTrustedTime.TimeResult result1 = mock(NtpTrustedTime.TimeResult.class); + doReturn(NtpTimeHelper.NTP_INTERVAL + 1).when(result1).getAgeMillis(); + doReturn(result1).when(mMockNtpTrustedTime).getCachedTimeResult(); doReturn(false).when(mMockNtpTrustedTime).forceRefresh(); mNtpTimeHelper.retrieveAndInjectNtpTime(); @@ -72,8 +77,10 @@ public class NtpTimeHelperTest { assertThat(mCountDownLatch.await(2, TimeUnit.SECONDS)).isFalse(); doReturn(true).when(mMockNtpTrustedTime).forceRefresh(); - doReturn(1L).when(mMockNtpTrustedTime).getCacheAge(); - doReturn(MOCK_NTP_TIME).when(mMockNtpTrustedTime).getCachedNtpTime(); + NtpTrustedTime.TimeResult result2 = mock(NtpTrustedTime.TimeResult.class); + doReturn(1L).when(result2).getAgeMillis(); + doReturn(MOCK_NTP_TIME).when(result2).getTimeMillis(); + doReturn(result2).when(mMockNtpTrustedTime).getCachedTimeResult(); SystemClock.sleep(NtpTimeHelper.RETRY_INTERVAL); waitForTasksToBePostedOnHandlerAndRunThem(); diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index 556f96ace5d2..6a5de84266e2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -345,8 +345,8 @@ public class AlarmManagerServiceTest { } /** - * Lowers quotas to make testing feasible. - * Careful while calling as this will replace any existing settings for the calling test. + * Lowers quotas to make testing feasible. Careful while calling as this will replace any + * existing settings for the calling test. */ private void setTestableQuotas() { final StringBuilder constantsBuilder = new StringBuilder(); @@ -981,6 +981,25 @@ public class AlarmManagerServiceTest { assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); } + @Test + public void alarmCountOnListenerBinderDied() { + final int numAlarms = 10; + final IAlarmListener[] listeners = new IAlarmListener[numAlarms]; + for (int i = 0; i < numAlarms; i++) { + listeners[i] = new IAlarmListener.Stub() { + @Override + public void doAlarm(IAlarmCompleteListener callback) throws RemoteException { + } + }; + setTestAlarmWithListener(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i, listeners[i]); + } + assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + for (int i = 0; i < numAlarms; i++) { + mService.mListenerDeathRecipient.binderDied(listeners[i].asBinder()); + assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); + } + } + @After public void tearDown() { if (mMockingSession != null) { diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index 0f11566f512c..39a3aae767ea 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -212,7 +212,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE}; when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list); - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(6, accounts.length); assertEquals(a11, accounts[0]); @@ -222,8 +223,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { assertEquals(a22, accounts[4]); assertEquals(a32, accounts[5]); - accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, - mContext.getOpPackageName()); + accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(3, accounts.length); assertEquals(a11, accounts[0]); @@ -232,8 +233,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { mAms.removeAccountInternal(a21); - accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, - mContext.getOpPackageName()); + accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(2, accounts.length); assertEquals(a11, accounts[0]); @@ -373,7 +374,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { unlockSystemUser(); String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE}; when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list); - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, UserHandle.getCallingUserId(), + mContext.getOpPackageName()); assertEquals("1 account should be migrated", 1, accounts.length); assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name); assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0])); @@ -2980,7 +2982,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { Log.d(TAG, logPrefix + " getAccounts started"); long ti = System.currentTimeMillis(); try { - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); if (accounts == null || accounts.length != 1 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals( accounts[0].type)) { @@ -3051,7 +3054,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { Log.d(TAG, logPrefix + " getAccounts started"); long ti = System.currentTimeMillis(); try { - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); if (accounts == null || accounts.length != 1 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals( accounts[0].type)) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index ac555fda2204..3a8258be5f01 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -51,6 +51,7 @@ import androidx.annotation.NonNull; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; +import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import java.io.File; @@ -223,6 +224,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + PersistentDataBlockManagerInternal getPersistentDataBlockManagerInternal() { + return services.persistentDataBlockManagerInternal; + } + + @Override Looper getMyLooper() { return Looper.getMainLooper(); } 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 20cb4497e08f..45729e5fd41f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -31,7 +31,10 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.server.testutils.TestUtils.assertExpectException; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -62,6 +65,7 @@ import android.app.Notification; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.FactoryResetProtectionPolicy; import android.app.admin.PasswordMetrics; import android.app.timedetector.ManualTimeSuggestion; import android.app.timezonedetector.ManualTimeZoneSuggestion; @@ -272,6 +276,29 @@ public class DevicePolicyManagerTest extends DpmTestBase { }).when(getServices().userManager).getApplicationRestrictions( anyString(), any(UserHandle.class)); + // Emulate UserManager.setUserRestriction/getUserRestrictions + final Map<UserHandle, Bundle> userRestrictions = new HashMap<>(); + + doAnswer((Answer<Void>) invocation -> { + String key = (String) invocation.getArguments()[0]; + boolean value = (Boolean) invocation.getArguments()[1]; + UserHandle user = (UserHandle) invocation.getArguments()[2]; + Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle()); + userBundle.putBoolean(key, value); + + userRestrictions.put(user, userBundle); + return null; + }).when(getServices().userManager).setUserRestriction( + anyString(), anyBoolean(), any(UserHandle.class)); + + doAnswer((Answer<Boolean>) invocation -> { + String key = (String) invocation.getArguments()[0]; + UserHandle user = (UserHandle) invocation.getArguments()[1]; + Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle()); + return userBundle.getBoolean(key); + }).when(getServices().userManager).hasUserRestriction( + anyString(), any(UserHandle.class)); + // Add the first secondary user. getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, UserManager.USER_TYPE_FULL_SECONDARY); @@ -819,10 +846,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); - // Setup device owner. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); - setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); @@ -830,18 +855,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Change the parent user's password. dpm.reportPasswordChanged(UserHandle.USER_SYSTEM); - // Both the device owner and the managed profile owner should receive this broadcast. + // The managed profile owner should receive this broadcast. final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED); intent.setComponent(admin1); intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntent(intent), - MockUtils.checkUserHandle(UserHandle.USER_SYSTEM), - eq(null), - any(Bundle.class)); - verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( - MockUtils.checkIntent(intent), MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID), eq(null), any(Bundle.class)); @@ -861,12 +881,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); - // Setup device owner. + // Configure system as having separate profile challenge. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); doReturn(true).when(getServices().lockPatternUtils) .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID); - setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); @@ -951,6 +970,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); + verify(getServices().userManager, times(1)).setUserRestriction( + eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), + eq(true), eq(UserHandle.SYSTEM)); + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); @@ -2002,12 +2025,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertNoDeviceOwnerRestrictions(); - // Initialize DPMS again and check that the user restriction wasn't enabled again. reset(getServices().userManagerInternal); - initializeDpms(); - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertNotNull(dpms.getDeviceOwnerAdminLocked()); + // Ensure the DISALLOW_REMOVE_MANAGED_PROFILES restriction doesn't show up as a + // restriction to the device owner. + dpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE); assertNoDeviceOwnerRestrictions(); } @@ -2022,6 +2044,116 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); } + public void testSetFactoryResetProtectionPolicyWithDO() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + + when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn( + DpmMockContext.CALLER_UID); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionAccounts(new ArrayList<>()) + .setFactoryResetProtectionDisabled(true) + .build(); + dpm.setFactoryResetProtectionPolicy(admin1, policy); + + FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(admin1); + assertThat(result).isEqualTo(policy); + assertPoliciesAreEqual(policy, result); + + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testSetFactoryResetProtectionPolicyFailWithPO() throws Exception { + setupProfileOwner(); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionDisabled(true) + .build(); + + assertExpectException(SecurityException.class, null, + () -> dpm.setFactoryResetProtectionPolicy(admin1, policy)); + } + + public void testSetFactoryResetProtectionPolicyWithPOOfOrganizationOwnedDevice() + throws Exception { + setupProfileOwner(); + configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE); + + when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn( + DpmMockContext.CALLER_UID); + + List<String> accounts = new ArrayList<>(); + accounts.add("Account 1"); + accounts.add("Account 2"); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionAccounts(accounts) + .build(); + + dpm.setFactoryResetProtectionPolicy(admin1, policy); + + FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(admin1); + assertThat(result).isEqualTo(policy); + assertPoliciesAreEqual(policy, result); + + verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testGetFactoryResetProtectionPolicyWithFrpManagementAgent() + throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + when(getServices().persistentDataBlockManagerInternal.getAllowedUid()).thenReturn( + DpmMockContext.CALLER_UID); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionAccounts(new ArrayList<>()) + .setFactoryResetProtectionDisabled(true) + .build(); + + dpm.setFactoryResetProtectionPolicy(admin1, policy); + + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + dpm.setActiveAdmin(admin1, /*replace=*/ false); + FactoryResetProtectionPolicy result = dpm.getFactoryResetProtectionPolicy(null); + assertThat(result).isEqualTo(policy); + assertPoliciesAreEqual(policy, result); + + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + } + + private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy, + FactoryResetProtectionPolicy actualPolicy) { + assertThat(actualPolicy.isFactoryResetProtectionDisabled()).isEqualTo( + expectedPolicy.isFactoryResetProtectionDisabled()); + assertAccountsAreEqual(expectedPolicy.getFactoryResetProtectionAccounts(), + actualPolicy.getFactoryResetProtectionAccounts()); + } + + private void assertAccountsAreEqual(List<String> expectedAccounts, + List<String> actualAccounts) { + assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts); + } + public void testGetMacAddress() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -2993,7 +3125,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_nonSplitUser_withDo_primaryUser(); final int MANAGED_PROFILE_USER_ID = 18; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308); - addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false /* we can't remove a managed profile */)).thenReturn(false); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, @@ -3045,41 +3176,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false); - // COMP mode is allowed. + // COMP mode NOT is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); - - // And other DPCs can also provision a managed profile (DO + BYOD case). - assertCheckProvisioningPreCondition( - DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, - DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); - } + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); - public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception { - setup_nonSplitUser_withDo_primaryUser(); - mContext.packageName = admin1.getPackageName(); - mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); - // The DO should be allowed to initiate provisioning if it set the restriction itself, but - // other packages should be forbidden. - when(getServices().userManager.hasUserRestriction( - eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), - eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) - .thenReturn(true); - when(getServices().userManager.getUserRestrictionSource( - eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), - eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) - .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); - assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + // And other DPCs can NOT provision a managed profile. assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } @@ -3100,31 +3206,46 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } - public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception { + public void testCheckCannotSetProfileOwnerWithDeviceOwner() throws Exception { + setup_nonSplitUser_withDo_primaryUser(); + final int managedProfileUserId = 18; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 1308); + + final int userId = UserHandle.getUserId(managedProfileAdminUid); + getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED, + UserHandle.USER_SYSTEM); + mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); + setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1); + dpm.setActiveAdmin(admin1, false, userId); + assertFalse(dpm.setProfileOwner(admin1, null, userId)); + mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); + } + + public void testCheckProvisioningPreCondition_nonSplitUser_attemptingComp() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // We can delete the managed profile to create a new one, so provisioning is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } @@ -3152,8 +3273,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { // But the device owner can still do it because it has set the restriction itself. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } private void setup_splitUser_firstBoot_systemUser() throws Exception { @@ -3362,6 +3483,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); + when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); @@ -3374,7 +3497,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); mContext.packageName = admin1.getPackageName(); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser() @@ -3382,9 +3505,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); - // COMP mode is allowed. + // COMP mode is NOT allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); } private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { @@ -3901,11 +4024,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); - // Setup a managed profile managed by the same admin. - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); - // Add a secondary user, it should never talk with. final int ANOTHER_USER_ID = 36; getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY); @@ -3915,30 +4033,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertEmpty(targetUsers); - // Setting affiliation ids final Set<String> userAffiliationIds = Collections.singleton("some.affiliation-id"); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; dpm.setAffiliationIds(admin1, userAffiliationIds); - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(admin1, userAffiliationIds); - - // Calling from device owner admin, the result list should just contain the managed - // profile user id. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID)); - - // Calling from managed profile admin, the result list should just contain the system - // user id. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM); - // Changing affiliation ids in one dpm.setAffiliationIds(admin1, Collections.singleton("some-different-affiliation-id")); @@ -3952,38 +4051,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { MoreAsserts.assertEmpty(targetUsers); } - public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception { - // Setup a device owner. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - setupDeviceOwner(); - - // Set up a managed profile managed by different package. - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - final ComponentName adminDifferentPackage = - new ComponentName("another.package", "whatever.class"); - addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); - - // Setting affiliation ids - final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id"); - dpm.setAffiliationIds(admin1, userAffiliationIds); - - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); - - // Calling from device owner admin, we should get zero bind device admin target users as - // their packages are different. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertEmpty(targetUsers); - - // Calling from managed profile admin, we should still get zero target users for the same - // reason. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage); - MoreAsserts.assertEmpty(targetUsers); - } - private void verifyLockTaskState(int userId) throws Exception { verifyLockTaskState(userId, new String[0], DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS); @@ -4020,79 +4087,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setLockTaskFeatures(who, flags)); } - public void testLockTaskPolicyAllowedForAffiliatedUsers() throws Exception { - // Setup a device owner. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - setupDeviceOwner(); - // Lock task policy is updated when loading user data. - verifyLockTaskState(UserHandle.USER_SYSTEM); - - // Set up a managed profile managed by different package (package name shouldn't matter) - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - final ComponentName adminDifferentPackage = - new ComponentName("another.package", "whatever.class"); - addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); - verifyLockTaskState(MANAGED_PROFILE_USER_ID); - - // Setup a PO on the secondary user - mContext.binder.callingUid = DpmMockContext.CALLER_UID; - setAsProfileOwner(admin3); - verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE); - - // The DO can still set lock task packages - final String[] doPackages = {"doPackage1", "doPackage2"}; - final int flags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanSetLockTask(DpmMockContext.CALLER_SYSTEM_USER_UID, UserHandle.USER_SYSTEM, admin1, doPackages, flags); - - final String[] secondaryPoPackages = {"secondaryPoPackage1", "secondaryPoPackage2"}; - final int secondaryPoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanNotSetLockTask(DpmMockContext.CALLER_UID, admin3, secondaryPoPackages, secondaryPoFlags); - - // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - final String[] poPackages = {"poPackage1", "poPackage2"}; - final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, poPackages, poFlags); - - // Setting same affiliation ids - final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id"); - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - dpm.setAffiliationIds(admin1, userAffiliationIds); - - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); - - // Now the managed profile can set lock task packages. - dpm.setLockTaskPackages(adminDifferentPackage, poPackages); - MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage)); - assertTrue(dpm.isLockTaskPermitted("poPackage1")); - assertFalse(dpm.isLockTaskPermitted("doPackage2")); - // And it can set lock task features. - dpm.setLockTaskFeatures(adminDifferentPackage, poFlags); - verifyLockTaskState(MANAGED_PROFILE_USER_ID, poPackages, poFlags); - - // Unaffiliate the profile, lock task mode no longer available on the profile. - dpm.setAffiliationIds(adminDifferentPackage, Collections.emptySet()); - assertFalse(dpm.isLockTaskPermitted("poPackage1")); - // Lock task packages cleared when loading user data and when the user becomes unaffiliated. - verify(getServices().iactivityManager, times(2)).updateLockTaskPackages( - MANAGED_PROFILE_USER_ID, new String[0]); - verify(getServices().iactivityTaskManager, times(2)).updateLockTaskFeatures( - MANAGED_PROFILE_USER_ID, DevicePolicyManager.LOCK_TASK_FEATURE_NONE); - - // Verify that lock task packages were not cleared for the DO - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - assertTrue(dpm.isLockTaskPermitted("doPackage1")); - - } - public void testLockTaskPolicyForProfileOwner() throws Exception { // Setup a PO mContext.binder.callingUid = DpmMockContext.CALLER_UID; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java new file mode 100644 index 000000000000..bc853c693b3a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2019 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.devicepolicy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.admin.FactoryResetProtectionPolicy; +import android.os.Parcel; +import android.util.Xml; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.FastXmlSerializer; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Unit tests for {@link android.app.admin.FactoryResetProtectionPolicy}. + * + * atest com.android.server.devicepolicy.FactoryResetProtectionPolicyTest + */ +@RunWith(AndroidJUnit4.class) +public class FactoryResetProtectionPolicyTest { + + private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = + "factory_reset_protection_policy"; + + @Test + public void testNonDefaultFactoryResetProtectionPolicyObject() throws Exception { + List<String> accounts = new ArrayList<>(); + accounts.add("Account 1"); + accounts.add("Account 2"); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionAccounts(accounts) + .setFactoryResetProtectionDisabled(true) + .build(); + + testParcelAndUnparcel(policy); + testSerializationAndDeserialization(policy); + } + + @Test + public void testInvalidXmlFactoryResetProtectionPolicyObject() throws Exception { + List<String> accounts = new ArrayList<>(); + accounts.add("Account 1"); + accounts.add("Account 2"); + + FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder() + .setFactoryResetProtectionAccounts(accounts) + .setFactoryResetProtectionDisabled(true) + .build(); + + testParcelAndUnparcel(policy); + testInvalidXmlSerializationAndDeserialization(policy); + } + + private void testParcelAndUnparcel(FactoryResetProtectionPolicy policy) { + Parcel parcel = Parcel.obtain(); + policy.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + FactoryResetProtectionPolicy actualPolicy = + FactoryResetProtectionPolicy.CREATOR.createFromParcel(parcel); + assertPoliciesAreEqual(policy, actualPolicy); + parcel.recycle(); + } + + private void testSerializationAndDeserialization(FactoryResetProtectionPolicy policy) + throws Exception { + ByteArrayOutputStream outStream = serialize(policy); + ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new InputStreamReader(inStream)); + assertEquals(XmlPullParser.START_TAG, parser.next()); + + assertPoliciesAreEqual(policy, policy.readFromXml(parser)); + } + + private void testInvalidXmlSerializationAndDeserialization(FactoryResetProtectionPolicy policy) + throws Exception { + ByteArrayOutputStream outStream = serialize(policy); + ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); + XmlPullParser parser = mock(XmlPullParser.class); + when(parser.next()).thenThrow(XmlPullParserException.class); + parser.setInput(new InputStreamReader(inStream)); + + // If deserialization fails, then null is returned. + assertNull(policy.readFromXml(parser)); + } + + private ByteArrayOutputStream serialize(FactoryResetProtectionPolicy policy) + throws IOException { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + final XmlSerializer outXml = new FastXmlSerializer(); + outXml.setOutput(outStream, StandardCharsets.UTF_8.name()); + outXml.startDocument(null, true); + outXml.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + policy.writeToXml(outXml); + outXml.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + outXml.endDocument(); + outXml.flush(); + return outStream; + } + + private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy, + FactoryResetProtectionPolicy actualPolicy) { + assertEquals(expectedPolicy.isFactoryResetProtectionDisabled(), + actualPolicy.isFactoryResetProtectionDisabled()); + assertAccountsAreEqual(expectedPolicy.getFactoryResetProtectionAccounts(), + actualPolicy.getFactoryResetProtectionAccounts()); + } + + private void assertAccountsAreEqual(List<String> expectedAccounts, + List<String> actualAccounts) { + assertEquals(expectedAccounts.size(), actualAccounts.size()); + for (int i = 0; i < expectedAccounts.size(); i++) { + assertEquals(expectedAccounts.get(i), actualAccounts.get(i)); + } + } + +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 919a3f6d7d1b..6c2c1446a459 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -68,6 +68,7 @@ import android.view.IWindowManager; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; +import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -117,6 +118,7 @@ public class MockSystemServices { public final TimeDetector timeDetector; public final TimeZoneDetector timeZoneDetector; public final KeyChain.KeyChainConnection keyChainConnection; + public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal; /** Note this is a partial mock, not a real mock. */ public final PackageManager packageManager; public final BuildMock buildMock = new BuildMock(); @@ -160,6 +162,7 @@ public class MockSystemServices { timeDetector = mock(TimeDetector.class); timeZoneDetector = mock(TimeZoneDetector.class); keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS); + persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class); // Package manager is huge, so we use a partial mock instead. packageManager = spy(realContext.getPackageManager()); diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java index dd69c6613ab2..5aed194773f5 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java @@ -185,7 +185,7 @@ public class IntegrityFileManagerTest { List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata); // Verify that we do not load all the rules and we have the necessary rules to evaluate. - assertThat(rulesFetched.size()).isEqualTo(170); + assertThat(rulesFetched.size()).isEqualTo(270); assertThat(rulesFetched) .containsAllOf( getPackageNameIndexedRule(installedPackageName), diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java index 1eb5eb51504a..4fa73028ece1 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/model/BitTrackedInputStreamTest.java @@ -121,6 +121,26 @@ public class BitTrackedInputStreamTest { } @Test + public void testBitTrackedInputStream_canReadMoreRules() throws IOException { + String packageName = "com.test.app"; + byte[] testInput = + getBytes( + IS_NOT_HASHED + + getBits(packageName.length(), VALUE_SIZE_BITS) + + getValueBits(packageName)); + + BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput); + assertThat(bitTrackedInputStream.canReadMoreRules(2)).isTrue(); + + // Read until the string parameter. + String stringValue = BinaryFileOperations.getStringValue(bitTrackedInputStream); + + // Verify that the read bytes are counted. + assertThat(stringValue).isEqualTo(packageName); + assertThat(bitTrackedInputStream.canReadMoreRules(2)).isFalse(); + } + + @Test public void testBitTrackedInputStream_moveCursorForwardFailsIfAlreadyRead() throws IOException { String packageName = "com.test.app"; byte[] testInput = diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java index 742952e056bc..291cfeea5bbc 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java @@ -115,7 +115,8 @@ public class RuleIndexingControllerTest { + getKeyValueString(START_INDEXING_KEY, 500) + getKeyValueString(END_INDEXING_KEY, 900) + getKeyValueString(START_INDEXING_KEY, 900) - + getKeyValueString(END_INDEXING_KEY, 945)); + + getKeyValueString(END_INDEXING_KEY, 945) + + getBits(1, 1)); ByteBuffer rule = ByteBuffer.allocate(stringBytes.length); rule.put(stringBytes); InputStream inputStream = new ByteArrayInputStream(rule.array()); @@ -152,7 +153,8 @@ public class RuleIndexingControllerTest { + getKeyValueString("888", 800) + getKeyValueString(END_INDEXING_KEY, 900) + getKeyValueString(START_INDEXING_KEY, 900) - + getKeyValueString(END_INDEXING_KEY, 945)); + + getKeyValueString(END_INDEXING_KEY, 945) + + getBits(1, 1)); ByteBuffer rule = ByteBuffer.allocate(stringBytes.length); rule.put(stringBytes); return new ByteArrayInputStream(rule.array()); diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index eb6698b0d479..bc2aac0acf10 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -135,15 +135,14 @@ public class RuleBinarySerializerTest { .isEqualTo(expectedRuleOutputStream.toByteArray()); ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream(); + String serializedIndexingBytes = + SERIALIZED_START_INDEXING_KEY + + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) + + SERIALIZED_END_INDEXING_KEY + + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */32); byte[] expectedIndexingBytes = - getBytes( - SERIALIZED_START_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) - + SERIALIZED_END_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ - 32)); - expectedIndexingOutputStream.write(expectedIndexingBytes); - expectedIndexingOutputStream.write(expectedIndexingBytes); + getBytes(serializedIndexingBytes + serializedIndexingBytes + + serializedIndexingBytes + getBits(1, 1)); expectedIndexingOutputStream.write(expectedIndexingBytes); assertThat(indexingOutputStream.toByteArray()) .isEqualTo(expectedIndexingOutputStream.toByteArray()); @@ -197,15 +196,16 @@ public class RuleBinarySerializerTest { + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) + SERIALIZED_END_INDEXING_KEY + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBitsForIndexed)); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBitsForIndexed)); String expectedIndexingBitsForUnindexed = SERIALIZED_START_INDEXING_KEY + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) + SERIALIZED_END_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length + getBytes( - expectedBits).length, /* numOfBits= */ 32); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBitsForUnindexed)); + + getBits(DEFAULT_FORMAT_VERSION_BYTES.length + + getBytes(expectedBits).length, /* numOfBits= */ 32); + expectedIndexingOutputStream.write(getBytes( + expectedIndexingBitsForIndexed + expectedIndexingBitsForIndexed + + expectedIndexingBitsForUnindexed + getBits(1, 1))); + assertThat(indexingOutputStream.toByteArray()) .isEqualTo(expectedIndexingOutputStream.toByteArray()); } @@ -564,7 +564,6 @@ public class RuleBinarySerializerTest { expectedIndexingBytesForPackageNameIndexed += SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBytesForPackageNameIndexed)); String expectedIndexingBytesForAppCertificateIndexed = SERIALIZED_START_INDEXING_KEY @@ -588,7 +587,6 @@ public class RuleBinarySerializerTest { expectedIndexingBytesForAppCertificateIndexed += SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBytesForAppCertificateIndexed)); String expectedIndexingBytesForUnindexed = SERIALIZED_START_INDEXING_KEY @@ -603,8 +601,11 @@ public class RuleBinarySerializerTest { expectedIndexingBytesForUnindexed += SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - expectedIndexingOutputStream.write(getBytes(expectedIndexingBytesForUnindexed)); - + expectedIndexingOutputStream.write( + getBytes(expectedIndexingBytesForPackageNameIndexed + + expectedIndexingBytesForAppCertificateIndexed + + expectedIndexingBytesForUnindexed + + getBits(1, 1))); assertThat(ruleOutputStream.toByteArray()) .isEqualTo(expectedOrderedRuleOutputStream.toByteArray()); diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java index 55fada44b99e..1674422f3af9 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java @@ -38,10 +38,8 @@ import org.junit.runners.JUnit4; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.TreeMap; /** Unit tests for {@link RuleIndexingDetailsIdentifier}. */ @RunWith(JUnit4.class) @@ -140,7 +138,7 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_PACKAGE_NAME); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); // Verify the resulting map content. assertThat(result.keySet()) @@ -157,7 +155,7 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_APP_CERTIFICATE); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); @@ -174,7 +172,7 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); @@ -189,7 +187,7 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); @@ -215,7 +213,7 @@ public class RuleIndexingDetailsIdentifierTest { List<Rule> ruleList = new ArrayList(); ruleList.add(negatedRule); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); @@ -225,7 +223,7 @@ public class RuleIndexingDetailsIdentifierTest { } @Test - public void getIndexType_allRulesTogetherInValidOrder() { + public void getIndexType_allRulesTogetherSplitCorrectly() { Rule packageNameRuleA = getRuleWithPackageName("aaa"); Rule packageNameRuleB = getRuleWithPackageName("bbb"); Rule packageNameRuleC = getRuleWithPackageName("ccc"); @@ -243,38 +241,20 @@ public class RuleIndexingDetailsIdentifierTest { ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); - Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); + Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); assertThat(result.keySet()) .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); // We check asserts this way to ensure ordering based on package name. assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc"); - Iterator<String> keySetIterator = result.get(PACKAGE_NAME_INDEXED).keySet().iterator(); - assertThat(keySetIterator.next()).isEqualTo("aaa"); - assertThat(keySetIterator.next()).isEqualTo("bbb"); - assertThat(keySetIterator.next()).isEqualTo("ccc"); - assertThat(result.get(PACKAGE_NAME_INDEXED).get("aaa")).containsExactly(packageNameRuleA); - assertThat(result.get(PACKAGE_NAME_INDEXED).get("bbb")).containsExactly(packageNameRuleB); - assertThat(result.get(PACKAGE_NAME_INDEXED).get("ccc")).containsExactly(packageNameRuleC); // We check asserts this way to ensure ordering based on app certificate. assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2", "cert3"); - keySetIterator = result.get(APP_CERTIFICATE_INDEXED).keySet().iterator(); - assertThat(keySetIterator.next()).isEqualTo("cert1"); - assertThat(keySetIterator.next()).isEqualTo("cert2"); - assertThat(keySetIterator.next()).isEqualTo("cert3"); - assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert1")).containsExactly( - certificateRule1); - assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert2")).containsExactly( - certificateRule2); - assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert3")).containsExactly( - certificateRule3); assertThat(result.get(NOT_INDEXED).get("N/A")) - .containsExactly( - RULE_WITH_INSTALLER_RESTRICTIONS, + .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS, RULE_WITH_NONSTRING_RESTRICTIONS); } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java index f7cd6a3d2245..99065854445a 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java @@ -21,12 +21,10 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; -import android.text.TextUtils; import android.util.Slog; -import java.util.Locale; +import java.io.PrintWriter; import java.util.UUID; /** @@ -39,7 +37,7 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { static final boolean DBG = false; private static final String NAME = "st_sound_model.db"; - private static final int VERSION = 1; + private static final int VERSION = 2; // Sound trigger-based sound models. public static interface GenericSoundModelContract { @@ -47,15 +45,16 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { public static final String KEY_MODEL_UUID = "model_uuid"; public static final String KEY_VENDOR_UUID = "vendor_uuid"; public static final String KEY_DATA = "data"; + public static final String KEY_MODEL_VERSION = "model_version"; } - // Table Create Statement for the sound trigger table private static final String CREATE_TABLE_ST_SOUND_MODEL = "CREATE TABLE " + GenericSoundModelContract.TABLE + "(" + GenericSoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY," + GenericSoundModelContract.KEY_VENDOR_UUID + " TEXT," - + GenericSoundModelContract.KEY_DATA + " BLOB" + " )"; + + GenericSoundModelContract.KEY_DATA + " BLOB," + + GenericSoundModelContract.KEY_MODEL_VERSION + " INTEGER" + " )"; public SoundTriggerDbHelper(Context context) { @@ -70,9 +69,13 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // TODO: For now, drop older tables and recreate new ones. - db.execSQL("DROP TABLE IF EXISTS " + GenericSoundModelContract.TABLE); - onCreate(db); + if (oldVersion == 1) { + // In version 2, a model version number was added. + Slog.d(TAG, "Adding model version column"); + db.execSQL("ALTER TABLE " + GenericSoundModelContract.TABLE + " ADD COLUMN " + + GenericSoundModelContract.KEY_MODEL_VERSION + " INTEGER DEFAULT -1"); + oldVersion++; + } } /** @@ -86,6 +89,7 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { values.put(GenericSoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString()); values.put(GenericSoundModelContract.KEY_VENDOR_UUID, soundModel.vendorUuid.toString()); values.put(GenericSoundModelContract.KEY_DATA, soundModel.data); + values.put(GenericSoundModelContract.KEY_MODEL_VERSION, soundModel.version); try { return db.insertWithOnConflict(GenericSoundModelContract.TABLE, null, values, @@ -113,8 +117,10 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { GenericSoundModelContract.KEY_DATA)); String vendor_uuid = c.getString( c.getColumnIndex(GenericSoundModelContract.KEY_VENDOR_UUID)); + int version = c.getInt( + c.getColumnIndex(GenericSoundModelContract.KEY_MODEL_VERSION)); return new GenericSoundModel(model_uuid, UUID.fromString(vendor_uuid), - data); + data, version); } while (c.moveToNext()); } } finally { @@ -142,4 +148,48 @@ public class SoundTriggerDbHelper extends SQLiteOpenHelper { } } } + + public void dump(PrintWriter pw) { + synchronized(this) { + String selectQuery = "SELECT * FROM " + GenericSoundModelContract.TABLE; + SQLiteDatabase db = getReadableDatabase(); + Cursor c = db.rawQuery(selectQuery, null); + try { + pw.println(" Enrolled GenericSoundModels:"); + if (c.moveToFirst()) { + String[] columnNames = c.getColumnNames(); + do { + for (String name : columnNames) { + int colNameIndex = c.getColumnIndex(name); + int type = c.getType(colNameIndex); + switch (type) { + case Cursor.FIELD_TYPE_STRING: + pw.printf(" %s: %s\n", name, + c.getString(colNameIndex)); + break; + case Cursor.FIELD_TYPE_BLOB: + pw.printf(" %s: data blob\n", name); + break; + case Cursor.FIELD_TYPE_INTEGER: + pw.printf(" %s: %d\n", name, + c.getInt(colNameIndex)); + break; + case Cursor.FIELD_TYPE_FLOAT: + pw.printf(" %s: %f\n", name, + c.getFloat(colNameIndex)); + break; + case Cursor.FIELD_TYPE_NULL: + pw.printf(" %s: null\n", name); + break; + } + } + pw.println(); + } while (c.moveToNext()); + } + } finally { + c.close(); + db.close(); + } + } + } } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index e37755bddcaa..767010ae821a 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -1495,6 +1495,9 @@ public class SoundTriggerService extends SystemService { // log sEventLogger.dump(pw); + // enrolled models + mDbHelper.dump(pw); + // stats mSoundModelStatTracker.dump(pw); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java index dd7b5a8752e5..c58b6da64baa 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java @@ -27,6 +27,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.text.TextUtils; import android.util.Slog; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -43,7 +44,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { static final boolean DBG = false; private static final String NAME = "sound_model.db"; - private static final int VERSION = 6; + private static final int VERSION = 7; public static interface SoundModelContract { public static final String TABLE = "sound_model"; @@ -56,6 +57,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { public static final String KEY_LOCALE = "locale"; public static final String KEY_HINT_TEXT = "hint_text"; public static final String KEY_USERS = "users"; + public static final String KEY_MODEL_VERSION = "model_version"; } // Table Create Statement @@ -70,6 +72,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { + SoundModelContract.KEY_LOCALE + " TEXT," + SoundModelContract.KEY_HINT_TEXT + " TEXT," + SoundModelContract.KEY_USERS + " TEXT," + + SoundModelContract.KEY_MODEL_VERSION + " INTEGER," + "PRIMARY KEY (" + SoundModelContract.KEY_KEYPHRASE_ID + "," + SoundModelContract.KEY_LOCALE + "," + SoundModelContract.KEY_USERS + ")" @@ -138,6 +141,13 @@ public class DatabaseHelper extends SQLiteOpenHelper { } oldVersion++; } + if (oldVersion == 6) { + // In version 7, a model version number was added. + Slog.d(TAG, "Adding model version column"); + db.execSQL("ALTER TABLE " + SoundModelContract.TABLE + " ADD COLUMN " + + SoundModelContract.KEY_MODEL_VERSION + " INTEGER DEFAULT -1"); + oldVersion++; + } } /** @@ -155,6 +165,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } values.put(SoundModelContract.KEY_TYPE, SoundTrigger.SoundModel.TYPE_KEYPHRASE); values.put(SoundModelContract.KEY_DATA, soundModel.data); + values.put(SoundModelContract.KEY_MODEL_VERSION, soundModel.version); if (soundModel.keyphrases != null && soundModel.keyphrases.length == 1) { values.put(SoundModelContract.KEY_KEYPHRASE_ID, soundModel.keyphrases[0].id); @@ -250,6 +261,8 @@ public class DatabaseHelper extends SQLiteOpenHelper { c.getColumnIndex(SoundModelContract.KEY_LOCALE)); String text = c.getString( c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT)); + int version = c.getInt( + c.getColumnIndex(SoundModelContract.KEY_MODEL_VERSION)); // Only add keyphrases meant for the current user. if (users == null) { @@ -282,7 +295,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { vendorUuid = UUID.fromString(vendorUuidString); } KeyphraseSoundModel model = new KeyphraseSoundModel( - UUID.fromString(modelUuid), vendorUuid, data, keyphrases); + UUID.fromString(modelUuid), vendorUuid, data, keyphrases, version); if (DBG) { Slog.d(TAG, "Found SoundModel for the given keyphrase/locale/user: " + model); @@ -325,6 +338,10 @@ public class DatabaseHelper extends SQLiteOpenHelper { return users; } + /** + * SoundModelRecord is no longer used, and it should only be used on database migration. + * This class does not need to be modified when modifying the database scheme. + */ private static class SoundModelRecord { public final String modelUuid; public final String vendorUuid; @@ -413,4 +430,48 @@ public class DatabaseHelper extends SQLiteOpenHelper { return a == b; } } + + public void dump(PrintWriter pw) { + synchronized(this) { + String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE; + SQLiteDatabase db = getReadableDatabase(); + Cursor c = db.rawQuery(selectQuery, null); + try { + pw.println(" Enrolled KeyphraseSoundModels:"); + if (c.moveToFirst()) { + String[] columnNames = c.getColumnNames(); + do { + for (String name : columnNames) { + int colNameIndex = c.getColumnIndex(name); + int type = c.getType(colNameIndex); + switch (type) { + case Cursor.FIELD_TYPE_STRING: + pw.printf(" %s: %s\n", name, + c.getString(colNameIndex)); + break; + case Cursor.FIELD_TYPE_BLOB: + pw.printf(" %s: data blob\n", name); + break; + case Cursor.FIELD_TYPE_INTEGER: + pw.printf(" %s: %d\n", name, + c.getInt(colNameIndex)); + break; + case Cursor.FIELD_TYPE_FLOAT: + pw.printf(" %s: %f\n", name, + c.getFloat(colNameIndex)); + break; + case Cursor.FIELD_TYPE_NULL: + pw.printf(" %s: null\n", name); + break; + } + } + pw.println(); + } while (c.moveToNext()); + } + } finally { + c.close(); + db.close(); + } + } + } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 6b95f0fe5350..506c67e12528 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1347,6 +1347,7 @@ public class VoiceInteractionManagerService extends SystemService { pw.println(" mCurUserUnlocked: " + mCurUserUnlocked); pw.println(" mCurUserSupported: " + mCurUserSupported); dumpSupportedUsers(pw, " "); + mDbHelper.dump(pw); if (mImpl == null) { pw.println(" (No active implementation)"); return; diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telecomm/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telephony/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index a17a19c74e08..9bc534c2877a 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -27,10 +27,10 @@ import android.os.RemoteException; import android.os.UserHandle; import android.permission.IPermissionManager; import android.provider.Settings; -import android.util.Log; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -141,8 +141,8 @@ public final class CarrierAppUtils { ContentResolver contentResolver, int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) { - List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager, - userId, systemCarrierAppsDisabledUntilUsed); + List<ApplicationInfo> candidates = getDefaultNotUpdatedCarrierAppCandidatesHelper( + packageManager, userId, systemCarrierAppsDisabledUntilUsed); if (candidates == null || candidates.isEmpty()) { return; } @@ -178,15 +178,16 @@ public final class CarrierAppUtils { } } + int enabledSetting = packageManager.getApplicationEnabledSetting(packageName, + userId); if (hasPrivileges) { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. - if (!ai.isUpdatedSystemApp() - && (ai.enabledSetting + if (enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || ai.enabledSetting + || enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED - || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) { + || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { Log.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); packageManager.setSystemAppInstallState( @@ -204,9 +205,12 @@ public final class CarrierAppUtils { // Also enable any associated apps for this carrier app. if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - if (associatedApp.enabledSetting + int associatedAppEnabledSetting = + packageManager.getApplicationEnabledSetting( + associatedApp.packageName, userId); + if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || associatedApp.enabledSetting + || associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED || (associatedApp.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { @@ -231,8 +235,7 @@ public final class CarrierAppUtils { } else { // No carrier privileges // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. - if (!ai.isUpdatedSystemApp() - && ai.enabledSetting + if (enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { Log.i(TAG, "Update state(" + packageName @@ -249,7 +252,10 @@ public final class CarrierAppUtils { if (!hasRunOnce) { if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - if (associatedApp.enabledSetting + int associatedAppEnabledSetting = + packageManager.getApplicationEnabledSetting( + associatedApp.packageName, userId); + if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (associatedApp.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { @@ -360,6 +366,31 @@ public final class CarrierAppUtils { return apps; } + private static List<ApplicationInfo> getDefaultNotUpdatedCarrierAppCandidatesHelper( + IPackageManager packageManager, + int userId, + ArraySet<String> systemCarrierAppsDisabledUntilUsed) { + if (systemCarrierAppsDisabledUntilUsed == null) { + return null; + } + + int size = systemCarrierAppsDisabledUntilUsed.size(); + if (size == 0) { + return null; + } + + List<ApplicationInfo> apps = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i); + ApplicationInfo ai = + getApplicationInfoIfNotUpdatedSystemApp(packageManager, userId, packageName); + if (ai != null) { + apps.add(ai); + } + } + return apps; + } + private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper( IPackageManager packageManager, int userId, @@ -372,11 +403,11 @@ public final class CarrierAppUtils { systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i); for (int j = 0; j < associatedAppPackages.size(); j++) { ApplicationInfo ai = - getApplicationInfoIfSystemApp( + getApplicationInfoIfNotUpdatedSystemApp( packageManager, userId, associatedAppPackages.get(j)); // Only update enabled state for the app on /system. Once it has been updated we // shouldn't touch it. - if (ai != null && !ai.isUpdatedSystemApp()) { + if (ai != null) { List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage); if (appList == null) { appList = new ArrayList<>(); @@ -390,6 +421,26 @@ public final class CarrierAppUtils { } @Nullable + private static ApplicationInfo getApplicationInfoIfNotUpdatedSystemApp( + IPackageManager packageManager, + int userId, + String packageName) { + try { + ApplicationInfo ai = packageManager.getApplicationInfo(packageName, + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.MATCH_FACTORY_ONLY, userId); + if (ai != null) { + return ai; + } + } catch (RemoteException e) { + Log.w(TAG, "Could not reach PackageManager", e); + } + return null; + } + + @Nullable private static ApplicationInfo getApplicationInfoIfSystemApp( IPackageManager packageManager, int userId, @@ -397,8 +448,9 @@ public final class CarrierAppUtils { try { ApplicationInfo ai = packageManager.getApplicationInfo(packageName, PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId); - if (ai != null && ai.isSystemApp()) { + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY, userId); + if (ai != null) { return ai; } } catch (RemoteException e) { diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java index e01deb2802ff..1e1cdba70ad0 100644 --- a/telephony/java/android/telephony/CallQuality.java +++ b/telephony/java/android/telephony/CallQuality.java @@ -80,6 +80,9 @@ public final class CallQuality implements Parcelable { private int mMaxRelativeJitter; private int mAverageRoundTripTime; private int mCodecType; + private boolean mRtpInactivityDetected; + private boolean mRxSilenceDetected; + private boolean mTxSilenceDetected; /** @hide **/ public CallQuality(Parcel in) { @@ -94,6 +97,9 @@ public final class CallQuality implements Parcelable { mMaxRelativeJitter = in.readInt(); mAverageRoundTripTime = in.readInt(); mCodecType = in.readInt(); + mRtpInactivityDetected = in.readBoolean(); + mRxSilenceDetected = in.readBoolean(); + mTxSilenceDetected = in.readBoolean(); } /** @hide **/ @@ -109,7 +115,7 @@ public final class CallQuality implements Parcelable { * @param numRtpPacketsReceived RTP packets received from network * @param numRtpPacketsTransmittedLost RTP packets which were lost in network and never * transmitted - * @param numRtpPacketsNotReceived RTP packets which were lost in network and never recieved + * @param numRtpPacketsNotReceived RTP packets which were lost in network and never received * @param averageRelativeJitter average relative jitter in milliseconds * @param maxRelativeJitter maximum relative jitter in milliseconds * @param averageRoundTripTime average round trip delay in milliseconds @@ -127,6 +133,48 @@ public final class CallQuality implements Parcelable { int maxRelativeJitter, int averageRoundTripTime, int codecType) { + this(downlinkCallQualityLevel, uplinkCallQualityLevel, callDuration, + numRtpPacketsTransmitted, numRtpPacketsReceived, numRtpPacketsTransmittedLost, + numRtpPacketsNotReceived, averageRelativeJitter, maxRelativeJitter, + averageRoundTripTime, codecType, false, false, false); + } + + /** + * Constructor. + * + * @param callQualityLevel the call quality level (see #CallQualityLevel) + * @param callDuration the call duration in milliseconds + * @param numRtpPacketsTransmitted RTP packets sent to network + * @param numRtpPacketsReceived RTP packets received from network + * @param numRtpPacketsTransmittedLost RTP packets which were lost in network and never + * transmitted + * @param numRtpPacketsNotReceived RTP packets which were lost in network and never received + * @param averageRelativeJitter average relative jitter in milliseconds + * @param maxRelativeJitter maximum relative jitter in milliseconds + * @param averageRoundTripTime average round trip delay in milliseconds + * @param codecType the codec type + * @param rtpInactivityDetected True if no incoming RTP is received for a continuous duration of + * 4 seconds + * @param rxSilenceDetected True if only silence RTP packets are received for 20 seconds + * immediately after call is connected + * @param txSilenceDetected True if only silence RTP packets are sent for 20 seconds immediately + * after call is connected + */ + public CallQuality( + @CallQualityLevel int downlinkCallQualityLevel, + @CallQualityLevel int uplinkCallQualityLevel, + int callDuration, + int numRtpPacketsTransmitted, + int numRtpPacketsReceived, + int numRtpPacketsTransmittedLost, + int numRtpPacketsNotReceived, + int averageRelativeJitter, + int maxRelativeJitter, + int averageRoundTripTime, + int codecType, + boolean rtpInactivityDetected, + boolean rxSilenceDetected, + boolean txSilenceDetected) { this.mDownlinkCallQualityLevel = downlinkCallQualityLevel; this.mUplinkCallQualityLevel = uplinkCallQualityLevel; this.mCallDuration = callDuration; @@ -138,6 +186,9 @@ public final class CallQuality implements Parcelable { this.mMaxRelativeJitter = maxRelativeJitter; this.mAverageRoundTripTime = averageRoundTripTime; this.mCodecType = codecType; + this.mRtpInactivityDetected = rtpInactivityDetected; + this.mRxSilenceDetected = rxSilenceDetected; + this.mTxSilenceDetected = txSilenceDetected; } // getters @@ -226,6 +277,29 @@ public final class CallQuality implements Parcelable { } /** + * Returns true if no rtp packets are received continuously for the last 4 seconds + */ + public boolean isRtpInactivityDetected() { + return mRtpInactivityDetected; + } + + /** + * Returns true if only silence rtp packets are received for a duration of 20 seconds starting + * at call setup + */ + public boolean isIncomingSilenceDetected() { + return mRxSilenceDetected; + } + + /** + * Returns true if only silence rtp packets are sent for a duration of 20 seconds starting at + * call setup + */ + public boolean isOutgoingSilenceDetected() { + return mTxSilenceDetected; + } + + /** * Returns the codec type. This value corresponds to the AUDIO_QUALITY_* constants in * {@link ImsStreamMediaProfile}. * @@ -270,6 +344,9 @@ public final class CallQuality implements Parcelable { + " maxRelativeJitter=" + mMaxRelativeJitter + " averageRoundTripTime=" + mAverageRoundTripTime + " codecType=" + mCodecType + + " rtpInactivityDetected=" + mRtpInactivityDetected + + " txSilenceDetected=" + mRxSilenceDetected + + " rxSilenceDetected=" + mTxSilenceDetected + "}"; } @@ -286,7 +363,10 @@ public final class CallQuality implements Parcelable { mAverageRelativeJitter, mMaxRelativeJitter, mAverageRoundTripTime, - mCodecType); + mCodecType, + mRtpInactivityDetected, + mRxSilenceDetected, + mTxSilenceDetected); } @Override @@ -311,7 +391,10 @@ public final class CallQuality implements Parcelable { && mAverageRelativeJitter == s.mAverageRelativeJitter && mMaxRelativeJitter == s.mMaxRelativeJitter && mAverageRoundTripTime == s.mAverageRoundTripTime - && mCodecType == s.mCodecType); + && mCodecType == s.mCodecType + && mRtpInactivityDetected == s.mRtpInactivityDetected + && mRxSilenceDetected == s.mRxSilenceDetected + && mTxSilenceDetected == s.mTxSilenceDetected); } /** @@ -336,6 +419,9 @@ public final class CallQuality implements Parcelable { dest.writeInt(mMaxRelativeJitter); dest.writeInt(mAverageRoundTripTime); dest.writeInt(mCodecType); + dest.writeBoolean(mRtpInactivityDetected); + dest.writeBoolean(mRxSilenceDetected); + dest.writeBoolean(mTxSilenceDetected); } public static final @android.annotation.NonNull Parcelable.Creator<CallQuality> CREATOR = new Parcelable.Creator() { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 6a622378dac7..86178334879f 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -672,6 +672,12 @@ public class CarrierConfigManager { "carrier_promote_wfc_on_call_fail_bool"; /** + * Flag specifying whether provisioning is required for RCS. + */ + public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = + "carrier_rcs_provisioning_required_bool"; + + /** * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi * Calling. */ @@ -848,9 +854,12 @@ public class CarrierConfigManager { "carrier_force_disable_etws_cmas_test_bool"; /** - * The default flag specifying whether "Turn on Notifications" option will be always shown in - * Settings->More->Emergency broadcasts menu regardless developer options is turned on or not. + * The default flag specifying whether "Allow alerts" option will be always shown in + * emergency alerts settings regardless developer options is turned on or not. + * + * @deprecated The allow alerts option is always shown now. No longer need a config for that. */ + @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; @@ -1627,8 +1636,8 @@ public class CarrierConfigManager { * Defines carrier-specific actions which act upon * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED * and configured signal args: - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType}, - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode} + * {@link TelephonyManager#EXTRA_APN_TYPE apnType}, + * {@link TelephonyManager#EXTRA_ERROR_CODE errorCode} * used for customization of the default carrier app * Format: * { @@ -3497,6 +3506,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2); sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2); sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false); + sDefaults.putBoolean(KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, false); diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 31434c1d2adf..5e2e554b7764 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -20,6 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.net.LinkProperties; import android.os.Build; @@ -31,8 +34,6 @@ import android.telephony.Annotation.DataState; import android.telephony.Annotation.NetworkType; import android.telephony.data.ApnSetting; -import dalvik.system.VMRuntime; - import java.util.Objects; @@ -134,6 +135,13 @@ public final class PreciseDataConnectionState implements Parcelable { } /** + * To check the SDK version for {@link PreciseDataConnectionState#getDataConnectionState}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + private static final long GET_DATA_CONNECTION_STATE_CODE_CHANGE = 147600208L; + + /** * Returns the state of data connection that supported the apn types returned by * {@link #getDataConnectionApnTypeBitMask()} * @@ -144,7 +152,7 @@ public final class PreciseDataConnectionState implements Parcelable { @SystemApi public @DataState int getDataConnectionState() { if (mState == TelephonyManager.DATA_DISCONNECTING - && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) { + && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_CODE_CHANGE)) { return TelephonyManager.DATA_CONNECTED; } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index eb328a705e56..1dbc8b1a6be9 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -281,6 +281,42 @@ public final class SmsManager { */ public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; + /** @hide */ + @IntDef(prefix = { "PREMIUM_SMS_CONSENT" }, value = { + SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN, + SmsManager.PREMIUM_SMS_CONSENT_ASK_USER, + SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW, + SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PremiumSmsConsent {} + + /** Premium SMS Consent for the package is unknown. This indicates that the user + * has not set a permission for this package, because this package has never tried + * to send a premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; + + /** Default premium SMS Consent (ask user for each premium SMS sent). + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; + + /** Premium SMS Consent when the owner has denied the app from sending premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; + + /** Premium SMS Consent when the owner has allowed the app to send premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; + // result of asking the user for a subscription to perform an operation. private interface SubscriptionResolverResult { void onSuccess(int subId); @@ -744,11 +780,7 @@ public final class SmsManager { "Invalid pdu format. format must be either 3gpp or 3gpp2"); } try { - ISms iSms = ISms.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSmsServiceRegisterer() - .get()); + ISms iSms = TelephonyManager.getSmsService(); if (iSms != null) { iSms.injectSmsPduForSubscriber( getSubscriptionId(), pdu, format, receivedIntent); @@ -1571,7 +1603,7 @@ public final class SmsManager { * the service does not exist. */ private static ISms getISmsServiceOrThrow() { - ISms iSms = getISmsService(); + ISms iSms = TelephonyManager.getSmsService(); if (iSms == null) { throw new UnsupportedOperationException("Sms is not supported"); } @@ -1579,11 +1611,7 @@ public final class SmsManager { } private static ISms getISmsService() { - return ISms.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSmsServiceRegisterer() - .get()); + return TelephonyManager.getSmsService(); } /** @@ -2017,11 +2045,7 @@ public final class SmsManager { public boolean isSMSPromptEnabled() { ISms iSms = null; try { - iSms = ISms.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSmsServiceRegisterer() - .get()); + iSms = TelephonyManager.getSmsService(); return iSms.isSMSPromptEnabled(); } catch (RemoteException ex) { return false; @@ -2448,14 +2472,18 @@ public final class SmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed * @throws IllegalArgumentException if contentUri is empty + * @deprecated use {@link MmsManager#sendMultimediaMessage} instead. */ public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent) { if (contentUri == null) { throw new IllegalArgumentException("Uri contentUri null"); } - MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri, - locationUrl, configOverrides, sentIntent); + MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); + if (m != null) { + m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides, + sentIntent); + } } /** @@ -2479,6 +2507,7 @@ public final class SmsManager { * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed * @throws IllegalArgumentException if locationUrl or contentUri is empty + * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead. */ public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) { @@ -2488,8 +2517,11 @@ public final class SmsManager { if (contentUri == null) { throw new IllegalArgumentException("Uri contentUri null"); } - MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl, - contentUri, configOverrides, downloadedIntent); + MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); + if (m != null) { + m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri, + configOverrides, downloadedIntent); + } } // MMS send/download failure result codes @@ -2531,9 +2563,9 @@ public final class SmsManager { * </p> * * @return the bundle key/values pairs that contains MMS configuration values + * or an empty Bundle if they cannot be found. */ - @Nullable - public Bundle getCarrierConfigValues() { + @NonNull public Bundle getCarrierConfigValues() { try { ISms iSms = getISmsService(); if (iSms != null) { @@ -2542,7 +2574,7 @@ public final class SmsManager { } catch (RemoteException ex) { // ignore it } - return null; + return new Bundle(); } /** @@ -2861,4 +2893,53 @@ public final class SmsManager { } return false; } + + /** + * Gets the premium SMS permission for the specified package. If the package has never + * been seen before, the default {@link SmsManager#PREMIUM_SMS_PERMISSION_ASK_USER} + * will be returned. + * @param packageName the name of the package to query permission + * @return one of {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or + * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public @PremiumSmsConsent int getPremiumSmsConsent(@NonNull String packageName) { + int permission = 0; + try { + ISms iSms = getISmsService(); + if (iSms != null) { + permission = iSms.getPremiumSmsPermission(packageName); + } + } catch (RemoteException e) { + Log.e(TAG, "getPremiumSmsPermission() RemoteException", e); + } + return permission; + } + + /** + * Sets the premium SMS permission for the specified package and save the value asynchronously + * to persistent storage. + * @param packageName the name of the package to set permission + * @param permission one of {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or + * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setPremiumSmsConsent( + @NonNull String packageName, @PremiumSmsConsent int permission) { + try { + ISms iSms = getISmsService(); + if (iSms != null) { + iSms.setPremiumSmsPermission(packageName, permission); + } + } catch (RemoteException e) { + Log.e(TAG, "setPremiumSmsPermission() RemoteException", e); + } + } } diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index c217b8b83c26..40a7619a3ee3 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -20,8 +20,13 @@ import com.android.telephony.Rlog; import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.StringDef; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Binder; @@ -31,8 +36,10 @@ import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsConstants; +import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; +import com.android.internal.telephony.cdma.sms.UserData; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -56,6 +63,16 @@ public class SmsMessage { UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } + /** @hide */ + @IntDef(prefix = { "ENCODING_" }, value = { + ENCODING_UNKNOWN, + ENCODING_7BIT, + ENCODING_8BIT, + ENCODING_16BIT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EncodingSize {} + /** User data text encoding code unit size */ public static final int ENCODING_UNKNOWN = 0; public static final int ENCODING_7BIT = 1; @@ -633,6 +650,83 @@ public class SmsMessage { } /** + * Get an SMS-SUBMIT PDU's encoded message. + * This is used by Bluetooth MAP profile to handle long non UTF-8 SMS messages. + * + * @param isTypeGsm true when message's type is GSM, false when type is CDMA + * @param destinationAddress the address of the destination for the message + * @param message message content + * @param encoding User data text encoding code unit size + * @param languageTable GSM national language table to use, specified by 3GPP + * 23.040 9.2.3.24.16 + * @param languageShiftTable GSM national language shift table to use, specified by 3GPP + * 23.040 9.2.3.24.15 + * @param refNumber parameter to create SmsHeader + * @param seqNumber parameter to create SmsHeader + * @param msgCount parameter to create SmsHeader + * @return a byte[] containing the encoded message + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @SystemApi + @NonNull + public static byte[] getSubmitPduEncodedMessage(boolean isTypeGsm, + @NonNull String destinationAddress, + @NonNull String message, + @EncodingSize int encoding, int languageTable, + int languageShiftTable, int refNumber, + int seqNumber, int msgCount) { + byte[] data; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = seqNumber; // 1-based sequence + concatRef.msgCount = msgCount; + // We currently set this to true since our messaging app will never + // send more than 255 parts (it converts the message to MMS well before that). + // However, we should support 3rd party messaging apps that might need 16-bit + // references + // Note: It's not sufficient to just flip this bit to true; it will have + // ripple effects (several calculations assume 8-bit ref). + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + + /* Depending on the type, call either GSM or CDMA getSubmitPdu(). The encoding + * will be determined(again) by getSubmitPdu(). + * All packets need to be encoded using the same encoding, as the bMessage + * only have one filed to describe the encoding for all messages in a concatenated + * SMS... */ + if (encoding == ENCODING_7BIT) { + smsHeader.languageTable = languageTable; + smsHeader.languageShiftTable = languageShiftTable; + } + + if (isTypeGsm) { + data = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, + destinationAddress, message, false, + SmsHeader.toByteArray(smsHeader), encoding, languageTable, + languageShiftTable).encodedMessage; + } else { // SMS_TYPE_CDMA + UserData uData = new UserData(); + uData.payloadStr = message; + uData.userDataHeader = smsHeader; + if (encoding == ENCODING_7BIT) { + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + } else { // assume UTF-16 + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + } + uData.msgEncodingSet = true; + data = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( + destinationAddress, uData, false).encodedMessage; + } + if (data == null) { + return new byte[0]; + } + return data; + } + + /** * Returns the address of the SMS service center that relayed this message * or null if there is none. */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 4510fede4e8e..cb4462f88581 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1146,11 +1146,7 @@ public class SubscriptionManager { SubscriptionInfo subInfo = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1184,11 +1180,7 @@ public class SubscriptionManager { SubscriptionInfo result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1222,11 +1214,7 @@ public class SubscriptionManager { SubscriptionInfo result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1250,11 +1238,7 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getAllSubInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1335,11 +1319,7 @@ public class SubscriptionManager { List<SubscriptionInfo> activeList = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1390,11 +1370,7 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1433,11 +1409,7 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName()); } @@ -1466,11 +1438,7 @@ public class SubscriptionManager { public void requestEmbeddedSubscriptionInfoListRefresh() { int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc(); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId); } @@ -1499,11 +1467,7 @@ public class SubscriptionManager { @SystemApi public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId); } @@ -1524,11 +1488,7 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getAllSubInfoCount(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1557,11 +1517,7 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1582,11 +1538,7 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getActiveSubInfoCountMax(); } @@ -1643,11 +1595,7 @@ public class SubscriptionManager { } try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub == null) { Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null"); return; @@ -1681,11 +1629,7 @@ public class SubscriptionManager { } try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub == null) { Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null"); return; @@ -1788,11 +1732,7 @@ public class SubscriptionManager { int result = INVALID_SIM_SLOT_INDEX; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getSlotIndex(subscriptionId); } @@ -1826,11 +1766,7 @@ public class SubscriptionManager { int[] subId = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getSubId(slotIndex); } @@ -1854,11 +1790,7 @@ public class SubscriptionManager { int result = INVALID_PHONE_INDEX; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getPhoneId(subId); } @@ -1892,11 +1824,7 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getDefaultSubId(); } @@ -1919,11 +1847,7 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getDefaultVoiceSubId(); } @@ -1953,11 +1877,7 @@ public class SubscriptionManager { public void setDefaultVoiceSubscriptionId(int subscriptionId) { if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.setDefaultVoiceSubId(subscriptionId); } @@ -2005,11 +1925,7 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getDefaultSmsSubId(); } @@ -2035,11 +1951,7 @@ public class SubscriptionManager { public void setDefaultSmsSubId(int subscriptionId) { if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.setDefaultSmsSubId(subscriptionId); } @@ -2077,11 +1989,7 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getDefaultDataSubId(); } @@ -2107,11 +2015,7 @@ public class SubscriptionManager { public void setDefaultDataSubId(int subscriptionId) { if (VDBG) logd("setDataSubscription sub id = " + subscriptionId); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.setDefaultDataSubId(subscriptionId); } @@ -2142,11 +2046,7 @@ public class SubscriptionManager { /** @hide */ public void clearSubscriptionInfo() { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.clearSubInfo(); } @@ -2282,11 +2182,7 @@ public class SubscriptionManager { */ public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { int[] subId = iSub.getActiveSubIdList(visibleOnly); if (subId != null) return subId; @@ -2337,11 +2233,7 @@ public class SubscriptionManager { int simState = TelephonyManager.SIM_STATE_UNKNOWN; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { simState = iSub.getSimStateForSlotIndex(slotIndex); } @@ -2360,11 +2252,7 @@ public class SubscriptionManager { */ public static void setSubscriptionProperty(int subId, String propKey, String propValue) { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.setSubscriptionProperty(subId, propKey, propValue); } @@ -2384,11 +2272,7 @@ public class SubscriptionManager { Context context) { String resultValue = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { resultValue = iSub.getSubscriptionProperty(subId, propKey, context.getOpPackageName(), context.getFeatureId()); @@ -2530,11 +2414,7 @@ public class SubscriptionManager { @UnsupportedAppUsage public boolean isActiveSubId(int subId) { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { return iSub.isActiveSubId(subId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -2837,11 +2717,7 @@ public class SubscriptionManager { @TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub == null) return; ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { @@ -2884,11 +2760,7 @@ public class SubscriptionManager { public int getPreferredDataSubscriptionId() { int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { preferredSubId = iSub.getPreferredDataSubscriptionId(); } @@ -2919,11 +2791,7 @@ public class SubscriptionManager { List<SubscriptionInfo> subInfoList = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature); } @@ -3024,11 +2892,7 @@ public class SubscriptionManager { ParcelUuid groupUuid = null; int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug); } else { @@ -3078,11 +2942,7 @@ public class SubscriptionManager { int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug); } else { @@ -3134,11 +2994,7 @@ public class SubscriptionManager { int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug); } else { @@ -3183,11 +3039,7 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature); } else { @@ -3300,11 +3152,7 @@ public class SubscriptionManager { logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable); } try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { return iSub.setSubscriptionEnabled(enable, subscriptionId); } @@ -3393,11 +3241,7 @@ public class SubscriptionManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int subscriptionId) { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { return iSub.isSubscriptionEnabled(subscriptionId); } @@ -3420,11 +3264,7 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { subId = iSub.getEnabledSubscriptionId(slotIndex); } @@ -3450,11 +3290,7 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = helper.callMethod(iSub); } @@ -3477,11 +3313,7 @@ public class SubscriptionManager { */ public static int getActiveDataSubscriptionId() { try { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); + ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { return iSub.getActiveDataSubscriptionId(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 157d92db8caa..d15a5317fc5d 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -57,6 +57,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; @@ -94,12 +95,15 @@ import android.util.Log; import android.util.Pair; import com.android.ims.internal.IImsServiceFeatureCallback; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CellNetworkScanResult; import com.android.internal.telephony.INumberVerificationCallback; import com.android.internal.telephony.IOns; import com.android.internal.telephony.IPhoneSubInfo; import com.android.internal.telephony.ISetOpportunisticDataCallback; +import com.android.internal.telephony.ISms; +import com.android.internal.telephony.ISub; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.IUpdateAvailableNetworksCallback; @@ -109,8 +113,6 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SmsApplication; import com.android.telephony.Rlog; -import dalvik.system.VMRuntime; - import java.io.FileInputStream; import java.io.IOException; import java.lang.annotation.Retention; @@ -301,6 +303,21 @@ public class TelephonyManager { private SubscriptionManager mSubscriptionManager; private TelephonyScanManager mTelephonyScanManager; + /** Cached service handles, cleared by resetServiceHandles() at death */ + private static final Object sCacheLock = new Object(); + + /** @hide */ + private static boolean sServiceHandleCacheEnabled = true; + + @GuardedBy("sCacheLock") + private static IPhoneSubInfo sIPhoneSubInfo; + @GuardedBy("sCacheLock") + private static ISub sISub; + @GuardedBy("sCacheLock") + private static ISms sISms; + @GuardedBy("sCacheLock") + private static final DeathRecipient sServiceDeath = new DeathRecipient(); + /** Enum indicating multisim variants * DSDS - Dual SIM Dual Standby * DSDA - Dual SIM Dual Active @@ -1464,6 +1481,193 @@ public class TelephonyManager { = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED"; /** + * <p>Broadcast Action: when data connections get redirected with validation failure. + * intended for sim/account status checks and only sent to the specified carrier app + * The intent will have the following extra values:</p> + * <ul> + * <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd> + * <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd> + * <li>{@link #EXTRA_REDIRECTION_URL}</li><dd>redirection url string</dd> + * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system.</p> + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String ACTION_CARRIER_SIGNAL_REDIRECTED = + "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"; + + /** + * <p>Broadcast Action: when data connections setup fails. + * intended for sim/account status checks and only sent to the specified carrier app + * The intent will have the following extra values:</p> + * <ul> + * <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd> + * <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd> + * <li>{@link #EXTRA_ERROR_CODE}</li><dd>A integer with dataFailCause.</dd> + * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system. </p> + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED = + "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED"; + + /** + * <p>Broadcast Action: when pco value is available. + * intended for sim/account status checks and only sent to the specified carrier app + * The intent will have the following extra values:</p> + * <ul> + * <li>{@link #EXTRA_APN_TYPE}</li><dd>A string with the apn type.</dd> + * <li>{@link #EXTRA_APN_TYPE_INT}</li><dd>A integer with the apn type.</dd> + * <li>{@link #EXTRA_APN_PROTOCOL}</li><dd>A string with the protocol of the apn connection + * (IP,IPV6, IPV4V6)</dd> + * <li>{@link #EXTRA_APN_PROTOCOL_INT}</li><dd>A integer with the protocol of the apn + * connection (IP,IPV6, IPV4V6)</dd> + * <li>{@link #EXTRA_PCO_ID}</li><dd>An integer indicating the pco id for the data.</dd> + * <li>{@link #EXTRA_PCO_VALUE}</li><dd>A byte array of pco data read from modem.</dd> + * <li>subId</li><dd>Sub Id which associated the data connection.</dd> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system. </p> + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = + "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE"; + + /** + * <p>Broadcast Action: when system default network available/unavailable with + * carrier-disabled mobile data. Intended for carrier apps to set/reset carrier actions when + * other network becomes system default network, Wi-Fi for example. + * The intent will have the following extra values:</p> + * <ul> + * <li>{@link #EXTRA_DEFAULT_NETWORK_AVAILABLE}</li> + * <dd>A boolean indicates default network available.</dd> + * <li>subId</li><dd>Sub Id which associated the default data.</dd> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system. </p> + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = + "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE"; + + /** + * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent. + * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app + * The intent will have the following extra values:</p> + * <ul> + * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system.</p> + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String ACTION_CARRIER_SIGNAL_RESET = + "com.android.internal.telephony.CARRIER_SIGNAL_RESET"; + + // CARRIER_SIGNAL_ACTION extra keys + /** + * An string extra of redirected url upon {@link #ACTION_CARRIER_SIGNAL_REDIRECTED}. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_REDIRECTION_URL = "redirectionUrl"; + + /** + * An integer extra of error code upon {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED}. + * Check {@link DataFailCause} for all possible values. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_ERROR_CODE = "errorCode"; + + /** + * An string extra of corresponding apn type upon + * {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED}, + * {@link #ACTION_CARRIER_SIGNAL_REDIRECTED} and + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * @deprecated This is kept for backward compatibility reason. Use {@link #EXTRA_APN_TYPE_INT} + * instead. + * + * @hide + */ + @SystemApi + @Deprecated + @SuppressLint("ActionValue") + public static final String EXTRA_APN_TYPE = "apnType"; + + /** + * An string integer of corresponding apn type upon + * {@link #ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED}, + * {@link #ACTION_CARRIER_SIGNAL_REDIRECTED} and + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * Check {@link ApnSetting} TYPE_* for its values. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_APN_TYPE_INT = "apnTypeInt"; + + /** + * An string extra with the protocol of the apn connection (IP,IPV6, IPV4V6) upon + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * @deprecated This is kept for backward compatibility reason. + * Use {@link #EXTRA_APN_PROTOCOL_INT} instead. + * + * @hide + */ + @SystemApi + @Deprecated + @SuppressLint("ActionValue") + public static final String EXTRA_APN_PROTOCOL = "apnProto"; + + /** + * An integer extra with the protocol of the apn connection (IP,IPV6, IPV4V6) upon + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * Check {@link ApnSetting} PROTOCOL_* for its values. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt"; + + /** + * An integer extra indicating the pco id for the data upon + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_PCO_ID = "pcoId"; + + /** + * An extra of byte array of pco data read from modem upon + * {@link #ACTION_CARRIER_SIGNAL_PCO_VALUE} broadcasts. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_PCO_VALUE = "pcoValue"; + + /** + * An boolean extra indicating default network available upon + * {@link #ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE} broadcasts. + * @hide + */ + @SystemApi + @SuppressLint("ActionValue") + public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable"; + + /** * <p>Broadcast Action: The emergency call state is changed. * <ul> * <li><em>phoneInEmergencyCall</em> - A boolean value, true if phone in emergency call, @@ -1662,7 +1866,7 @@ public class TelephonyManager { public String getDeviceId(int slotIndex) { // FIXME this assumes phoneId == slotIndex try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(), @@ -1916,7 +2120,7 @@ public class TelephonyManager { private String getNaiBySubscriberId(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(), @@ -3605,7 +3809,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getSimSerialNumber(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(), @@ -3879,7 +4083,7 @@ public class TelephonyManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getSubscriberId(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(), @@ -3915,7 +4119,7 @@ public class TelephonyManager { @Nullable public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) { Rlog.e(TAG,"IMSI error: Subscriber Info is null"); return null; @@ -3958,7 +4162,7 @@ public class TelephonyManager { @SystemApi public void resetCarrierKeysForImsiEncryption() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) { Rlog.e(TAG, "IMSI error: Subscriber Info is null"); if (!isSystemProcess()) { @@ -4023,7 +4227,7 @@ public class TelephonyManager { */ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return; info.setCarrierInfoForImsiEncryption(mSubId, mContext.getOpPackageName(), imsiEncryptionInfo); @@ -4047,7 +4251,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(), @@ -4071,7 +4275,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getGroupIdLevel1(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(), @@ -4134,7 +4338,7 @@ public class TelephonyManager { return number; } try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(), @@ -4225,7 +4429,7 @@ public class TelephonyManager { return alphaTag; } try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(), @@ -4313,7 +4517,7 @@ public class TelephonyManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getMsisdn(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId()); @@ -4347,7 +4551,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getVoiceMailNumber(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(), @@ -4946,7 +5150,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getVoiceMailAlphaTag(int subId) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(), @@ -4994,7 +5198,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getIsimImpi() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; //get the Isim Impi based on subId @@ -5021,7 +5225,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; //get the Isim Domain based on subId @@ -5045,7 +5249,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; //get the Isim Impu based on subId @@ -5058,19 +5262,6 @@ public class TelephonyManager { } } - /** - * @hide - */ - @UnsupportedAppUsage - private IPhoneSubInfo getSubscriberInfo() { - // get it each time because that process crashes a lot - return IPhoneSubInfo.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getPhoneSubServiceRegisterer() - .get()); - } - /** * Device call state: No activity. */ @@ -5224,6 +5415,13 @@ public class TelephonyManager { public static final int DATA_DISCONNECTING = 4; /** + * To check the SDK version for {@link TelephonyManager#getDataState}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + private static final long GET_DATA_STATE_CODE_CHANGE = 147600208L; + + /** * Returns a constant indicating the current data connection state * (cellular). * @@ -5241,7 +5439,7 @@ public class TelephonyManager { int state = telephony.getDataStateForSubId( getSubId(SubscriptionManager.getActiveDataSubscriptionId())); if (state == TelephonyManager.DATA_DISCONNECTING - && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) { + && !Compatibility.isChangeEnabled(GET_DATA_STATE_CODE_CHANGE)) { return TelephonyManager.DATA_CONNECTED; } @@ -5303,6 +5501,13 @@ public class TelephonyManager { // /** + * To check the SDK version for {@link TelephonyManager#listen}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long LISTEN_CODE_CHANGE = 147600208L; + + /** * Registers a listener object to receive notification of changes * in specified telephony states. * <p> @@ -5341,7 +5546,7 @@ public class TelephonyManager { // subId from PhoneStateListener is deprecated Q on forward, use the subId from // TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q. int subId = mSubId; - if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) { + if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) { // since mSubId in PhoneStateListener is deprecated from Q on forward, this is // the only place to set mSubId and its for "informational" only. // TODO: remove this once we completely get rid of mSubId in PhoneStateListener @@ -6807,7 +7012,7 @@ public class TelephonyManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; //get the Isim Ist based on subId @@ -6829,7 +7034,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String[] getIsimPcscf() { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; //get the Isim Pcscf based on subId @@ -6910,7 +7115,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getIccAuthentication(int subId, int appType, int authType, String data) { try { - IPhoneSubInfo info = getSubscriberInfo(); + IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) return null; return info.getIccSimChallengeResponse(subId, appType, authType, data); @@ -12186,4 +12391,150 @@ public class TelephonyManager { } return false; } + + private static class DeathRecipient implements IBinder.DeathRecipient { + @Override + public void binderDied() { + resetServiceCache(); + } + } + + /** + * Reset everything in the service cache; if one handle died then they are + * all probably broken. + * @hide + */ + private static void resetServiceCache() { + synchronized (sCacheLock) { + if (sISub != null) { + sISub.asBinder().unlinkToDeath(sServiceDeath, 0); + sISub = null; + } + if (sISms != null) { + sISms.asBinder().unlinkToDeath(sServiceDeath, 0); + sISms = null; + } + if (sIPhoneSubInfo != null) { + sIPhoneSubInfo.asBinder().unlinkToDeath(sServiceDeath, 0); + sIPhoneSubInfo = null; + } + } + } + + /** + * @hide + */ + static IPhoneSubInfo getSubscriberInfoService() { + if (!sServiceHandleCacheEnabled) { + return IPhoneSubInfo.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getPhoneSubServiceRegisterer() + .get()); + } + + if (sIPhoneSubInfo == null) { + IPhoneSubInfo temp = IPhoneSubInfo.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getPhoneSubServiceRegisterer() + .get()); + synchronized (sCacheLock) { + if (sIPhoneSubInfo == null && temp != null) { + try { + sIPhoneSubInfo = temp; + sIPhoneSubInfo.asBinder().linkToDeath(sServiceDeath, 0); + } catch (Exception e) { + // something has gone horribly wrong + sIPhoneSubInfo = null; + } + } + } + } + return sIPhoneSubInfo; + } + + /** + * @hide + */ + static ISub getSubscriptionService() { + if (!sServiceHandleCacheEnabled) { + return ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); + } + + if (sISub == null) { + ISub temp = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); + synchronized (sCacheLock) { + if (sISub == null && temp != null) { + try { + sISub = temp; + sISub.asBinder().linkToDeath(sServiceDeath, 0); + } catch (Exception e) { + // something has gone horribly wrong + sISub = null; + } + } + } + } + return sISub; + } + + /** + * @hide + */ + static ISms getSmsService() { + if (!sServiceHandleCacheEnabled) { + return ISms.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSmsServiceRegisterer() + .get()); + } + + if (sISms == null) { + ISms temp = ISms.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSmsServiceRegisterer() + .get()); + synchronized (sCacheLock) { + if (sISms == null && temp != null) { + try { + sISms = temp; + sISms.asBinder().linkToDeath(sServiceDeath, 0); + } catch (Exception e) { + // something has gone horribly wrong + sISms = null; + } + } + } + } + return sISms; + } + + /** + * Disables service handle caching for tests that utilize mock services. + * @hide + */ + @VisibleForTesting + public static void disableServiceHandleCaching() { + sServiceHandleCacheEnabled = false; + } + + /** + * Reenables service handle caching. + * @hide + */ + @VisibleForTesting + public static void enableServiceHandleCaching() { + sServiceHandleCacheEnabled = true; + } } diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 7ffba7abffd6..6005f77605a6 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -34,6 +34,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.ims.aidl.IImsConfigCallback; import android.telephony.ims.feature.MmTelFeature; +import android.telephony.ims.feature.RcsFeature; import android.telephony.ims.stub.ImsConfigImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -546,6 +547,54 @@ public class ProvisioningManager { } /** + * Get the provisioning status for the IMS RCS capability specified. + * + * If provisioning is not required for the queried + * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method will always return + * {@code true}. + * + * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL + * @return true if the device is provisioned for the capability or does not require + * provisioning, false if the capability does require provisioning and has not been + * provisioned yet. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean getRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { + try { + return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Set the provisioning status for the IMS RCS capability using the specified subscription. + * + * Provisioning may or may not be required, depending on the carrier configuration. If + * provisioning is not required for the carrier associated with this subscription or the device + * does not support the capability/technology combination specified, this operation will be a + * no-op. + * + * @see CarrierConfigManager#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL + * @param isProvisioned true if the device is provisioned for the RCS capability specified, + * false otherwise. + */ + @WorkerThread + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setRcsProvisioningStatusForCapability( + @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability, + boolean isProvisioned) { + try { + getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability, + isProvisioned); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** * Notify the framework that an RCS autoconfiguration XML file has been received for * provisioning. * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index b846a1029c68..28f3974162b7 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1977,6 +1977,17 @@ interface ITelephony { */ boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech); + /** + * Get the provisioning status for the IMS Rcs capability specified. + */ + boolean getRcsProvisioningStatusForCapability(int subId, int capability); + + /** + * Set the provisioning status for the IMS Rcs capability using the specified subscription. + */ + void setRcsProvisioningStatusForCapability(int subId, int capability, + boolean isProvisioned); + /** Is the capability and tech flagged as provisioned in the cache */ boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech); diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 1fbe8cb49836..a15f73cf348d 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -328,85 +328,6 @@ public class TelephonyIntents { "android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED"; /** - * <p>Broadcast Action: when data connections get redirected with validation failure. - * intended for sim/account status checks and only sent to the specified carrier app - * The intent will have the following extra values:</p> - * <ul> - * <li>apnType</li><dd>A string with the apn type.</dd> - * <li>redirectionUrl</li><dd>redirection url string</dd> - * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> - * </ul> - * <p class="note">This is a protected intent that can only be sent by the system.</p> - */ - public static final String ACTION_CARRIER_SIGNAL_REDIRECTED = - "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"; - /** - * <p>Broadcast Action: when data connections setup fails. - * intended for sim/account status checks and only sent to the specified carrier app - * The intent will have the following extra values:</p> - * <ul> - * <li>apnType</li><dd>A string with the apn type.</dd> - * <li>errorCode</li><dd>A integer with dataFailCause.</dd> - * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> - * </ul> - * <p class="note">This is a protected intent that can only be sent by the system. </p> - */ - public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED = - "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED"; - - /** - * <p>Broadcast Action: when pco value is available. - * intended for sim/account status checks and only sent to the specified carrier app - * The intent will have the following extra values:</p> - * <ul> - * <li>apnType</li><dd>A string with the apn type.</dd> - * <li>apnProto</li><dd>A string with the protocol of the apn connection (IP,IPV6, - * IPV4V6)</dd> - * <li>pcoId</li><dd>An integer indicating the pco id for the data.</dd> - * <li>pcoValue</li><dd>A byte array of pco data read from modem.</dd> - * <li>subId</li><dd>Sub Id which associated the data connection.</dd> - * </ul> - * <p class="note">This is a protected intent that can only be sent by the system. </p> - */ - public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = - "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE"; - - /** - * <p>Broadcast Action: when system default network available/unavailable with - * carrier-disabled mobile data. Intended for carrier apps to set/reset carrier actions when - * other network becomes system default network, Wi-Fi for example. - * The intent will have the following extra values:</p> - * <ul> - * <li>defaultNetworkAvailable</li><dd>A boolean indicates default network available.</dd> - * <li>subId</li><dd>Sub Id which associated the default data.</dd> - * </ul> - * <p class="note">This is a protected intent that can only be sent by the system. </p> - */ - public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = - "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE"; - - /** - * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent. - * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app - * The intent will have the following extra values:</p> - * <ul> - * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd> - * </ul> - * <p class="note">This is a protected intent that can only be sent by the system.</p> - */ - public static final String ACTION_CARRIER_SIGNAL_RESET = - "com.android.internal.telephony.CARRIER_SIGNAL_RESET"; - - // CARRIER_SIGNAL_ACTION extra keys - public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl"; - public static final String EXTRA_ERROR_CODE_KEY = "errorCode"; - public static final String EXTRA_APN_TYPE_KEY = "apnType"; - public static final String EXTRA_APN_PROTO_KEY = "apnProto"; - public static final String EXTRA_PCO_ID_KEY = "pcoId"; - public static final String EXTRA_PCO_VALUE_KEY = "pcoValue"; - public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY = "defaultNetworkAvailable"; - - /** * Broadcast action to trigger CI OMA-DM Session. */ public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java index eed7159ffddc..ca4ba63142a2 100644 --- a/tests/net/common/java/android/net/CaptivePortalTest.java +++ b/tests/net/common/java/android/net/CaptivePortalTest.java @@ -44,6 +44,11 @@ public class CaptivePortalTest { } @Override + public void appRequest(final int request) throws RemoteException { + mCode = request; + } + + @Override public void logEvent(int eventId, String packageName) throws RemoteException { mCode = eventId; mPackageName = packageName; @@ -80,6 +85,12 @@ public class CaptivePortalTest { } @Test + public void testReevaluateNetwork() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork()); + assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED); + } + + @Test public void testLogEvent() { final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent( MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY, diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 0ab5c97d317e..11d5b250d752 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { @Override public Network getNetwork() { - return new Network(mNetworkAgent.netId); + return mNetworkAgent.network; } public void expectPreventReconnectReceived(long timeoutMs) { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b2d363e27839..1901a1db633b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -575,7 +575,7 @@ public class ConnectivityServiceTest { } }; - assertEquals(na.netId, nmNetworkCaptor.getValue().netId); + assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId); mNmCallbacks = nmCbCaptor.getValue(); mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 9e915aec6832..e863266c4b49 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -35,7 +35,6 @@ import android.net.ConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; import android.net.Network; -import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; @@ -75,7 +74,6 @@ public class LingerMonitorTest { @Mock INetd mNetd; @Mock INetworkManagementService mNMS; @Mock Context mCtx; - @Mock NetworkAgentConfig mAgentConfig; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; @@ -358,7 +356,7 @@ public class LingerMonitorTest { NetworkScore ns = new NetworkScore(); ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, - caps, ns, mCtx, null, mAgentConfig, mConnService, mNetd, mDnsResolver, mNMS, + caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE); nai.everValidated = true; return nai; diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index cf70f5d499d1..9b248878fe96 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -63,7 +63,6 @@ public class Nat464XlatTest { static final int NETID = 42; @Mock ConnectivityService mConnectivity; - @Mock NetworkAgentConfig mAgentConfig; @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; @Mock INetworkManagementService mNms; @@ -72,6 +71,7 @@ public class Nat464XlatTest { TestLooper mLooper; Handler mHandler; + NetworkAgentConfig mAgentConfig = new NetworkAgentConfig(); Nat464Xlat makeNat464Xlat() { return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) { diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 3623b1112bc6..469128b1e50b 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -800,7 +800,12 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config } // This is a normal reference. - return util::make_unique<Reference>(data, ref_type); + auto reference = util::make_unique<Reference>(data, ref_type); + if (res_value.dataType == android::Res_value::TYPE_DYNAMIC_REFERENCE || + res_value.dataType == android::Res_value::TYPE_DYNAMIC_ATTRIBUTE) { + reference->is_dynamic = true; + } + return reference; } break; } diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp index c016cb44af00..b08bf9a1ff17 100644 --- a/tools/aapt2/ResourceUtils_test.cpp +++ b/tools/aapt2/ResourceUtils_test.cpp @@ -109,6 +109,20 @@ TEST(ResourceUtilsTest, ParsePrivateReference) { EXPECT_TRUE(private_ref); } +TEST(ResourceUtilsTest, ParseBinaryDynamicReference) { + android::Res_value value = {}; + value.data = util::HostToDevice32(0x01); + value.dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE; + std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(ResourceType::kId, + android::ConfigDescription(), + android::ResStringPool(), value, + nullptr); + + Reference* ref = ValueCast<Reference>(item.get()); + EXPECT_TRUE(ref->is_dynamic); + EXPECT_EQ(ref->id.value().id, 0x01); +} + TEST(ResourceUtilsTest, FailToParseAutoCreateNonIdReference) { bool create = false; bool private_ref = false; diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 7498e132d943..8a2f5afa7255 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -269,6 +269,11 @@ message CompoundValue { } } +// Message holding a boolean, so it can be optionally encoded. +message Boolean { + bool value = 1; +} + // A value that is a reference to another resource. This reference can be by name or resource ID. message Reference { enum Type { @@ -289,6 +294,9 @@ message Reference { // Whether this reference is referencing a private resource (@*package:type/entry). bool private = 4; + + // Whether this reference is dynamic. + Boolean is_dynamic = 5; } // A value that represents an ID. This is just a placeholder, as ID values are used to occupy a diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index efbf636878f2..4cd6e930915d 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -634,6 +634,7 @@ static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* o std::string* out_error) { out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); out_ref->private_reference = pb_ref.private_(); + out_ref->is_dynamic = pb_ref.is_dynamic().value(); if (pb_ref.id() != 0) { out_ref->id = ResourceId(pb_ref.id()); diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index e4b3fce52166..d9f6c193fc2f 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -418,6 +418,9 @@ static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) pb_ref->set_private_(ref.private_reference); pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type)); + if (ref.is_dynamic) { + pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic); + } } template <typename T> diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index e7f23302652c..61a8335e17a7 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -608,4 +608,41 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { ASSERT_FALSE(search_result.value().entry->overlayable_item); } +TEST(ProtoSerializeTest, SerializeAndDeserializeDynamicReference) { + Reference ref(ResourceId(0x00010001)); + ref.is_dynamic = true; + + pb::Item pb_item; + SerializeItemToPb(ref, &pb_item); + + ASSERT_TRUE(pb_item.has_ref()); + EXPECT_EQ(pb_item.ref().id(), ref.id.value().id); + EXPECT_TRUE(pb_item.ref().is_dynamic().value()); + + std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(), + android::ConfigDescription(), nullptr, + nullptr, nullptr); + Reference* actual_ref = ValueCast<Reference>(item.get()); + EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id); + EXPECT_TRUE(actual_ref->is_dynamic); +} + +TEST(ProtoSerializeTest, SerializeAndDeserializeNonDynamicReference) { + Reference ref(ResourceId(0x00010001)); + + pb::Item pb_item; + SerializeItemToPb(ref, &pb_item); + + ASSERT_TRUE(pb_item.has_ref()); + EXPECT_EQ(pb_item.ref().id(), ref.id.value().id); + EXPECT_FALSE(pb_item.ref().has_is_dynamic()); + + std::unique_ptr<Item> item = DeserializeItemFromPb(pb_item, android::ResStringPool(), + android::ConfigDescription(), nullptr, + nullptr, nullptr); + Reference* actual_ref = ValueCast<Reference>(item.get()); + EXPECT_EQ(actual_ref->id.value().id, ref.id.value().id); + EXPECT_FALSE(actual_ref->is_dynamic); +} + } // namespace aapt diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index 0b82a3dcebc4..7bbac137f998 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -291,6 +291,15 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, } if (field->options().GetExtension(os::statsd::state_field_option).option() == + os::statsd::StateField::PRIMARY_FIELD_FIRST_UID) { + if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) { + errorCount++; + } else { + atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID); + } + } + + if (field->options().GetExtension(os::statsd::state_field_option).option() == os::statsd::StateField::EXCLUSIVE) { if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 3efdd520d7f5..87d4d5db0cee 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -36,6 +36,8 @@ using google::protobuf::FieldDescriptor; const int PULL_ATOM_START_ID = 10000; +const int FIRST_UID_IN_CHAIN_ID = 0; + /** * The types for atom parameters. */ diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp index 54a9982bb5c2..66ae96401974 100644 --- a/tools/stats_log_api_gen/atoms_info_writer.cpp +++ b/tools/stats_log_api_gen/atoms_info_writer.cpp @@ -25,6 +25,8 @@ namespace android { namespace stats_log_api_gen { static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) { + fprintf(out, "static int FIRST_UID_IN_CHAIN = 0;\n"); + fprintf(out, "struct StateAtomFieldOptions {\n"); fprintf(out, " std::vector<int> primaryFields;\n"); fprintf(out, " int exclusiveField;\n"); diff --git a/wifi/Android.bp b/wifi/Android.bp index 286be0b82db7..6326f14bc6fd 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -52,18 +52,43 @@ test_access_hidden_api_whitelist = [ "//external/robolectric-shadows:__subpackages__", ] +// wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility +// classes before they are renamed. java_library { - name: "framework-wifi", + name: "framework-wifi-pre-jarjar", // TODO(b/140299412) should be core_current once we build against framework-system-stubs sdk_version: "core_platform", + static_libs: [ + "framework-wifi-util-lib", + "android.hardware.wifi-V1.0-java-constants", + ], libs: [ // TODO(b/140299412) should be framework-system-stubs once we fix all @hide dependencies "framework-minus-apex", - "unsupportedappusage", + "framework-annotations-lib", + "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage + "unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage ], srcs: [ ":framework-wifi-updatable-sources", ], + installable: false, + visibility: [ + "//frameworks/opt/net/wifi/service", + "//frameworks/opt/net/wifi/tests/wifitests", + ], +} + +// post-jarjar version of framework-wifi +java_library { + name: "framework-wifi", + // TODO(b/140299412) should be core_current once we build against framework-system-stubs + sdk_version: "core_platform", + static_libs: [ + "framework-wifi-pre-jarjar", + ], + jarjar_rules: ":wifi-jarjar-rules", + installable: true, optimize: { enabled: false @@ -122,3 +147,8 @@ java_defaults { ], visibility: test_access_hidden_api_whitelist, } + +filegroup { + name: "wifi-jarjar-rules", + srcs: ["jarjar-rules.txt"], +} diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt new file mode 100644 index 000000000000..8f720407f4d7 --- /dev/null +++ b/wifi/jarjar-rules.txt @@ -0,0 +1,40 @@ +rule android.net.InterfaceConfigurationParcel* @0 +rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1 + +# We don't jar-jar the entire package because, we still use some classes (like +# AsyncChannel in com.android.internal.util) from these packages which are not +# inside our jar (currently in framework.jar, but will be in wifisdk.jar in the future). +rule com.android.internal.util.FastXmlSerializer* com.android.server.x.wifi.util.FastXmlSerializer@1 +rule com.android.internal.util.HexDump* com.android.server.x.wifi.util.HexDump@1 +rule com.android.internal.util.IState* com.android.server.x.wifi.util.IState@1 +rule com.android.internal.util.MessageUtils* com.android.server.x.wifi.util.MessageUtils@1 +rule com.android.internal.util.State* com.android.server.x.wifi.util.State@1 +rule com.android.internal.util.StateMachine* com.android.server.x.wifi.util.StateMachine@1 +rule com.android.internal.util.WakeupMessage* com.android.server.x.wifi.util.WakeupMessage@1 + +rule android.util.BackupUtils* com.android.server.x.wifi.util.BackupUtils@1 +rule android.util.LocalLog* com.android.server.x.wifi.util.LocalLog@1 +rule android.util.Rational* com.android.server.x.wifi.util.Rational@1 + +rule android.os.BasicShellCommandHandler* com.android.server.x.wifi.os.BasicShellCommandHandler@1 + +# Use our statically linked bouncy castle library +rule org.bouncycastle.** com.android.server.x.wifi.bouncycastle.@1 +# Use our statically linked protobuf library +rule com.google.protobuf.** com.android.server.x.wifi.protobuf.@1 +# use statically linked SystemMessageProto +rule com.android.internal.messages.SystemMessageProto* com.android.server.x.wifi.messages.SystemMessageProto@1 +# Use our statically linked PlatformProperties library +rule android.sysprop.** com.android.server.x.wifi.sysprop.@1 + + +# used by both framework-wifi and wifi-service +rule android.content.pm.BaseParceledListSlice* android.x.net.wifi.util.BaseParceledListSlice@1 +rule android.content.pm.ParceledListSlice* android.x.net.wifi.util.ParceledListSlice@1 +rule android.net.shared.Inet4AddressUtils* android.x.net.wifi.util.Inet4AddressUtils@1 +rule android.os.HandlerExecutor* android.x.net.wifi.util.HandlerExecutor@1 +rule android.telephony.Annotation* android.x.net.wifi.util.TelephonyAnnotation@1 +rule com.android.internal.util.AsyncChannel* android.x.net.wifi.util.AsyncChannel@1 +rule com.android.internal.util.AsyncService* android.x.net.wifi.util.AsyncService@1 +rule com.android.internal.util.Preconditions* android.x.net.wifi.util.Preconditions@1 +rule com.android.internal.util.Protocol* android.x.net.wifi.util.Protocol@1 diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 729ac14b8b73..a8a31eba303c 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -233,16 +233,20 @@ public class WifiManager { public @interface SuggestionConnectionStatusCode {} /** - * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently - * @hide + * Broadcast intent action indicating whether Wi-Fi scanning is currently available. + * Available extras: + * - {@link #EXTRA_SCAN_AVAILABLE} */ - public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_WIFI_SCAN_AVAILABLE = + "android.net.wifi.action.WIFI_SCAN_AVAILABLE"; /** - * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED - * @hide + * A boolean extra indicating whether scanning is currently available. + * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABLE}. + * Its value is true if scanning is currently available, false otherwise. */ - public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled"; + public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE"; /** * Broadcast intent action indicating that the credential of a Wi-Fi network diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 2c39c32ac81e..4f602fac7a36 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -833,6 +833,7 @@ public class WifiScanner { * delivered to the listener. It is possible that onFullResult will not be called for all * results of the first scan if the listener was registered during the scan. * + * @param executor the Executor on which to run the callback. * @param listener specifies the object to report events to. This object is also treated as a * key for this request, and must also be specified to cancel the request. * Multiple requests should also not share this object. @@ -955,15 +956,32 @@ public class WifiScanner { * starts a single scan and reports results asynchronously * @param settings specifies various parameters for the scan; for more information look at * {@link ScanSettings} - * @param workSource WorkSource to blame for power usage * @param listener specifies the object to report events to. This object is also treated as a * key for this scan, and must also be specified to cancel the scan. Multiple * scans should also not share this object. + * @param workSource WorkSource to blame for power usage */ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) { + startScan(settings, null, listener, workSource); + } + + /** + * starts a single scan and reports results asynchronously + * @param settings specifies various parameters for the scan; for more information look at + * {@link ScanSettings} + * @param executor the Executor on which to run the callback. + * @param listener specifies the object to report events to. This object is also treated as a + * key for this scan, and must also be specified to cancel the scan. Multiple + * scans should also not share this object. + * @param workSource WorkSource to blame for power usage + * @hide + */ + @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor, + ScanListener listener, WorkSource workSource) { Objects.requireNonNull(listener, "listener cannot be null"); - int key = addListener(listener); + int key = addListener(listener, executor); if (key == INVALID_KEY) return; validateChannel(); Bundle scanParams = new Bundle(); @@ -1029,16 +1047,17 @@ public class WifiScanner { * {@link ScanSettings} * @param pnoSettings specifies various parameters for PNO; for more information look at * {@link PnoSettings} + * @param executor the Executor on which to run the callback. * @param listener specifies the object to report events to. This object is also treated as a * key for this scan, and must also be specified to cancel the scan. Multiple * scans should also not share this object. * {@hide} */ public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, - PnoScanListener listener) { + @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) { Objects.requireNonNull(listener, "listener cannot be null"); Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null"); - int key = addListener(listener); + int key = addListener(listener, executor); if (key == INVALID_KEY) return; validateChannel(); pnoSettings.isConnected = true; @@ -1057,10 +1076,10 @@ public class WifiScanner { */ @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, - PnoScanListener listener) { + @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) { Objects.requireNonNull(listener, "listener cannot be null"); Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null"); - int key = addListener(listener); + int key = addListener(listener, executor); if (key == INVALID_KEY) return; validateChannel(); pnoSettings.isConnected = false; diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java index 1af0bcbf3f30..0cc76b68a15e 100644 --- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java @@ -366,7 +366,7 @@ public class WifiScannerTest { /** * Test behavior of {@link WifiScanner#startDisconnectedPnoScan(ScanSettings, PnoSettings, - * WifiScanner.PnoScanListener)} + * Executor, WifiScanner.PnoScanListener)} * @throws Exception */ @Test @@ -375,7 +375,8 @@ public class WifiScannerTest { PnoSettings pnoSettings = new PnoSettings(); WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class); - mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener); + mWifiScanner.startDisconnectedPnoScan( + scanSettings, pnoSettings, mock(Executor.class), pnoScanListener); mLooper.dispatchAll(); ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); @@ -396,7 +397,7 @@ public class WifiScannerTest { /** * Test behavior of {@link WifiScanner#startConnectedPnoScan(ScanSettings, PnoSettings, - * WifiScanner.PnoScanListener)} + * Executor, WifiScanner.PnoScanListener)} * @throws Exception */ @Test @@ -405,7 +406,8 @@ public class WifiScannerTest { PnoSettings pnoSettings = new PnoSettings(); WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class); - mWifiScanner.startConnectedPnoScan(scanSettings, pnoSettings, pnoScanListener); + mWifiScanner.startConnectedPnoScan( + scanSettings, pnoSettings, mock(Executor.class), pnoScanListener); mLooper.dispatchAll(); ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); @@ -426,7 +428,7 @@ public class WifiScannerTest { /** * Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)} - * WifiScanner.PnoScanListener)} + * Executor, WifiScanner.PnoScanListener)} * @throws Exception */ @Test @@ -435,7 +437,8 @@ public class WifiScannerTest { PnoSettings pnoSettings = new PnoSettings(); WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class); - mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener); + mWifiScanner.startDisconnectedPnoScan( + scanSettings, pnoSettings, mock(Executor.class), pnoScanListener); mLooper.dispatchAll(); mWifiScanner.stopPnoScan(pnoScanListener); mLooper.dispatchAll(); |