diff options
88 files changed, 4941 insertions, 943 deletions
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS index a060ad9a5a7e..7e7feafdc5a5 100644 --- a/apct-tests/perftests/OWNERS +++ b/apct-tests/perftests/OWNERS @@ -1,2 +1,11 @@ -timmurray@google.com +balejs@google.com +carmenjackson@google.com +cfijalkovich@google.com +dualli@google.com +edgararriaga@google.com +jpakaravoor@google.com +kevinjeon@google.com philipcuadra@google.com +shombert@google.com +timmurray@google.com +wessam@google.com diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index c2ee6dcd13b2..405d6f6f5f63 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -107,6 +107,8 @@ public final class Sm { runStartCheckpoint(); } else if ("supports-checkpoint".equals(op)) { runSupportsCheckpoint(); + } else if ("unmount-app-data-dirs".equals(op)) { + runDisableAppDataIsolation(); } else { throw new IllegalArgumentException(); } @@ -253,6 +255,13 @@ public final class Sm { System.out.println(result.get()); } + public void runDisableAppDataIsolation() throws RemoteException { + final String pkgName = nextArg(); + final int pid = Integer.parseInt(nextArg()); + final int userId = Integer.parseInt(nextArg()); + mSm.disableAppDataIsolation(pkgName, pid, userId); + } + public void runForget() throws RemoteException { final String fsUuid = nextArg(); if ("all".equals(fsUuid)) { @@ -373,6 +382,8 @@ public final class Sm { System.err.println(""); System.err.println(" sm supports-checkpoint"); System.err.println(""); + System.err.println(" sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID"); + System.err.println(""); return 1; } } diff --git a/core/api/current.txt b/core/api/current.txt index 9f4af3791d85..a7071036f212 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -385,6 +385,7 @@ package android { field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d field public static final int canControlMagnification = 16844039; // 0x1010507 + field public static final int canPauseRecording = 16844311; // 0x1010617 field public static final int canPerformGestures = 16844045; // 0x101050d field public static final int canRecord = 16844060; // 0x101051c field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8 @@ -10186,6 +10187,7 @@ package android.content { field public static final String BIOMETRIC_SERVICE = "biometric"; field public static final String BLOB_STORE_SERVICE = "blob_store"; field public static final String BLUETOOTH_SERVICE = "bluetooth"; + field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CAMERA_SERVICE = "camera"; field public static final String CAPTIONING_SERVICE = "captioning"; field public static final String CARRIER_CONFIG_SERVICE = "carrier_config"; @@ -24265,6 +24267,7 @@ package android.media.tv { } public final class TvInputInfo implements android.os.Parcelable { + method public boolean canPauseRecording(); method public boolean canRecord(); method @Deprecated public android.content.Intent createSettingsIntent(); method public android.content.Intent createSetupIntent(); @@ -24298,6 +24301,7 @@ package android.media.tv { public static final class TvInputInfo.Builder { ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName); method public android.media.tv.TvInputInfo build(); + method @NonNull public android.media.tv.TvInputInfo.Builder setCanPauseRecording(boolean); method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean); method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle); method public android.media.tv.TvInputInfo.Builder setTunerCount(int); @@ -24389,7 +24393,9 @@ package android.media.tv { method public void notifyRecordingStopped(android.net.Uri); method public void notifyTuned(android.net.Uri); method public void onAppPrivateCommand(@NonNull String, android.os.Bundle); + method public void onPauseRecording(@NonNull android.os.Bundle); method public abstract void onRelease(); + method public void onResumeRecording(@NonNull android.os.Bundle); method public abstract void onStartRecording(@Nullable android.net.Uri); method public void onStartRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle); method public abstract void onStopRecording(); @@ -24439,7 +24445,11 @@ package android.media.tv { public class TvRecordingClient { ctor public TvRecordingClient(android.content.Context, String, @NonNull android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler); + method public void pauseRecording(); + method public void pauseRecording(@NonNull android.os.Bundle); method public void release(); + method public void resumeRecording(); + method public void resumeRecording(@NonNull android.os.Bundle); method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle); method public void startRecording(@Nullable android.net.Uri); method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle); @@ -29587,6 +29597,24 @@ package android.os { method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int); } + public final class BugreportManager { + method public void cancelBugreport(); + method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + } + + public abstract static class BugreportManager.BugreportCallback { + ctor public BugreportManager.BugreportCallback(); + method public void onEarlyReportFinished(); + method public void onError(int); + method public void onFinished(); + method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float); + field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5 + field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 + field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 + field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 + field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 + } + public class Build { ctor public Build(); method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions(); @@ -40486,6 +40514,12 @@ package android.telephony { field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1 } + public final class PhoneCapability implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR; + } + public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher { ctor public PhoneNumberFormattingTextWatcher(); ctor public PhoneNumberFormattingTextWatcher(String); @@ -40555,10 +40589,10 @@ package android.telephony { public class PhoneStateListener { ctor public PhoneStateListener(); - ctor public PhoneStateListener(@NonNull java.util.concurrent.Executor); + ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor); method public void onActiveDataSubscriptionIdChanged(int); method public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo); - method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int); method public void onCallForwardingIndicatorChanged(boolean); method public void onCallStateChanged(int, String); method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>); @@ -40566,36 +40600,140 @@ package android.telephony { method public void onDataActivity(int); method public void onDataConnectionStateChanged(int); method public void onDataConnectionStateChanged(int, int); - method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo); + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo); method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>); - method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); method public void onMessageWaitingIndicatorChanged(boolean); - method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState); method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int); method public void onServiceStateChanged(android.telephony.ServiceState); method @Deprecated public void onSignalStrengthChanged(int); method public void onSignalStrengthsChanged(android.telephony.SignalStrength); method public void onUserMobileDataStateChanged(boolean); - field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000 - field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000 - field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000 - field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8 - field public static final int LISTEN_CALL_STATE = 32; // 0x20 - field public static final int LISTEN_CELL_INFO = 1024; // 0x400 - field public static final int LISTEN_CELL_LOCATION = 16; // 0x10 - field public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80 - field public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40 - field public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000 - field public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000 - field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000 - field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4 + field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000 + field @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8 + field @Deprecated public static final int LISTEN_CALL_STATE = 32; // 0x20 + field @Deprecated public static final int LISTEN_CELL_INFO = 1024; // 0x400 + field @Deprecated public static final int LISTEN_CELL_LOCATION = 16; // 0x10 + field @Deprecated public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80 + field @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40 + field @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000 + field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000 + field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4 field public static final int LISTEN_NONE = 0; // 0x0 - field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 - field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000 - field public static final int LISTEN_SERVICE_STATE = 1; // 0x1 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000 + field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1 field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2 - field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100 - field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000 + field @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100 + field @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000 + } + + public static interface PhoneStateListener.ActiveDataSubscriptionIdChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int); + } + + public static interface PhoneStateListener.AlwaysReportedSignalStrengthChangedListener { + method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength); + } + + public static interface PhoneStateListener.BarringInfoChangedListener { + method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo); + } + + public static interface PhoneStateListener.CallDisconnectCauseChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int); + } + + public static interface PhoneStateListener.CallForwardingIndicatorChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean); + } + + public static interface PhoneStateListener.CallStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String); + } + + public static interface PhoneStateListener.CarrierNetworkChangeListener { + method public void onCarrierNetworkChange(boolean); + } + + public static interface PhoneStateListener.CellInfoChangedListener { + method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>); + } + + public static interface PhoneStateListener.CellLocationChangedListener { + method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation); + } + + public static interface PhoneStateListener.DataActivationStateChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int); + } + + public static interface PhoneStateListener.DataActivityListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int); + } + + public static interface PhoneStateListener.DataConnectionStateChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int); + } + + public static interface PhoneStateListener.DisplayInfoChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo); + } + + public static interface PhoneStateListener.EmergencyNumberListChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>); + } + + public static interface PhoneStateListener.ImsCallDisconnectCauseChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); + } + + public static interface PhoneStateListener.MessageWaitingIndicatorChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean); + } + + public static interface PhoneStateListener.PhoneCapabilityChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability); + } + + public static interface PhoneStateListener.PreciseDataConnectionStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState); + } + + public static interface PhoneStateListener.RegistrationFailedListener { + method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int); + } + + public static interface PhoneStateListener.ServiceStateChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState); + } + + public static interface PhoneStateListener.SignalStrengthsChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength); + } + + public static interface PhoneStateListener.UserMobileDataStateChangedListener { + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean); + } + + public final class PhysicalChannelConfig implements android.os.Parcelable { + method public int describeContents(); + method public int getCellBandwidthDownlink(); + method public int getChannelNumber(); + method public int getConnectionStatus(); + method public int getNetworkType(); + method @IntRange(from=0, to=1007) public int getPhysicalCellId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff + field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 + field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2 + field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR; + field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff } public final class PreciseDataConnectionState implements android.os.Parcelable { @@ -40677,6 +40815,49 @@ package android.telephony { field public static final int INVALID = 2147483647; // 0x7fffffff } + public final class SignalStrengthUpdateRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos(); + method public boolean isReportingRequestedWhileIdle(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR; + } + + public static final class SignalStrengthUpdateRequest.Builder { + ctor public SignalStrengthUpdateRequest.Builder(); + method @NonNull public android.telephony.SignalStrengthUpdateRequest build(); + method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean); + method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>); + } + + public final class SignalThresholdInfo implements android.os.Parcelable { + method public int describeContents(); + method public static int getMaximumNumberOfThresholdsAllowed(); + method public static int getMinimumNumberOfThresholdsAllowed(); + method public int getRadioAccessNetworkType(); + method public int getSignalMeasurementType(); + method @NonNull public int[] getThresholds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalThresholdInfo> CREATOR; + field public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2; // 0x2 + field public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3; // 0x3 + field public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4; // 0x4 + field public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1; // 0x1 + field public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5; // 0x5 + field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6; // 0x6 + field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7; // 0x7 + field public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; // 0x8 + field public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0; // 0x0 + } + + public static final class SignalThresholdInfo.Builder { + ctor public SignalThresholdInfo.Builder(); + method @NonNull public android.telephony.SignalThresholdInfo build(); + method @NonNull public android.telephony.SignalThresholdInfo.Builder setRadioAccessNetworkType(int); + method @NonNull public android.telephony.SignalThresholdInfo.Builder setSignalMeasurementType(int); + method @NonNull public android.telephony.SignalThresholdInfo.Builder setThresholds(@NonNull int[]); + } + public final class SmsManager { method public String createAppSpecificSmsToken(android.app.PendingIntent); method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent); @@ -41106,7 +41287,8 @@ package android.telephony { method public boolean isVoiceCapable(); method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle); method public boolean isWorldPhone(); - method public void listen(android.telephony.PhoneStateListener, int); + method @Deprecated public void listen(android.telephony.PhoneStateListener, int); + method public void registerPhoneStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.PhoneStateListener); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback); method public void sendDialerSpecialCode(String); @@ -41129,6 +41311,7 @@ package android.telephony { method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri); method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int); + method public void unregisterPhoneStateListener(@NonNull android.telephony.PhoneStateListener); method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE"; field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 03e80fc4a7c7..08644489c2db 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1684,7 +1684,6 @@ package android.content { field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String BACKUP_SERVICE = "backup"; field public static final String BATTERY_STATS_SERVICE = "batterystats"; - field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; field public static final String ETHERNET_SERVICE = "ethernet"; @@ -7046,24 +7045,10 @@ package android.os { } public final class BugreportManager { - method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport(); method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence); method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); } - public abstract static class BugreportManager.BugreportCallback { - ctor public BugreportManager.BugreportCallback(); - method public void onEarlyReportFinished(); - method public void onError(int); - method public void onFinished(); - method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float); - field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5 - field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 - field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 - field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 - field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 - } - public final class BugreportParams { ctor public BugreportParams(int); method public int getMode(); @@ -9813,17 +9798,87 @@ package android.telephony { method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int); method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber); method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int); - method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState); + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState); method public void onRadioPowerStateChanged(int); method public void onSrvccStateChanged(int); method public void onVoiceActivationStateChanged(int); - field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 - field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 - field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 - field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800 - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000 - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000 - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000 + field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17 + field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa + field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a + field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4 + field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6 + field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11 + field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb + field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5 + field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13 + field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe + field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22 + field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15 + field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c + field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3 + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf + field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d + field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e + field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18 + field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f + field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1 + field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9 + field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2 + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10 + field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14 + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000 + field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000 + } + + public static interface PhoneStateListener.CallAttributesChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); + } + + public static interface PhoneStateListener.DataEnabledChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int); + } + + public static interface PhoneStateListener.OutgoingEmergencyCallListener { + method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int); + } + + public static interface PhoneStateListener.OutgoingEmergencySmsListener { + method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int); + } + + public static interface PhoneStateListener.PhysicalChannelConfigChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>); + } + + public static interface PhoneStateListener.PreciseCallStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState); + } + + public static interface PhoneStateListener.RadioPowerStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int); + } + + public static interface PhoneStateListener.SrvccStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int); + } + + public static interface PhoneStateListener.VoiceActivationStateChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int); } public final class PinResult implements android.os.Parcelable { diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index be1681bc7cc6..66a832505ead 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -223,7 +223,7 @@ interface IActivityTaskManager { */ IBinder requestStartActivityPermissionToken(in IBinder delegatorToken); - void releaseSomeActivities(in IApplicationThread app); + oneway void releaseSomeActivities(in IApplicationThread app); Bitmap getTaskDescriptionIcon(in String filename, int userId); void registerTaskStackListener(in ITaskStackListener listener); void unregisterTaskStackListener(in ITaskStackListener listener); diff --git a/core/java/android/app/search/OWNERS b/core/java/android/app/search/OWNERS new file mode 100644 index 000000000000..92835c2b0626 --- /dev/null +++ b/core/java/android/app/search/OWNERS @@ -0,0 +1,2 @@ +hyunyoungs@google.com +sfufa@google.com diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 92ede1ca45fb..e0813cc83b1d 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4999,9 +4999,7 @@ public abstract class Context { * Service to capture a bugreport. * @see #getSystemService(String) * @see android.os.BugreportManager - * @hide */ - @SystemApi public static final String BUGREPORT_SERVICE = "bugreport"; /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 8742ecbd2570..ce0ed5bc0553 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -72,7 +72,6 @@ import com.android.internal.util.Protocol; import libcore.net.event.NetworkEventDispatcher; -import java.io.FileDescriptor; import java.io.IOException; import java.io.UncheckedIOException; import java.lang.annotation.Retention; @@ -1958,6 +1957,12 @@ public class ConnectivityManager { return k; } + // Construct an invalid fd. + private ParcelFileDescriptor createInvalidFd() { + final int invalidFd = -1; + return ParcelFileDescriptor.adoptFd(invalidFd); + } + /** * Request that keepalives be started on a IPsec NAT-T socket. * @@ -1988,7 +1993,7 @@ public class ConnectivityManager { } catch (IOException ignored) { // Construct an invalid fd, so that if the user later calls start(), it will fail with // ERROR_INVALID_SOCKET. - dup = new ParcelFileDescriptor(new FileDescriptor()); + dup = createInvalidFd(); } return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source, destination, executor, callback); @@ -2030,7 +2035,7 @@ public class ConnectivityManager { } catch (IOException ignored) { // Construct an invalid fd, so that if the user later calls start(), it will fail with // ERROR_INVALID_SOCKET. - dup = new ParcelFileDescriptor(new FileDescriptor()); + dup = createInvalidFd(); } return new NattSocketKeepalive(mService, network, dup, INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback); @@ -2067,7 +2072,7 @@ public class ConnectivityManager { } catch (UncheckedIOException ignored) { // Construct an invalid fd, so that if the user later calls start(), it will fail with // ERROR_INVALID_SOCKET. - dup = new ParcelFileDescriptor(new FileDescriptor()); + dup = createInvalidFd(); } return new TcpSocketKeepalive(mService, network, dup, executor, callback); } diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java index 58ea91573775..bb91f893c916 100644 --- a/core/java/android/net/metrics/IpConnectivityLog.java +++ b/core/java/android/net/metrics/IpConnectivityLog.java @@ -137,7 +137,7 @@ public class IpConnectivityLog { * @return true if the event was successfully logged. */ public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) { - return log(network.netId, transports, data); + return log(network.getNetId(), transports, data); } /** diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 039360a69a3a..d531cdb2a6e9 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,8 +15,6 @@ */ package android.net.vcn; -import static android.net.NetworkCapabilities.NetCapability; - import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntRange; @@ -233,7 +231,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean hasExposedCapability(@NetCapability int capability) { + public boolean hasExposedCapability(int capability) { checkValidCapability(capability); return mExposedCapabilities.contains(capability); @@ -254,7 +252,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean requiresUnderlyingCapability(@NetCapability int capability) { + public boolean requiresUnderlyingCapability(int capability) { checkValidCapability(capability); return mUnderlyingCapabilities.contains(capability); @@ -341,7 +339,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder addExposedCapability(@NetCapability int exposedCapability) { + public Builder addExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); @@ -357,7 +355,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder removeExposedCapability(@NetCapability int exposedCapability) { + public Builder removeExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -373,7 +371,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder addRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.add(underlyingCapability); @@ -393,7 +391,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder removeRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.remove(underlyingCapability); diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java new file mode 100644 index 000000000000..4d8cf91621ba --- /dev/null +++ b/core/java/android/net/vcn/VcnTransportInfo.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2021 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.net.vcn; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.TransportInfo; +import android.net.wifi.WifiInfo; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.SubscriptionManager; + +import java.util.Objects; + +/** + * VcnTransportInfo contains information about the VCN's underlying transports for SysUi. + * + * <p>Presence of this class in the NetworkCapabilities.TransportInfo implies that the network is a + * VCN. + * + * <p>VcnTransportInfo must exist on top of either an underlying Wifi or Cellular Network. If the + * underlying Network is WiFi, the subId will be {@link + * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo + * will be {@code null}. + * + * @hide + */ +public class VcnTransportInfo implements TransportInfo, Parcelable { + @Nullable private final WifiInfo mWifiInfo; + private final int mSubId; + + public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { + this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + public VcnTransportInfo(int subId) { + this(null /* wifiInfo */, subId); + } + + private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) { + if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + throw new IllegalArgumentException( + "VcnTransportInfo requires either non-null WifiInfo or valid subId"); + } + + mWifiInfo = wifiInfo; + mSubId = subId; + } + + /** + * Get the {@link WifiInfo} for this VcnTransportInfo. + * + * <p>If the underlying Network for the associated VCN is Cellular, returns null. + * + * @return the WifiInfo if there is an underlying WiFi connection, else null. + */ + @Nullable + public WifiInfo getWifiInfo() { + return mWifiInfo; + } + + /** + * Get the subId for the VCN Network associated with this VcnTransportInfo. + * + * <p>If the underlying Network for the associated VCN is WiFi, returns {@link + * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * + * @return the Subscription ID if a cellular underlying Network is present, else {@link + * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}. + */ + public int getSubId() { + return mSubId; + } + + @Override + public int hashCode() { + return Objects.hash(mWifiInfo, mSubId); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof VcnTransportInfo)) return false; + final VcnTransportInfo that = (VcnTransportInfo) o; + + return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId; + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) {} + + /** Implement the Parcelable interface */ + public static final @NonNull Creator<VcnTransportInfo> CREATOR = + new Creator<VcnTransportInfo>() { + public VcnTransportInfo createFromParcel(Parcel in) { + // return null instead of a default VcnTransportInfo to avoid leaking + // information about this being a VCN Network (instead of macro cellular, etc) + return null; + } + + public VcnTransportInfo[] newArray(int size) { + return new VcnTransportInfo[size]; + } + }; +} diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 46ad7b880a37..305c686f8657 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -22,11 +22,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.ActivityManager; import android.content.Context; -import android.os.Handler; import android.util.Log; import android.widget.Toast; @@ -41,12 +41,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; -/** - * Class that provides a privileged API to capture and consume bugreports. - * - * @hide - */ -@SystemApi +/** Class that provides a privileged API to capture and consume bugreports. */ @SystemService(Context.BUGREPORT_SERVICE) public final class BugreportManager { @@ -61,28 +56,30 @@ public final class BugreportManager { mBinder = binder; } - /** - * An interface describing the callback for bugreport progress and status. - */ + /** An interface describing the callback for bugreport progress and status. */ public abstract static class BugreportCallback { - /** @hide */ + /** + * Possible error codes taking a bugreport can encounter. + * + * @hide + */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = { - BUGREPORT_ERROR_INVALID_INPUT, - BUGREPORT_ERROR_RUNTIME, - BUGREPORT_ERROR_USER_DENIED_CONSENT, - BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT, - BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS - }) - - /** Possible error codes taking a bugreport can encounter */ + @IntDef( + prefix = {"BUGREPORT_ERROR_"}, + value = { + BUGREPORT_ERROR_INVALID_INPUT, + BUGREPORT_ERROR_RUNTIME, + BUGREPORT_ERROR_USER_DENIED_CONSENT, + BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT, + BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS + }) public @interface BugreportErrorCode {} /** The input options were invalid */ public static final int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT; - /** A runtime error occured */ + /** A runtime error occurred */ public static final int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR; @@ -100,6 +97,7 @@ public final class BugreportManager { /** * Called when there is a progress update. + * * @param progress the progress in [0.0, 100.0] */ public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {} @@ -114,14 +112,12 @@ public final class BugreportManager { * out, but the bugreport could be available in the internal directory of dumpstate for * manual retrieval. * - * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the - * caller should try later, as only one bugreport can be in progress at a time. + * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller + * should try later, as only one bugreport can be in progress at a time. */ public void onError(@BugreportErrorCode int errorCode) {} - /** - * Called when taking bugreport finishes successfully. - */ + /** Called when taking bugreport finishes successfully. */ public void onFinished() {} /** @@ -138,20 +134,23 @@ public final class BugreportManager { * seconds to return in the worst case. {@code callback} will receive progress and status * updates. * - * <p>The bugreport artifacts will be copied over to the given file descriptors only if the - * user consents to sharing with the calling app. + * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user + * consents to sharing with the calling app. * * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}. * - * @param bugreportFd file to write the bugreport. This should be opened in write-only, - * append mode. - * @param screenshotFd file to write the screenshot, if necessary. This should be opened - * in write-only, append mode. + * @param bugreportFd file to write the bugreport. This should be opened in write-only, append + * mode. + * @param screenshotFd file to write the screenshot, if necessary. This should be opened in + * write-only, append mode. * @param params options that specify what kind of a bugreport should be taken * @param callback callback for progress and status updates + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.DUMP) - public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd, + public void startBugreport( + @NonNull ParcelFileDescriptor bugreportFd, @Nullable ParcelFileDescriptor screenshotFd, @NonNull BugreportParams params, @NonNull @CallbackExecutor Executor executor, @@ -165,17 +164,21 @@ public final class BugreportManager { boolean isScreenshotRequested = screenshotFd != null; if (screenshotFd == null) { // Binder needs a valid File Descriptor to be passed - screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"), - ParcelFileDescriptor.MODE_READ_ONLY); + screenshotFd = + ParcelFileDescriptor.open( + new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY); } - DumpstateListener dsListener = new DumpstateListener(executor, callback, - isScreenshotRequested); + DumpstateListener dsListener = + new DumpstateListener(executor, callback, isScreenshotRequested); // Note: mBinder can get callingUid from the binder transaction. - mBinder.startBugreport(-1 /* callingUid */, + mBinder.startBugreport( + -1 /* callingUid */, mContext.getOpPackageName(), bugreportFd.getFileDescriptor(), screenshotFd.getFileDescriptor(), - params.getMode(), dsListener, isScreenshotRequested); + params.getMode(), + dsListener, + isScreenshotRequested); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (FileNotFoundException e) { @@ -189,13 +192,64 @@ public final class BugreportManager { } } - /* - * Cancels a currently running bugreport. + /** + * Starts a connectivity bugreport. + * + * <p>The connectivity bugreport is a specialized version of bugreport that only includes + * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi, + * and IP networking issues). It is intended primarily for use by OEMs and network providers + * such as mobile network operators. In addition to generally excluding information that isn't + * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive + * information that isn't strictly necessary for connectivity debugging. + * + * <p>The calling app MUST have a context-specific reason for requesting a connectivity + * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to + * perform random sampling from a fleet of public end-user devices. + * + * <p>Calling this API will cause the system to ask the user for consent every single time. The + * bugreport artifacts will be copied over to the given file descriptors only if the user + * consents to sharing with the calling app. + * + * <p>This starts a bugreport in the background. However the call itself can take several + * seconds to return in the worst case. {@code callback} will receive progress and status + * updates. + * + * <p>Requires that the calling app has carrier privileges (see {@link + * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription. + * + * @param bugreportFd file to write the bugreport. This should be opened in write-only, append + * mode. + * @param callback callback for progress and status updates. */ - @RequiresPermission(android.Manifest.permission.DUMP) + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + public void startConnectivityBugreport( + @NonNull ParcelFileDescriptor bugreportFd, + @NonNull @CallbackExecutor Executor executor, + @NonNull BugreportCallback callback) { + startBugreport( + bugreportFd, + null /* screenshotFd */, + new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY), + executor, + callback); + } + + /** + * Cancels the currently running bugreport. + * + * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started + * by app B. + * + * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has + * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on + * any active subscription. + * + * @throws SecurityException if trying to cancel another app's bugreport in progress + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges public void cancelBugreport() { try { - mBinder.cancelBugreport(); + mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -205,23 +259,26 @@ public final class BugreportManager { * Requests a bugreport. * * <p>This requests the platform/system to take a bugreport and makes the final bugreport - * available to the user. The user may choose to share it with another app, but the bugreport - * is never given back directly to the app that requested it. + * available to the user. The user may choose to share it with another app, but the bugreport is + * never given back directly to the app that requested it. * - * @param params {@link BugreportParams} that specify what kind of a bugreport should - * be taken, please note that not all kinds of bugreport allow for a - * progress notification - * @param shareTitle title on the final share notification + * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken, + * please note that not all kinds of bugreport allow for a progress notification + * @param shareTitle title on the final share notification * @param shareDescription description on the final share notification + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.DUMP) - public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle, + public void requestBugreport( + @NonNull BugreportParams params, + @Nullable CharSequence shareTitle, @Nullable CharSequence shareDescription) { try { String title = shareTitle == null ? null : shareTitle.toString(); String description = shareDescription == null ? null : shareDescription.toString(); - ActivityManager.getService().requestBugReportWithDescription(title, description, - params.getMode()); + ActivityManager.getService() + .requestBugReportWithDescription(title, description, params.getMode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -232,8 +289,8 @@ public final class BugreportManager { private final BugreportCallback mCallback; private final boolean mIsScreenshotRequested; - DumpstateListener(Executor executor, BugreportCallback callback, - boolean isScreenshotRequested) { + DumpstateListener( + Executor executor, BugreportCallback callback, boolean isScreenshotRequested) { mExecutor = executor; mCallback = callback; mIsScreenshotRequested = isScreenshotRequested; @@ -243,9 +300,7 @@ public final class BugreportManager { public void onProgress(int progress) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onProgress(progress); - }); + mExecutor.execute(() -> mCallback.onProgress(progress)); } finally { Binder.restoreCallingIdentity(identity); } @@ -255,9 +310,7 @@ public final class BugreportManager { public void onError(int errorCode) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onError(errorCode); - }); + mExecutor.execute(() -> mCallback.onError(errorCode)); } finally { Binder.restoreCallingIdentity(identity); } @@ -267,9 +320,7 @@ public final class BugreportManager { public void onFinished() throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onFinished(); - }); + mExecutor.execute(() -> mCallback.onFinished()); } finally { Binder.restoreCallingIdentity(identity); } @@ -284,20 +335,19 @@ public final class BugreportManager { Handler mainThreadHandler = new Handler(Looper.getMainLooper()); mainThreadHandler.post( () -> { - int message = success ? R.string.bugreport_screenshot_success_toast - : R.string.bugreport_screenshot_failure_toast; + int message = + success + ? R.string.bugreport_screenshot_success_toast + : R.string.bugreport_screenshot_failure_toast; Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); }); } @Override - public void onUiIntensiveBugreportDumpsFinished() - throws RemoteException { + public void onUiIntensiveBugreportDumpsFinished() throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onEarlyReportFinished(); - }); + mExecutor.execute(() -> mCallback.onEarlyReportFinished()); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java index df3c4d55d979..51856d8bb723 100644 --- a/core/java/android/os/storage/DiskInfo.java +++ b/core/java/android/os/storage/DiskInfo.java @@ -50,6 +50,8 @@ public class DiskInfo implements Parcelable { public static final int FLAG_DEFAULT_PRIMARY = 1 << 1; public static final int FLAG_SD = 1 << 2; public static final int FLAG_USB = 1 << 3; + /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */ + public static final int FLAG_STUB_VISIBLE = 1 << 6; public final String id; @UnsupportedAppUsage @@ -152,6 +154,10 @@ public class DiskInfo implements Parcelable { return (flags & FLAG_USB) != 0; } + public boolean isStubVisible() { + return (flags & FLAG_STUB_VISIBLE) != 0; + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 99bdfd1fc103..4669b208b163 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -195,4 +195,5 @@ interface IStorageManager { void abortChanges(in String message, boolean retry) = 87; void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; void fixupAppDir(in String path) = 89; + void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90; } diff --git a/core/java/android/service/search/OWNERS b/core/java/android/service/search/OWNERS new file mode 100644 index 000000000000..92835c2b0626 --- /dev/null +++ b/core/java/android/service/search/OWNERS @@ -0,0 +1,2 @@ +hyunyoungs@google.com +sfufa@google.com diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index d6ae434af9d5..03d3755111aa 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -17,7 +17,10 @@ package android.telephony; import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -29,9 +32,16 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.telephony.Annotation.CallState; +import android.telephony.Annotation.DataActivityType; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; +import android.telephony.NetworkRegistrationInfo.Domain; +import android.telephony.TelephonyManager.DataEnabledReason; +import android.telephony.TelephonyManager.DataState; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; @@ -40,6 +50,8 @@ import com.android.internal.telephony.IPhoneStateListener; import dalvik.system.VMRuntime; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.List; import java.util.Map; @@ -114,7 +126,9 @@ public class PhoneStateListener { * * @see #onServiceStateChanged * @see ServiceState + * @deprecated Use {@link ServiceStateChangedListener} instead. */ + @Deprecated public static final int LISTEN_SERVICE_STATE = 0x00000001; /** @@ -122,8 +136,7 @@ public class PhoneStateListener { * {@more} * * @see #onSignalStrengthChanged - * - * @deprecated by {@link #LISTEN_SIGNAL_STRENGTHS} + * @deprecated Use {@link SignalStrengthsChangedListener} instead. */ @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 0x00000002; @@ -139,7 +152,9 @@ public class PhoneStateListener { * voicemail icon. * * @see #onMessageWaitingIndicatorChanged + * @deprecated Use {@link MessageWaitingIndicatorChangedListener} instead. */ + @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 0x00000004; /** @@ -150,7 +165,9 @@ public class PhoneStateListener { * {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onCallForwardingIndicatorChanged + * @deprecated Use {@link CallForwardingIndicatorChangedListener} instead. */ + @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008; /** @@ -166,7 +183,9 @@ public class PhoneStateListener { * instead. * * @see #onCellLocationChanged + * @deprecated Use {@link CellLocationChangedListener} instead. */ + @Deprecated public static final int LISTEN_CELL_LOCATION = 0x00000010; /** @@ -174,14 +193,18 @@ public class PhoneStateListener { * {@more} * * @see #onCallStateChanged + * @deprecated Use {@link CallStateChangedListener} instead. */ + @Deprecated public static final int LISTEN_CALL_STATE = 0x00000020; /** * Listen for changes to the data connection state (cellular). * * @see #onDataConnectionStateChanged + * @deprecated Use {@link DataConnectionStateChangedListener} instead. */ + @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 0x00000040; /** @@ -192,7 +215,9 @@ public class PhoneStateListener { * data-traffic icon. * * @see #onDataActivity + * @deprecated Use {@link DataActivityListener} instead. */ + @Deprecated public static final int LISTEN_DATA_ACTIVITY = 0x00000080; /** @@ -202,7 +227,9 @@ public class PhoneStateListener { * icon. * * @see #onSignalStrengthsChanged + * @deprecated Use {@link SignalStrengthsChangedListener} instead. */ + @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100; /** @@ -212,7 +239,9 @@ public class PhoneStateListener { * @see #onSignalStrengthsChanged * * @hide + * @deprecated Use {@link AlwaysReportedSignalStrengthChangedListener} instead. */ + @Deprecated @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200; @@ -223,7 +252,9 @@ public class PhoneStateListener { * permission. * * @see #onCellInfoChanged + * @deprecated Use {@link CellInfoChangedListener} instead. */ + @Deprecated public static final int LISTEN_CELL_INFO = 0x00000400; /** @@ -235,8 +266,10 @@ public class PhoneStateListener { * (see {@link TelephonyManager#hasCarrierPrivileges}). * * @hide + * @deprecated Use {@link PreciseCallStateChangedListener} instead. */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @Deprecated + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @SystemApi public static final int LISTEN_PRECISE_CALL_STATE = 0x00000800; @@ -248,8 +281,10 @@ public class PhoneStateListener { * (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onPreciseDataConnectionStateChanged + * @deprecated Use {@link PreciseDataConnectionStateChangedListener} instead. */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @Deprecated + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000; /** @@ -259,7 +294,7 @@ public class PhoneStateListener { * READ_PRECISE_PHONE_STATE} * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo) * - * @deprecated Use {@link TelephonyManager#getModemActivityInfo()} + * @deprecated Use {@link TelephonyManager#requestModemActivityInfo} instead. * @hide */ @Deprecated @@ -272,7 +307,9 @@ public class PhoneStateListener { * * @see #onServiceStateChanged(ServiceState) * @hide + * @deprecated Use {@link SrvccStateChangedListener} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 0x00004000; @@ -290,10 +327,11 @@ public class PhoneStateListener { /** * Listen for carrier network changes indicated by a carrier app. * - * @see #onCarrierNetworkRequest - * @see TelephonyManager#notifyCarrierNetworkChange(boolean) + * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean) * @hide + * @deprecated Use {@link CarrierNetworkChangeListener} instead. */ + @Deprecated public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000; /** @@ -312,7 +350,9 @@ public class PhoneStateListener { * * @see #onVoiceActivationStateChanged * @hide + * @deprecated Use {@link VoiceActivationStateChangedListener} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000; @@ -324,20 +364,24 @@ public class PhoneStateListener { * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN - * {@more} + * * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been * fully activated * * @see #onDataActivationStateChanged * @hide + * @deprecated Use {@link DataActivationStateChangedListener} instead. */ + @Deprecated public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000; /** * Listen for changes to the user mobile data state * * @see #onUserMobileDataStateChanged + * @deprecated Use {@link UserMobileDataStateChangedListener} instead. */ + @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 0x00080000; /** @@ -348,7 +392,9 @@ public class PhoneStateListener { * {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onDisplayInfoChanged + * @deprecated Use {@link DisplayInfoChangedListener} instead. */ + @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000; /** @@ -356,7 +402,9 @@ public class PhoneStateListener { * * @see #onPhoneCapabilityChanged * @hide + * @deprecated Use {@link PhoneCapabilityChangedListener} instead. */ + @Deprecated public static final int LISTEN_PHONE_CAPABILITY_CHANGE = 0x00200000; /** @@ -366,17 +414,19 @@ public class PhoneStateListener { * subscription user selected as default data subscription in DSDS mode. * * @see #onActiveDataSubscriptionIdChanged + * @deprecated Use {@link ActiveDataSubscriptionIdChangedListener} instead. */ + @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000; /** * Listen for changes to the radio power state. * - * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} - * * @see #onRadioPowerStateChanged * @hide + * @deprecated Use {@link RadioPowerStateChangedListener} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 0x00800000; @@ -386,7 +436,10 @@ public class PhoneStateListener { * * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @deprecated Use {@link EmergencyNumberListChangedListener} instead. */ + @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000; /** @@ -397,8 +450,10 @@ public class PhoneStateListener { * or the calling app has carrier privileges * (see {@link TelephonyManager#hasCarrierPrivileges}). * + * @deprecated Use {@link CallDisconnectCauseChangedListener} instead. */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @Deprecated + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 0x02000000; /** @@ -410,9 +465,11 @@ public class PhoneStateListener { * * @see #onCallAttributesChanged * @hide + * @deprecated Use {@link CallAttributesChangedListener} instead. */ + @Deprecated @SystemApi - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000; /** @@ -424,18 +481,20 @@ public class PhoneStateListener { * (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo) + * @deprecated Use {@link ImsCallDisconnectCauseChangedListener} instead. */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @Deprecated + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 0x08000000; /** * Listen for the emergency number placed from an outgoing call. * - * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION} - * * @see #onOutgoingEmergencyCall * @hide + * @deprecated Use {@link OutgoingEmergencyCallListener} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 0x10000000; @@ -443,11 +502,11 @@ public class PhoneStateListener { /** * Listen for the emergency number placed from an outgoing SMS. * - * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION} - * * @see #onOutgoingEmergencySms * @hide + * @deprecated Use {@link OutgoingEmergencySmsListener} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 0x20000000; @@ -466,7 +525,9 @@ public class PhoneStateListener { * of whether the calling app has carrier privileges. * * @see #onRegistrationFailed + * @deprecated Use {@link RegistrationFailedListener} instead. */ + @Deprecated @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000; @@ -480,10 +541,525 @@ public class PhoneStateListener { * of whether the calling app has carrier privileges. * * @see #onBarringInfoChanged + * @deprecated Use {@link BarringInfoChangedListener} instead. */ + @Deprecated @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = 0x80000000; + /** + * Event for changes to the network service state (cellular). + * + * @see ServiceStateChangedListener#onServiceStateChanged + * @see ServiceState + * + * @hide + */ + @SystemApi + public static final int EVENT_SERVICE_STATE_CHANGED = 1; + + /** + * Event for changes to the network signal strength (cellular). + * + * @see SignalStrengthsChangedListener#onSignalStrengthsChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; + + /** + * Event for changes to the message-waiting indicator. + * + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that + * the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * <p> + * Example: The status bar uses this to determine when to display the + * voicemail icon. + * + * @see MessageWaitingIndicatorChangedListener#onMessageWaitingIndicatorChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; + + /** + * Event for changes to the call-forwarding indicator. + * + * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that + * the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see CallForwardingIndicatorChangedListener#onCallForwardingIndicatorChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; + + /** + * Event for changes to the device's cell location. Note that + * this will result in frequent callbacks to the listener. + * + * If you need regular location updates but want more control over + * the update interval or location precision, you can set up a listener + * through the {@link android.location.LocationManager location manager} + * instead. + * + * @see CellLocationChangedListener#onCellLocationChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + public static final int EVENT_CELL_LOCATION_CHANGED = 5; + + /** + * Event for changes to the device call state. + * + * @see CallStateChangedListener#onCallStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) + public static final int EVENT_CALL_STATE_CHANGED = 6; + + /** + * Event for changes to the data connection state (cellular). + * + * @see DataConnectionStateChangedListener#onDataConnectionStateChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; + + /** + * Event for changes to the direction of data traffic on the data + * connection (cellular). + * + * Example: The status bar uses this to display the appropriate + * data-traffic icon. + * + * @see DataActivityListener#onDataActivity + * + * @hide + */ + @SystemApi + public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; + + /** + * Event for changes to the network signal strengths (cellular). + * <p> + * Example: The status bar uses this to control the signal-strength + * icon. + * + * @see SignalStrengthsChangedListener#onSignalStrengthsChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; + + /** + * Event for changes of the network signal strengths (cellular) always reported from modem, + * even in some situations such as the screen of the device is off. + * + * @see AlwaysReportedSignalStrengthChangedListener#onSignalStrengthsChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) + public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; + + /** + * Event for changes to observed cell info. + * + * @see CellInfoChangedListener#onCellInfoChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + public static final int EVENT_CELL_INFO_CHANGED = 11; + + /** + * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing, + * background and foreground calls. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see PreciseCallStateChangedListener#onPreciseCallStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; + + /** + * Event for {@link PreciseDataConnectionState} on the data connection (cellular). + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see PreciseDataConnectionStateChangedListener#onPreciseDataConnectionStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; + + /** + * Event for real time info for all data connections (cellular)). + * + * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo) + * + * @deprecated Use {@link TelephonyManager#requestModemActivityInfo} + * @hide + */ + @Deprecated + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; + + /** + * Event for OEM hook raw event + * + * @see #onOemHookRawEvent + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final int EVENT_OEM_HOOK_RAW = 15; + + /** + * Event for changes to the SRVCC state of the active call. + * + * @see SrvccStateChangedListener#onSrvccStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final int EVENT_SRVCC_STATE_CHANGED = 16; + + /** + * Event for carrier network changes indicated by a carrier app. + * + * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean) + * @see CarrierNetworkChangeListener#onCarrierNetworkChange + * + * @hide + */ + @SystemApi + public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; + + /** + * Event for changes to the sim voice activation state + * + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED + * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN + * + * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been + * fully activated + * + * @see VoiceActivationStateChangedListener#onVoiceActivationStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; + + /** + * Event for changes to the sim data activation state + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED + * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN + * + * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been + * fully activated + * + * @see DataActivationStateChangedListener#onDataActivationStateChanged + * @hide + */ + @SystemApi + public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; + + /** + * Event for changes to the user mobile data state + * + * @see UserMobileDataStateChangedListener#onUserMobileDataStateChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; + + /** + * Event for display info changed event. + * + * @see DisplayInfoChangedListener#onDisplayInfoChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_DISPLAY_INFO_CHANGED = 21; + + /** + * Event for changes to the phone capability. + * + * @see PhoneCapabilityChangedListener#onPhoneCapabilityChanged + * + * @hide + */ + @SystemApi + public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; + + /** + * Event for changes to active data subscription ID. Active data subscription is + * the current subscription used to setup Cellular Internet data. For example, + * it could be the current active opportunistic subscription in use, or the + * subscription user selected as default data subscription in DSDS mode. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling + * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see ActiveDataSubscriptionIdChangedListener#onActiveDataSubscriptionIdChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; + + /** + * Event for changes to the radio power state. + * + * @see RadioPowerStateChangedListener#onRadioPowerStateChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; + + /** + * Event for changes to emergency number list based on all active subscriptions. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling + * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see EmergencyNumberListChangedListener#onEmergencyNumberListChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; + + /** + * Event for call disconnect causes which contains {@link DisconnectCause} and + * {@link PreciseDisconnectCause}. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see CallDisconnectCauseChangedListener#onCallDisconnectCauseChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; + + /** + * Event for changes to the call attributes of a currently active call. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see CallAttributesChangedListener#onCallAttributesChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; + + /** + * Event for IMS call disconnect causes which contains + * {@link android.telephony.ims.ImsReasonInfo} + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see ImsCallDisconnectCauseChangedListener#onImsCallDisconnectCauseChanged(ImsReasonInfo) + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; + + /** + * Event for the emergency number placed from an outgoing call. + * + * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; + + /** + * Event for the emergency number placed from an outgoing SMS. + * + * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; + + /** + * Event for registration failures. + * + * Event for indications that a registration procedure has failed in either the CS or PS + * domain. This indication does not necessarily indicate a change of service state, which should + * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or + * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless + * of whether the calling app has carrier privileges. + * + * @see RegistrationFailedListener#onRegistrationFailed + * + * @hide + */ + @SystemApi + @RequiresPermission(allOf = { + Manifest.permission.READ_PRECISE_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION + }) + public static final int EVENT_REGISTRATION_FAILURE = 31; + + /** + * Event for Barring Information for the current registered / camped cell. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or + * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless + * of whether the calling app has carrier privileges. + * + * @see BarringInfoChangedListener#onBarringInfoChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(allOf = { + Manifest.permission.READ_PRECISE_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION + }) + public static final int EVENT_BARRING_INFO_CHANGED = 32; + + /** + * Event for changes to the physical channel configuration. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see PhysicalChannelConfigChangedListener#onPhysicalChannelConfigChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; + + /** + * Event for changes to the data enabled. + * + * Event for indications that the enabled status of current data has changed. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see DataEnabledChangedListener#onDataEnabledChanged + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public static final int EVENT_DATA_ENABLED_CHANGED = 34; + + /** @hide */ + @IntDef(prefix = { "EVENT_" }, value = { + EVENT_SERVICE_STATE_CHANGED, + EVENT_SIGNAL_STRENGTH_CHANGED, + EVENT_MESSAGE_WAITING_INDICATOR_CHANGED, + EVENT_CALL_FORWARDING_INDICATOR_CHANGED, + EVENT_CELL_LOCATION_CHANGED, + EVENT_CALL_STATE_CHANGED, + EVENT_DATA_CONNECTION_STATE_CHANGED, + EVENT_DATA_ACTIVITY_CHANGED, + EVENT_SIGNAL_STRENGTHS_CHANGED, + EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED, + EVENT_CELL_INFO_CHANGED, + EVENT_PRECISE_CALL_STATE_CHANGED, + EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED, + EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED, + EVENT_OEM_HOOK_RAW, + EVENT_SRVCC_STATE_CHANGED, + EVENT_CARRIER_NETWORK_CHANGED, + EVENT_VOICE_ACTIVATION_STATE_CHANGED, + EVENT_DATA_ACTIVATION_STATE_CHANGED, + EVENT_USER_MOBILE_DATA_STATE_CHANGED, + EVENT_DISPLAY_INFO_CHANGED, + EVENT_PHONE_CAPABILITY_CHANGED, + EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED, + EVENT_RADIO_POWER_STATE_CHANGED, + EVENT_EMERGENCY_NUMBER_LIST_CHANGED, + EVENT_CALL_DISCONNECT_CAUSE_CHANGED, + EVENT_CALL_ATTRIBUTES_CHANGED, + EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED, + EVENT_OUTGOING_EMERGENCY_CALL, + EVENT_OUTGOING_EMERGENCY_SMS, + EVENT_REGISTRATION_FAILURE, + EVENT_BARRING_INFO_CHANGED, + EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, + EVENT_DATA_ENABLED_CHANGED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TelephonyEvent {} + /* * Subscription used to listen to the phone state changes * @hide @@ -495,13 +1071,19 @@ public class PhoneStateListener { /** * @hide */ + //TODO: The maxTargetSdk should be S if the build time tool updates it. @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - @UnsupportedAppUsage - public final IPhoneStateListener callback; + @UnsupportedAppUsage( + maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "Use {@code TelephonyManager#registerPhoneStateListener(" + + "Executor, PhoneStateListener)} instead") + public IPhoneStateListener callback; /** * Create a PhoneStateListener for the Phone with the default subscription. - * This class requires Looper.myLooper() not return null. + * If this is created for use with deprecated API + * {@link TelephonyManager#listen(PhoneStateListener, int)}, then this class requires + * Looper.myLooper() not return null. */ public PhoneStateListener() { this(null, Looper.myLooper()); @@ -539,7 +1121,10 @@ public class PhoneStateListener { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public PhoneStateListener(Integer subId, Looper looper) { - this(subId, new HandlerExecutor(new Handler(looper))); + if (looper != null) { + setExecutor(new HandlerExecutor(new Handler(looper))); + } + mSubId = subId; if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) { throw new IllegalArgumentException("PhoneStateListener with subId: " @@ -554,17 +1139,744 @@ public class PhoneStateListener { * The Executor must not be null. * * @param executor a non-null Executor that will execute callbacks for the PhoneStateListener. + * @deprecated Use + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} instead. */ + @Deprecated public PhoneStateListener(@NonNull Executor executor) { - this(null, executor); + setExecutor(executor); + mSubId = null; } - private PhoneStateListener(Integer subId, Executor e) { - if (e == null) { + private @NonNull Executor mExecutor; + + /** + * @hide + */ + public void setExecutor(@NonNull @CallbackExecutor Executor executor) { + if (executor == null) { throw new IllegalArgumentException("PhoneStateListener Executor must be non-null"); } - mSubId = subId; - callback = new IPhoneStateListenerStub(this, e); + mExecutor = executor; + callback = new IPhoneStateListenerStub(this, mExecutor); + } + + /** + * @hide + */ + public boolean isExecutorSet() { + return mExecutor != null; + } + + /** + * Interface for service state listener. + */ + public interface ServiceStateChangedListener { + /** + * Callback invoked when device service state changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * The instance of {@link ServiceState} passed as an argument here will have various + * levels of location information stripped from it depending on the location permissions + * that your app holds. + * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will + * receive all the information in {@link ServiceState}. + * + * @see ServiceState#STATE_EMERGENCY_ONLY + * @see ServiceState#STATE_IN_SERVICE + * @see ServiceState#STATE_OUT_OF_SERVICE + * @see ServiceState#STATE_POWER_OFF + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onServiceStateChanged(@NonNull ServiceState serviceState); + } + + /** + * Interface for message waiting indicator listener. + */ + public interface MessageWaitingIndicatorChangedListener { + /** + * Callback invoked when the message-waiting indicator changes on the registered + * subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void onMessageWaitingIndicatorChanged(boolean mwi); + } + + /** + * Interface for call-forwarding indicator listener. + */ + public interface CallForwardingIndicatorChangedListener { + /** + * Callback invoked when the call-forwarding indicator changes on the registered + * subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void onCallForwardingIndicatorChanged(boolean cfi); + } + + /** + * Interface for device cell location listener. + */ + public interface CellLocationChangedListener { + /** + * Callback invoked when device cell location changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + public void onCellLocationChanged(@NonNull CellLocation location); + } + + /** + * Interface for call state listener. + */ + public interface CallStateChangedListener { + /** + * Callback invoked when device call state changes. + * <p> + * Reports the state of Telephony (mobile) calls on the device for the registered s + * ubscription. + * <p> + * Note: the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to all subIds. + * <p> + * Note: The state returned here may differ from that returned by + * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that + * calling {@link TelephonyManager#getCallState()} from within this callback may return a + * different state than the callback reports. + * + * @param state call state + * @param phoneNumber call phone number. If application does not have + * {@link android.Manifest.permission#READ_CALL_LOG} permission or carrier + * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be + * passed as an argument. + */ + @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) + public void onCallStateChanged(@CallState int state, @Nullable String phoneNumber); + } + + /** + * Interface for data connection state listener. + */ + public interface DataConnectionStateChangedListener { + /** + * Callback invoked when connection state changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @see TelephonyManager#DATA_DISCONNECTED + * @see TelephonyManager#DATA_CONNECTING + * @see TelephonyManager#DATA_CONNECTED + * @see TelephonyManager#DATA_SUSPENDED + * + * @param state is the current state of data connection. + * @param networkType is the current network type of data connection. + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onDataConnectionStateChanged(@DataState int state, + @NetworkType int networkType); + } + + /** + * Interface for data activity state listener. + */ + public interface DataActivityListener { + /** + * Callback invoked when data activity state changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @see TelephonyManager#DATA_ACTIVITY_NONE + * @see TelephonyManager#DATA_ACTIVITY_IN + * @see TelephonyManager#DATA_ACTIVITY_OUT + * @see TelephonyManager#DATA_ACTIVITY_INOUT + * @see TelephonyManager#DATA_ACTIVITY_DORMANT + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onDataActivity(@DataActivityType int direction); + } + + /** + * Interface for network signal strengths listener. + */ + public interface SignalStrengthsChangedListener { + /** + * Callback invoked when network signal strengths changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength); + } + + /** + * Interface for network signal strengths listener which always reported from modem. + */ + public interface AlwaysReportedSignalStrengthChangedListener { + /** + * Callback always invoked from modem when network signal strengths changes on the + * registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) + public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength); + } + + /** + * Interface for cell info listener. + */ + public interface CellInfoChangedListener { + /** + * Callback invoked when a observed cell info has changed or new cells have been added + * or removed on the registered subscription. + * Note, the registration subscription ID s from {@link TelephonyManager} object + * which registersPhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param cellInfo is the list of currently visible cells. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo); + } + + /** + * Interface for precise device call state listener. + * + * @hide + */ + @SystemApi + public interface PreciseCallStateChangedListener { + /** + * Callback invoked when precise device call state changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param callState {@link PreciseCallState} + */ + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onPreciseCallStateChanged(@NonNull PreciseCallState callState); + } + + /** + * Interface for call disconnect cause listener. + */ + public interface CallDisconnectCauseChangedListener { + /** + * Callback invoked when call disconnect cause changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param disconnectCause {@link DisconnectCause}. + * @param preciseDisconnectCause {@link PreciseDisconnectCause}. + */ + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause, + @PreciseDisconnectCauses int preciseDisconnectCause); + } + + /** + * Interface for IMS call disconnect cause listener. + */ + public interface ImsCallDisconnectCauseChangedListener { + /** + * Callback invoked when IMS call disconnect cause changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed. + * + */ + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo); + } + + /** + * Interface for precise data connection state listener. + */ + public interface PreciseDataConnectionStateChangedListener { + /** + * Callback providing update about the default/internet data connection on the registered + * subscription. + * + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} + * or the calling app has carrier privileges + * (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @param dataConnectionState {@link PreciseDataConnectionState} + */ + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onPreciseDataConnectionStateChanged( + @NonNull PreciseDataConnectionState dataConnectionState); + } + + /** + * Interface for Single Radio Voice Call Continuity listener. + * + * @hide + */ + @SystemApi + public interface SrvccStateChangedListener { + /** + * Callback invoked when there has been a change in the Single Radio Voice Call Continuity + * (SRVCC) state for the currently active call on the registered subscription. + * + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void onSrvccStateChanged(@SrvccState int srvccState); + } + + /** + * Interface for SIM voice activation state listener. + * + * @hide + */ + @SystemApi + public interface VoiceActivationStateChangedListener { + /** + * Callback invoked when the SIM voice activation state has changed on the registered + * subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param state is the current SIM voice activation state + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void onVoiceActivationStateChanged(@SimActivationState int state); + + } + + /** + * Interface for SIM data activation state listener. + */ + public interface DataActivationStateChangedListener { + /** + * Callback invoked when the SIM data activation state has changed on the registered + * subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param state is the current SIM data activation state + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onDataActivationStateChanged(@SimActivationState int state); + } + + /** + * Interface for user mobile data state listener. + */ + public interface UserMobileDataStateChangedListener { + /** + * Callback invoked when the user mobile data state has changed on the registered + * subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param enabled indicates whether the current user mobile data state is enabled or + * disabled. + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onUserMobileDataStateChanged(boolean enabled); + } + + /** + * Interface for display info listener. + */ + public interface DisplayInfoChangedListener { + /** + * Callback invoked when the display info has changed on the registered subscription. + * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user + * based on carrier policy. + * + * @param telephonyDisplayInfo The display information. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo); + } + + /** + * Interface for the current emergency number list listener. + */ + public interface EmergencyNumberListChangedListener { + /** + * Callback invoked when the current emergency number list has changed on the registered + * subscription. + * + * Note, the registered subscription is associated with {@link TelephonyManager} object + * on which + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} + * was called. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * given subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param emergencyNumberList Map associating all active subscriptions on the device with + * the list of emergency numbers originating from that + * subscription. + * If there are no active subscriptions, the map will contain a + * single entry with + * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as + * the key and a list of emergency numbers as the value. If no + * emergency number information is available, the value will be + * empty. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void onEmergencyNumberListChanged( + @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList); + } + + /** + * Interface for outgoing emergency call listener. + * + * @hide + */ + @SystemApi + public interface OutgoingEmergencyCallListener { + /** + * Callback invoked when an outgoing call is placed to an emergency number. + * + * This method will be called when an emergency call is placed on any subscription + * (including the no-SIM case), regardless of which subscription this listener was + * registered on. + * + * The default implementation of this method calls + * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes. + * Do not call {@code super(...)} from within your implementation unless you want + * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well. + * + * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was + * placed to. + * @param subscriptionId The subscription ID used to place the emergency call. If the + * emergency call was placed without a valid subscription + * (e.g. when there are no SIM cards in the device), this will be + * equal to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + */ + @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber, + int subscriptionId); + } + + /** + * Interface for outgoing emergency sms listener. + * + * @hide + */ + @SystemApi + public interface OutgoingEmergencySmsListener { + /** + * Smsback invoked when an outgoing sms is sent to an emergency number. + * + * This method will be called when an emergency sms is sent on any subscription, + * regardless of which subscription this listener was registered on. + * + * The default implementation of this method calls + * {@link #onOutgoingEmergencySms(EmergencyNumber)} for backwards compatibility purposes. Do + * not call {@code super(...)} from within your implementation unless you want + * {@link #onOutgoingEmergencySms(EmergencyNumber)} to be called as well. + * + * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to. + * @param subscriptionId The subscription ID used to send the emergency sms. + */ + @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber, + int subscriptionId); + } + + /** + * Interface for phone capability listener. + * + */ + public interface PhoneCapabilityChangedListener { + /** + * Callback invoked when phone capability changes. + * Note, this callback triggers regardless of registered subscription. + * + * @param capability the new phone capability + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability); + } + + /** + * Interface for active data subscription ID listener. + */ + public interface ActiveDataSubscriptionIdChangedListener { + /** + * Callback invoked when active data subscription ID changes. + * Note, this callback triggers regardless of registered subscription. + * + * @param subId current subscription used to setup Cellular Internet data. + * For example, it could be the current active opportunistic subscription + * in use, or the subscription user selected as default data subscription in + * DSDS mode. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void onActiveDataSubscriptionIdChanged(int subId); + } + + /** + * Interface for modem radio power state listener. + * + * @hide + */ + @SystemApi + public interface RadioPowerStateChangedListener { + /** + * Callback invoked when modem radio power state changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param state the modem radio power state + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void onRadioPowerStateChanged(@RadioPowerState int state); + } + + /** + * Interface for carrier network listener. + */ + public interface CarrierNetworkChangeListener { + /** + * Callback invoked when telephony has received notice from a carrier + * app that a network action that could result in connectivity loss + * has been requested by an app using + * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)} + * + * This is optional and is only used to allow the system to provide alternative UI while + * telephony is performing an action that may result in intentional, temporary network + * lack of connectivity. + * + * Note, this callback is pinned to the registered subscription and will be invoked when + * the notifying carrier app has carrier privilege rule on the registered + * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges} + * + * @param active If the carrier network change is or shortly will be active, + * {@code true} indicate that showing alternative UI, {@code false} otherwise. + */ + public void onCarrierNetworkChange(boolean active); + } + + /** + * Interface for registration failures listener. + */ + public interface RegistrationFailedListener { + /** + * Report that Registration or a Location/Routing/Tracking Area update has failed. + * + * <p>Indicate whenever a registration procedure, including a location, routing, or tracking + * area update fails. This includes procedures that do not necessarily result in a change of + * the modem's registration status. If the modem's registration status changes, that is + * reflected in the onNetworkStateChanged() and subsequent + * get{Voice/Data}RegistrationState(). + * + * <p>Because registration failures are ephemeral, this callback is not sticky. + * Registrants will not receive the most recent past value when registering. + * + * @param cellIdentity the CellIdentity, which must include the globally unique identifier + * for the cell (for example, all components of the CGI or ECGI). + * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the + * cell that was chosen for the failed registration attempt. + * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure. + * @param causeCode the primary failure cause code of the procedure. + * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95 + * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147 + * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9 + * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2 + * Integer.MAX_VALUE if this value is unused. + * @param additionalCauseCode the cause code of any secondary/combined procedure + * if appropriate. For UMTS, if a combined attach succeeds for + * PS only, then the GMM cause code shall be included as an + * additionalCauseCode. For LTE (ESM), cause codes are in + * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused. + */ + @RequiresPermission(allOf = { + Manifest.permission.READ_PRECISE_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION + }) + public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, + @NonNull String chosenPlmn, @Domain int domain, + int causeCode, int additionalCauseCode); + } + + /** + * Interface for call attributes listener. + * + * @hide + */ + @SystemApi + public interface CallAttributesChangedListener { + /** + * Callback invoked when the call attributes changes on the registered subscription. + * Note, the registration subscription ID comes from {@link TelephonyManager} object + * which registers PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param callAttributes the call attributes + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + void onCallAttributesChanged(@NonNull CallAttributes callAttributes); + } + + /** + * Interface for barring information listener. + */ + public interface BarringInfoChangedListener { + /** + * Report updated barring information for the current camped/registered cell. + * + * <p>Barring info is provided for all services applicable to the current camped/registered + * cell, for the registered PLMN and current access class/access category. + * + * @param barringInfo for all services on the current cell. + * @see android.telephony.BarringInfo + */ + @RequiresPermission(allOf = { + Manifest.permission.READ_PRECISE_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION + }) + public void onBarringInfoChanged(@NonNull BarringInfo barringInfo); + } + + /** + * Interface for current physical channel configuration listener. + * @hide + */ + @SystemApi + public interface PhysicalChannelConfigChangedListener { + /** + * Callback invoked when the current physical channel configuration has changed + * + * @param configs List of the current {@link PhysicalChannelConfig}s + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs); + } + + /** + * Interface for data enabled listener. + * + * @hide + */ + @SystemApi + public interface DataEnabledChangedListener { + /** + * Callback invoked when the data enabled changes. + * + * @param enabled {@code true} if data is enabled, otherwise disabled. + * @param reason Reason for data enabled/disabled. + * See {@link TelephonyManager.DataEnabledReason}. + */ + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onDataEnabledChanged(boolean enabled, + @DataEnabledReason int reason); } /** @@ -658,8 +1970,7 @@ public class PhoneStateListener { * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}. * If this TelephonyManager object was created with * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the - * subId. Otherwise, this callback applies to - * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * subId. Otherwise, this callback applies to all subIds. * <p> * Note: The state returned here may differ from that returned by * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that @@ -698,6 +2009,7 @@ public class PhoneStateListener { * same as above, but with the network type. Both called. */ public void onDataConnectionStateChanged(int state, int networkType) { + // default implementation empty } /** @@ -745,6 +2057,7 @@ public class PhoneStateListener { * @param cellInfo is the list of currently visible cells. */ public void onCellInfoChanged(List<CellInfo> cellInfo) { + // default implementation empty } /** @@ -758,7 +2071,7 @@ public class PhoneStateListener { * @param callState {@link PreciseCallState} * @hide */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) @SystemApi public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) { // default implementation empty @@ -777,9 +2090,9 @@ public class PhoneStateListener { * @param preciseDisconnectCause {@link PreciseDisconnectCause}. * */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) - public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause, - int preciseDisconnectCause) { + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) + public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause, + @PreciseDisconnectCauses int preciseDisconnectCause) { // default implementation empty } @@ -795,7 +2108,7 @@ public class PhoneStateListener { * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed. * */ - @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE)) + @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) { // default implementation empty } @@ -817,7 +2130,7 @@ public class PhoneStateListener { * * @param dataConnectionState {@link PreciseDataConnectionState} */ - @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE)) + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged( @NonNull PreciseDataConnectionState dataConnectionState) { // default implementation empty @@ -855,6 +2168,7 @@ public class PhoneStateListener { */ @SystemApi public void onSrvccStateChanged(@SrvccState int srvccState) { + // default implementation empty } @@ -873,6 +2187,7 @@ public class PhoneStateListener { */ @SystemApi public void onVoiceActivationStateChanged(@SimActivationState int state) { + // default implementation empty } /** @@ -889,6 +2204,7 @@ public class PhoneStateListener { * @hide */ public void onDataActivationStateChanged(@SimActivationState int state) { + // default implementation empty } /** @@ -916,7 +2232,7 @@ public class PhoneStateListener { * * @param telephonyDisplayInfo The display information. */ - @RequiresPermission((android.Manifest.permission.READ_PHONE_STATE)) + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) { // default implementation empty } @@ -1030,7 +2346,8 @@ public class PhoneStateListener { /** * Callback invoked when OEM hook raw event is received on the registered subscription. * Note, the registration subId comes from {@link TelephonyManager} object which registers - * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}. + * PhoneStateListener by + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}. * If this TelephonyManager object was created with * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the * subId. Otherwise, this callback applies to @@ -1052,7 +2369,7 @@ public class PhoneStateListener { * @param capability the new phone capability * @hide */ - public void onPhoneCapabilityChanged(PhoneCapability capability) { + public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability) { // default implementation empty } @@ -1096,7 +2413,8 @@ public class PhoneStateListener { * subId. Otherwise, this callback applies to * {@link SubscriptionManager#getDefaultSubscriptionId()}. * - * @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE} + * Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} + * * @param state the modem radio power state * @hide */ @@ -1453,18 +2771,16 @@ public class PhoneStateListener { Binder.withCleanCallingIdentity( () -> mExecutor.execute( () -> psl.onImsCallDisconnectCauseChanged(disconnectCause))); - } public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, - @NonNull String chosenPlmn, int domain, - int causeCode, int additionalCauseCode) { + @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> psl.onRegistrationFailed( - cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode))); + cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode))); // default implementation empty } @@ -1475,8 +2791,27 @@ public class PhoneStateListener { Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> psl.onBarringInfoChanged(barringInfo))); } - } + public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) { + PhysicalChannelConfigChangedListener listener = + (PhysicalChannelConfigChangedListener) mPhoneStateListenerWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged( + configs))); + } + + public void onDataEnabledChanged(boolean enabled, @DataEnabledReason int reason) { + DataEnabledChangedListener listener = + (DataEnabledChangedListener) mPhoneStateListenerWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> listener.onDataEnabledChanged( + enabled, reason))); + } + } private void log(String s) { Rlog.d(LOG_TAG, s); diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 3673ae7f7a37..a9548b0a42b4 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -15,6 +15,7 @@ */ package android.telephony; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -24,6 +25,9 @@ import android.compat.annotation.EnabledAfter; import android.content.Context; import android.os.Binder; import android.os.Build; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Annotation.CallState; @@ -37,6 +41,7 @@ import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; +import android.util.ArraySet; import android.util.Log; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -45,6 +50,7 @@ import com.android.internal.telephony.ITelephonyRegistry; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -206,7 +212,7 @@ public class TelephonyRegistryManager { } /** - * To check the SDK version for {@link #listenForSubscriber}. + * To check the SDK version for {@link #listenWithEventList}. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P) @@ -218,23 +224,23 @@ public class TelephonyRegistryManager { * @param pkg Package name * @param featureId Feature ID * @param listener Listener providing callback - * @param events Events + * @param events List events * @param notifyNow Whether to notify instantly */ - public void listenForSubscriber(int subId, @NonNull String pkg, @NonNull String featureId, - @NonNull PhoneStateListener listener, int events, boolean notifyNow) { + public void listenWithEventList(int subId, @NonNull String pkg, @NonNull String featureId, + @NonNull PhoneStateListener listener, @NonNull int[] events, boolean notifyNow) { try { // subId from PhoneStateListener is deprecated Q on forward, use the subId from // TelephonyManager instance. Keep using subId from PhoneStateListener for pre-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. - listener.mSubId = (events == PhoneStateListener.LISTEN_NONE) + listener.mSubId = (events.length == 0) ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId; } else if (listener.mSubId != null) { subId = listener.mSubId; } - sRegistry.listenForSubscriber( + sRegistry.listenWithEventList( subId, pkg, featureId, listener.callback, events, notifyNow); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -765,4 +771,366 @@ public class TelephonyRegistryManager { } } + /** + * Notify {@link PhysicalChannelConfig} has changed for a specific subscription. + * + * @param subId the subId + * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel. + */ + public void notifyPhysicalChannelConfigForSubscriber( + int subId, List<PhysicalChannelConfig> configs) { + try { + sRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs); + } catch (RemoteException ex) { + // system server crash + } + } + + /** + * Notify that the data enabled has changed. + * + * @param enabled True if data is enabled, otherwise disabled. + * @param reason Reason for data enabled/disabled. See {@code REASON_*} in + * {@link TelephonyManager}. + */ + public void notifyDataEnabled(boolean enabled, @TelephonyManager.DataEnabledReason int reason) { + try { + sRegistry.notifyDataEnabled(enabled, reason); + } catch (RemoteException ex) { + // system server crash + } + } + + public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) { + + Set<Integer> eventList = new ArraySet<>(); + + if (listener instanceof PhoneStateListener.ServiceStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.MessageWaitingIndicatorChangedListener) { + eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED); + } + + if (listener instanceof PhoneStateListener.CallForwardingIndicatorChangedListener) { + eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED); + } + + if (listener instanceof PhoneStateListener.CellLocationChangedListener) { + eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED); + } + + if (listener instanceof PhoneStateListener.CallStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.DataConnectionStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.DataActivityListener) { + eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED); + } + + if (listener instanceof PhoneStateListener.SignalStrengthsChangedListener) { + eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED); + } + + if (listener instanceof PhoneStateListener.AlwaysReportedSignalStrengthChangedListener) { + eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED); + } + + if (listener instanceof PhoneStateListener.CellInfoChangedListener) { + eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED); + } + + if (listener instanceof PhoneStateListener.PreciseCallStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.CallDisconnectCauseChangedListener) { + eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED); + } + + if (listener instanceof PhoneStateListener.ImsCallDisconnectCauseChangedListener) { + eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED); + } + + if (listener instanceof PhoneStateListener.PreciseDataConnectionStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.SrvccStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.VoiceActivationStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.DataActivationStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.UserMobileDataStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.DisplayInfoChangedListener) { + eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED); + } + + if (listener instanceof PhoneStateListener.EmergencyNumberListChangedListener) { + eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED); + } + + if (listener instanceof PhoneStateListener.OutgoingEmergencyCallListener) { + eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL); + } + + if (listener instanceof PhoneStateListener.OutgoingEmergencySmsListener) { + eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS); + } + + if (listener instanceof PhoneStateListener.PhoneCapabilityChangedListener) { + eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED); + } + + if (listener instanceof PhoneStateListener.ActiveDataSubscriptionIdChangedListener) { + eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED); + } + + if (listener instanceof PhoneStateListener.RadioPowerStateChangedListener) { + eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED); + } + + if (listener instanceof PhoneStateListener.CarrierNetworkChangeListener) { + eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED); + } + + if (listener instanceof PhoneStateListener.RegistrationFailedListener) { + eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE); + } + + if (listener instanceof PhoneStateListener.CallAttributesChangedListener) { + eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED); + } + + if (listener instanceof PhoneStateListener.BarringInfoChangedListener) { + eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED); + } + + if (listener instanceof PhoneStateListener.PhysicalChannelConfigChangedListener) { + eventList.add(PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); + } + + if (listener instanceof PhoneStateListener.DataEnabledChangedListener) { + eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED); + } + + return eventList; + } + + private @NonNull Set<Integer> getEventsFromBitmask(int eventMask) { + + Set<Integer> eventList = new ArraySet<>(); + + if ((eventMask & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { + eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { + eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { + eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { + eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { + eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { + eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) { + eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) { + eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) { + eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) { + eventList.add(PhoneStateListener.EVENT_OEM_HOOK_RAW); + } + + if ((eventMask & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) { + eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) { + eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) { + eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) { + eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) { + eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) { + eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) { + eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) { + eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) { + eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) { + eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) { + eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED); + } + + if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL) != 0) { + eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL); + } + + if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS) != 0) { + eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS); + } + + if ((eventMask & PhoneStateListener.LISTEN_REGISTRATION_FAILURE) != 0) { + eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE); + } + + if ((eventMask & PhoneStateListener.LISTEN_BARRING_INFO) != 0) { + eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED); + } + return eventList; + + } + + /** + * Registers a listener object to receive notification of changes + * in specified telephony states. + * <p> + * To register a listener, pass a {@link PhoneStateListener} which implements + * interfaces of events. For example, + * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements + * {@link PhoneStateListener.ServiceStateChangedListener}. + * + * At registration, and when a specified telephony state changes, the telephony manager invokes + * the appropriate callback method on the listener object and passes the current (updated) + * values. + * <p> + * + * If this TelephonyManager object has been created with + * {@link TelephonyManager#createForSubscriptionId}, applies to the given subId. + * Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}. + * To listen events for multiple subIds, pass a separate listener object to + * each TelephonyManager object created with {@link TelephonyManager#createForSubscriptionId}. + * + * Note: if you call this method while in the middle of a binder transaction, you <b>must</b> + * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A + * {@link SecurityException} will be thrown otherwise. + * + * This API should be used sparingly -- large numbers of listeners will cause system + * instability. If a process has registered too many listeners without unregistering them, it + * may encounter an {@link IllegalStateException} when trying to register more listeners. + * + * @param listener The {@link PhoneStateListener} object to register. + */ + public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, int subId, + String pkgName, String attributionTag, @NonNull PhoneStateListener listener, + boolean notifyNow) { + listener.setExecutor(executor); + registerPhoneStateListener(subId, pkgName, attributionTag, listener, + getEventsFromListener(listener), notifyNow); + } + + public void registerPhoneStateListenerWithEvents(int subId, String pkgName, + String attributionTag, @NonNull PhoneStateListener listener, int events, + boolean notifyNow) { + registerPhoneStateListener( + subId, pkgName, attributionTag, listener, getEventsFromBitmask(events), notifyNow); + } + + private void registerPhoneStateListener(int subId, + String pkgName, String attributionTag, @NonNull PhoneStateListener listener, + @NonNull Set<Integer> events, boolean notifyNow) { + if (listener == null) { + throw new IllegalStateException("telephony service is null."); + } + + listenWithEventList(subId, pkgName, attributionTag, listener, + events.stream().mapToInt(i -> i).toArray(), notifyNow); + } + + /** + * Unregister an existing {@link PhoneStateListener}. + * + * @param listener The {@link PhoneStateListener} object to unregister. + */ + public void unregisterPhoneStateListener(int subId, String pkgName, String attributionTag, + @NonNull PhoneStateListener listener, + boolean notifyNow) { + listenWithEventList(subId, pkgName, attributionTag, listener, new int[0], notifyNow); + } } diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 17d3ae4a7ff0..471f2c2aecae 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -24,11 +24,12 @@ import android.content.res.Resources; import android.icu.text.MeasureFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; -import android.net.NetworkUtils; import android.text.BidiFormatter; import android.text.TextUtils; import android.view.View; +import com.android.net.module.util.Inet4AddressUtils; + import java.util.Locale; /** @@ -207,7 +208,7 @@ public final class Formatter { */ @Deprecated public static String formatIpAddress(int ipv4Address) { - return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress(); + return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress(); } private static final int SECONDS_PER_MINUTE = 60; diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS index ac80d9f4cdd0..4bcdeea472e3 100644 --- a/core/java/android/view/textclassifier/OWNERS +++ b/core/java/android/view/textclassifier/OWNERS @@ -6,3 +6,5 @@ svetoslavganov@android.com svetoslavganov@google.com augale@google.com joannechung@google.com +tonymak@google.com +licha@google.com diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index c0648ab89c41..2e7629a76dee 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -129,7 +129,7 @@ public class VpnConfig implements Parcelable { String[] routes = routesStr.trim().split(" "); for (String route : routes) { //each route is ip/prefix - RouteInfo info = new RouteInfo(new IpPrefix(route), null); + RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST); this.routes.add(info); updateAllowedFamilies(info.getDestination().getAddress()); } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 790d7f7ab694..6860759eea8a 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -69,15 +69,16 @@ public class WrapperInit { // Tell the Zygote what our actual PID is (since it only knows about the // wrapper that it directly forked). if (fdNum != 0) { + FileDescriptor fd = new FileDescriptor(); try { - FileDescriptor fd = new FileDescriptor(); fd.setInt$(fdNum); DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); os.writeInt(Process.myPid()); os.close(); - IoUtils.closeQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); + } finally { + IoUtils.closeQuietly(fd); } } diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index d2dc7c283ff7..854fb17e692b 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -23,6 +23,7 @@ import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.TelephonyDisplayInfo; import android.telephony.PhoneCapability; +import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; @@ -68,4 +69,6 @@ oneway interface IPhoneStateListener { void onRegistrationFailed(in CellIdentity cellIdentity, String chosenPlmn, int domain, int causeCode, int additionalCauseCode); void onBarringInfoChanged(in BarringInfo barringInfo); + void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs); + void onDataEnabledChanged(boolean enabled, int reason); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 5f2dcc3d22e1..2a73dacbc94a 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -41,16 +41,8 @@ interface ITelephonyRegistry { IOnSubscriptionsChangedListener callback); void removeOnSubscriptionsChangedListener(String pkg, IOnSubscriptionsChangedListener callback); - /** - * @deprecated Use {@link #listenWithFeature(String, String, IPhoneStateListener, int, - * boolean) instead - */ - @UnsupportedAppUsage - void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow); - void listenWithFeature(String pkg, String featureId, IPhoneStateListener callback, int events, - boolean notifyNow); - void listenForSubscriber(in int subId, String pkg, String featureId, - IPhoneStateListener callback, int events, boolean notifyNow); + void listenWithEventList(in int subId, String pkg, String featureId, + IPhoneStateListener callback, in int[] events, boolean notifyNow); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) void notifyCallStateForAllSubs(int state, String incomingNumber); void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber); @@ -99,4 +91,7 @@ interface ITelephonyRegistry { void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity, String chosenPlmn, int domain, int causeCode, int additionalCauseCode); void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo); + void notifyPhysicalChannelConfigForSubscriber(in int subId, + in List<PhysicalChannelConfig> configs); + void notifyDataEnabled(boolean enabled, int reason); } diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java index cd8fc350362d..c583d5a5be37 100644 --- a/core/java/com/android/internal/util/LocationPermissionChecker.java +++ b/core/java/com/android/internal/util/LocationPermissionChecker.java @@ -24,6 +24,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.location.LocationManager; +import android.net.NetworkStack; import android.os.Binder; import android.os.Build; import android.os.UserHandle; @@ -147,6 +148,13 @@ public class LocationPermissionChecker { int uid, @Nullable String message) { checkPackage(uid, pkgName); + // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK + // are granted a bypass. + if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) + || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) { + return SUCCEEDED; + } + // Location mode must be enabled if (!isLocationModeEnabled()) { return ERROR_LOCATION_MODE_OFF; @@ -259,4 +267,37 @@ public class LocationPermissionChecker { // We don't care about pid, pass in -1 return mContext.checkPermission(permissionType, -1, uid); } + + /** + * Returns true if the |uid| holds NETWORK_SETTINGS permission. + */ + public boolean checkNetworkSettingsPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. + */ + public boolean checkNetworkSetupWizardPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds NETWORK_STACK permission. + */ + public boolean checkNetworkStackPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. + */ + public boolean checkMainlineNetworkStackPermission(int uid) { + return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) + == PackageManager.PERMISSION_GRANTED; + } + } diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS index cca39ea3287d..ae566c3988cd 100644 --- a/core/java/com/android/internal/widget/OWNERS +++ b/core/java/com/android/internal/widget/OWNERS @@ -1 +1,7 @@ per-file PointerLocationView.java = michaelwr@google.com, svv@google.com + +# LockSettings related +per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index 0fb29111d043..a9db91be1d5b 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -257,7 +257,17 @@ jobject JHwBlob::NewObject(JNIEnv *env, size_t size) { // XXX Again cannot refer to gFields.constructID because InitClass may // not have been called yet. - return env->NewObject(clazz.get(), constructID, size); + // Cases: + // - this originates from another process (something so large should not fit + // in the binder buffer, and it should be rejected by the binder driver) + // - if this is used in process, this code makes too many heap copies (in + // order to retrofit HIDL's scatter-gather format to java types) to + // justify passing such a large amount of data over this path. So the + // alternative (updating the constructor and other code to accept other + // types, should also probably not be taken in this case). + CHECK_LE(size, std::numeric_limits<jint>::max()); + + return env->NewObject(clazz.get(), constructID, static_cast<jint>(size)); } } // namespace android diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 22dd765f2526..dc98aafb129e 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1810,7 +1810,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; break; } - android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level)); + mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level); // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 2f1bcdc76afb..4b3d82a04b8b 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8968,6 +8968,11 @@ changed at runtime by calling {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}. --> <attr name="tunerCount" format="integer" /> + <!-- Attribute whether the TV input service can pause recording programs. + This value can be changed at runtime by calling + {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)} + . --> + <attr name="canPauseRecording" format="boolean" /> </declare-styleable> <!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e00aff1af37b..a0be0681bd38 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3043,6 +3043,7 @@ =============================================================== --> <public-group type="attr" first-id="0x01010617"> + <public name="canPauseRecording" /> <!-- attribute definitions go here --> </public-group> diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java index f9e3bc60561c..222471a830b1 100644 --- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java +++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java @@ -23,7 +23,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.Manifest; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.BugreportManager; import android.os.BugreportManager.BugreportCallback; import android.os.BugreportParams; @@ -31,7 +34,9 @@ import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.StrictMode; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; @@ -53,10 +58,11 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; - /** * Tests for BugreportManager API. */ @@ -67,8 +73,16 @@ public class BugreportManagerTest { private static final String TAG = "BugreportManagerTest"; private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10); + private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); + // Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name + // associated with the bugreport). + private static final String INTENT_BUGREPORT_FINISHED = + "com.android.internal.intent.action.BUGREPORT_FINISHED"; + private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT"; + private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT"; + private Handler mHandler; private Executor mExecutor; private BugreportManager mBrm; @@ -212,6 +226,48 @@ public class BugreportManagerTest { } @Test + public void cancelBugreport_noReportStarted() throws Exception { + // Without the native DumpstateService running, we don't get a SecurityException. + mBrm.cancelBugreport(); + } + + @LargeTest + @Test + public void cancelBugreport_fromDifferentUid() throws Exception { + assertThat(Process.myUid()).isNotEqualTo(Process.SHELL_UID); + + // Start a bugreport through ActivityManager's shell command - this starts a BR from the + // shell UID rather than our own. + BugreportBroadcastReceiver br = new BugreportBroadcastReceiver(); + InstrumentationRegistry.getContext() + .registerReceiver(br, new IntentFilter(INTENT_BUGREPORT_FINISHED)); + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand("am bug-report"); + + // The command triggers the report through a broadcast, so wait until dumpstate actually + // starts up, which may take a bit. + waitTillDumpstateRunningOrTimeout(); + + try { + mBrm.cancelBugreport(); + fail("Expected cancelBugreport to throw SecurityException when report started by " + + "different UID"); + } catch (SecurityException expected) { + } finally { + // Do this in the finally block so that even if this test case fails, we don't break + // other test cases unexpectedly due to the still-running shell report. + try { + // The shell's BR is still running and should complete successfully. + br.waitForBugreportFinished(); + } finally { + // The latch may fail for a number of reasons but we still need to unregister the + // BroadcastReceiver. + InstrumentationRegistry.getContext().unregisterReceiver(br); + } + } + } + + @Test public void insufficientPermissions_throwsException() throws Exception { dropPermissions(); @@ -346,6 +402,28 @@ public class BugreportManagerTest { .adoptShellPermissionIdentity(Manifest.permission.DUMP); } + private static boolean isDumpstateRunning() { + String[] output; + try { + output = + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand("ps -A -o NAME | grep dumpstate") + .trim() + .split("\n"); + } catch (IOException e) { + Log.w(TAG, "Failed to check if dumpstate is running", e); + return false; + } + for (String line : output) { + // Check for an exact match since there may be other things that contain "dumpstate" as + // a substring (e.g. the dumpstate HAL). + if (TextUtils.equals("dumpstate", line)) { + return true; + } + } + return false; + } + private static void assertFdIsClosed(ParcelFileDescriptor pfd) { try { int fd = pfd.getFd(); @@ -364,18 +442,25 @@ public class BugreportManagerTest { return System.currentTimeMillis(); } - private static boolean shouldTimeout(long startTimeMs) { - return now() - startTimeMs >= BUGREPORT_TIMEOUT_MS; + private static void waitTillDumpstateRunningOrTimeout() throws Exception { + long startTimeMs = now(); + while (!isDumpstateRunning()) { + Thread.sleep(500 /* .5s */); + if (now() - startTimeMs >= DUMPSTATE_STARTUP_TIMEOUT_MS) { + break; + } + Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for dumpstate to start"); + } } private static void waitTillDoneOrTimeout(BugreportCallbackImpl callback) throws Exception { long startTimeMs = now(); while (!callback.isDone()) { Thread.sleep(1000 /* 1s */); - if (shouldTimeout(startTimeMs)) { + if (now() - startTimeMs >= BUGREPORT_TIMEOUT_MS) { break; } - Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms"); + Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for bugreport to finish"); } } @@ -450,6 +535,36 @@ public class BugreportManagerTest { assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)); } + private class BugreportBroadcastReceiver extends BroadcastReceiver { + Intent mBugreportFinishedIntent = null; + final CountDownLatch mLatch; + + BugreportBroadcastReceiver() { + mLatch = new CountDownLatch(1); + } + + @Override + public void onReceive(Context context, Intent intent) { + setBugreportFinishedIntent(intent); + mLatch.countDown(); + } + + private void setBugreportFinishedIntent(Intent intent) { + mBugreportFinishedIntent = intent; + } + + public Intent getBugreportFinishedIntent() { + return mBugreportFinishedIntent; + } + + public void waitForBugreportFinished() throws Exception { + if (!mLatch.await(BUGREPORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + throw new Exception("Failed to receive BUGREPORT_FINISHED in " + + BUGREPORT_TIMEOUT_MS + " ms."); + } + } + } + /** * A rule to change strict mode vm policy temporarily till test method finished. * diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS index 696aa11618ff..912db1e835dc 100644 --- a/core/tests/coretests/src/android/content/OWNERS +++ b/core/tests/coretests/src/android/content/OWNERS @@ -1,4 +1,3 @@ per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS -per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS new file mode 100644 index 000000000000..711f5f012b8b --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/OWNERS @@ -0,0 +1,2 @@ +per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS + diff --git a/core/tests/coretests/src/android/view/autofill/OWNERS b/core/tests/coretests/src/android/view/autofill/OWNERS new file mode 100644 index 000000000000..9a30e826a24f --- /dev/null +++ b/core/tests/coretests/src/android/view/autofill/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 351486 + +include /core/java/android/view/autofill/OWNERS diff --git a/core/tests/coretests/src/android/view/contentcapture/OWNERS b/core/tests/coretests/src/android/view/contentcapture/OWNERS new file mode 100644 index 000000000000..24561c59bba6 --- /dev/null +++ b/core/tests/coretests/src/android/view/contentcapture/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 544200 + +include /core/java/android/view/contentcapture/OWNERS diff --git a/core/tests/coretests/src/android/view/textclassifier/OWNERS b/core/tests/coretests/src/android/view/textclassifier/OWNERS new file mode 100644 index 000000000000..46b3cb8824a0 --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/OWNERS @@ -0,0 +1 @@ +include /core/java/android/service/textclassifier/OWNERS diff --git a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java index 4c3eaeb1730b..7175f562d7ef 100644 --- a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java @@ -15,6 +15,8 @@ */ package com.android.internal.util; +import static android.Manifest.permission.NETWORK_SETTINGS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -82,6 +84,7 @@ public class LocationPermissionCheckerTest { private int mAllowCoarseLocationApps; private int mFineLocationPermission; private int mAllowFineLocationApps; + private int mNetworkSettingsPermission; private int mCurrentUser; private boolean mIsLocationEnabled; private boolean mThrowSecurityException; @@ -138,6 +141,7 @@ public class LocationPermissionCheckerTest { mFineLocationPermission = PackageManager.PERMISSION_DENIED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED; } private void setupMockInterface() { @@ -151,6 +155,8 @@ public class LocationPermissionCheckerTest { .thenReturn(mCoarseLocationPermission); when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) .thenReturn(mFineLocationPermission); + when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid)) + .thenReturn(mNetworkSettingsPermission); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); } @@ -264,6 +270,21 @@ public class LocationPermissionCheckerTest { assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); } + @Test + public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings() + throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = false; + mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.SUCCEEDED, result); + } + + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { try { r.run(); diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java index 6c733ba712d5..33e8dede9f5c 100644 --- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java @@ -139,7 +139,9 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength, inputLength); inputLength -= inputConsumed; - inputOffset += inputOffset; + inputOffset += inputConsumed; + mChunkLength += inputConsumed; + if (mChunkLength < mChunkSizeMax) return output; byte[] o = mKeyStoreStream.update(mChunk); if (o != null) { output = ArrayUtils.concat(output, o); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 158c3493a90c..2edd48c5a41b 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -102,12 +102,12 @@ bool SkiaDisplayList::prepareListAndChildren( bool hasBackwardProjectedNodesSubtree = false; for (auto& child : mChildNodes) { - hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); RenderNode* childNode = child.getRenderNode(); Matrix4 mat4(child.getRecordedMatrix()); info.damageAccumulator->pushTransform(&mat4); info.hasBackwardProjectedNodes = false; childFn(childNode, observer, info, functorsNeedLayer); + hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes; info.damageAccumulator->popTransform(); } diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 068f9689d06f..4b8a8adade1f 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -73,6 +73,8 @@ interface IMediaRouterService { void unregisterManager(IMediaRouter2Manager manager); void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, in MediaRoute2Info route, int volume); + void startScan(IMediaRouter2Manager manager); + void stopScan(IMediaRouter2Manager manager); void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId, in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route); diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 4b09a5f19fb0..68237de2ca98 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -147,6 +147,36 @@ public final class MediaRouter2Manager { } /** + * Starts scanning remote routes. + * @see #stopScan(String) + */ + public void startScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.startScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** + * Stops scanning remote routes to reduce resource consumption. + * @see #startScan(String) + */ + public void stopScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.stopScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** * Gets a {@link android.media.session.MediaController} associated with the * given routing session. * If there is no matching media session, {@code null} is returned. diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java index 68f2964dbeb2..2f952474b7f0 100644 --- a/media/java/android/media/RouteDiscoveryPreference.java +++ b/media/java/android/media/RouteDiscoveryPreference.java @@ -153,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable { return false; } RouteDiscoveryPreference other = (RouteDiscoveryPreference) o; + //TODO: Make this order-free return Objects.equals(mPreferredFeatures, other.mPreferredFeatures) && mShouldPerformActiveScan == other.mShouldPerformActiveScan; } diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index 1fbb67260895..5d7fdff70f5c 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -91,6 +91,8 @@ interface ITvInputManager { // For the recording session void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId); void stopRecording(in IBinder sessionToken, int userId); + void pauseRecording(in IBinder sessionToken, in Bundle params, int userId); + void resumeRecording(in IBinder sessionToken, in Bundle params, int userId); // For TV input hardware binding List<TvInputHardwareInfo> getHardwareList(); diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl index 24b87d50b33e..158cf211d9f0 100644 --- a/media/java/android/media/tv/ITvInputSession.aidl +++ b/media/java/android/media/tv/ITvInputSession.aidl @@ -58,4 +58,6 @@ oneway interface ITvInputSession { // For the recording session void startRecording(in Uri programUri, in Bundle params); void stopRecording(); + void pauseRecording(in Bundle params); + void resumeRecording(in Bundle params); } diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index e89d33d70d5c..abccf8da9cfc 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -68,6 +68,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19; private static final int DO_START_RECORDING = 20; private static final int DO_STOP_RECORDING = 21; + private static final int DO_PAUSE_RECORDING = 22; + private static final int DO_RESUME_RECORDING = 23; private final boolean mIsRecordingSession; private final HandlerCaller mCaller; @@ -224,6 +226,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mTvInputRecordingSessionImpl.stopRecording(); break; } + case DO_PAUSE_RECORDING: { + mTvInputRecordingSessionImpl.pauseRecording((Bundle) msg.obj); + break; + } + case DO_RESUME_RECORDING: { + mTvInputRecordingSessionImpl.resumeRecording((Bundle) msg.obj); + break; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); break; @@ -363,6 +373,16 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_STOP_RECORDING)); } + @Override + public void pauseRecording(@Nullable Bundle params) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_PAUSE_RECORDING, params)); + } + + @Override + public void resumeRecording(@Nullable Bundle params) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESUME_RECORDING, params)); + } + private final class TvInputEventReceiver extends InputEventReceiver { public TvInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java index b12f7c551288..1249e0d3cb0f 100644 --- a/media/java/android/media/tv/TvInputHardwareInfo.java +++ b/media/java/android/media/tv/TvInputHardwareInfo.java @@ -188,6 +188,17 @@ public final class TvInputHardwareInfo implements Parcelable { mCableConnectionStatus = source.readInt(); } + /** @hide */ + public Builder toBuilder() { + return new Builder() + .deviceId(mDeviceId) + .type(mType) + .audioType(mAudioType) + .audioAddress(mAudioAddress) + .hdmiPortId(mHdmiPortId) + .cableConnectionStatus(mCableConnectionStatus); + } + public static final class Builder { private Integer mDeviceId = null; private Integer mType = null; diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 195ad5bc10f9..54cb2bff5566 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -143,6 +143,7 @@ public final class TvInputInfo implements Parcelable { // Attributes from XML meta data. private final String mSetupActivity; private final boolean mCanRecord; + private final boolean mCanPauseRecording; private final int mTunerCount; // Attributes specific to HDMI @@ -264,8 +265,8 @@ public final class TvInputInfo implements Parcelable { private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput, CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected, - String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo, - boolean isConnectedToHdmiSwitch, + String setupActivity, boolean canRecord, boolean canPauseRecording, int tunerCount, + HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, @HdmiAddressRelativePosition int hdmiConnectionRelativePosition, String parentId, Bundle extras) { mService = service; @@ -279,6 +280,7 @@ public final class TvInputInfo implements Parcelable { mIconDisconnected = iconDisconnected; mSetupActivity = setupActivity; mCanRecord = canRecord; + mCanPauseRecording = canPauseRecording; mTunerCount = tunerCount; mHdmiDeviceInfo = hdmiDeviceInfo; mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch; @@ -386,6 +388,14 @@ public final class TvInputInfo implements Parcelable { } /** + * Returns {@code true} if this TV input can pause recording TV programs, + * {@code false} otherwise. + */ + public boolean canPauseRecording() { + return mCanPauseRecording; + } + + /** * Returns domain-specific extras associated with this TV input. */ public Bundle getExtras() { @@ -571,6 +581,7 @@ public final class TvInputInfo implements Parcelable { && Objects.equals(mIconDisconnected, obj.mIconDisconnected) && TextUtils.equals(mSetupActivity, obj.mSetupActivity) && mCanRecord == obj.mCanRecord + && mCanPauseRecording == obj.mCanPauseRecording && mTunerCount == obj.mTunerCount && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo) && mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch @@ -606,6 +617,7 @@ public final class TvInputInfo implements Parcelable { dest.writeParcelable(mIconDisconnected, flags); dest.writeString(mSetupActivity); dest.writeByte(mCanRecord ? (byte) 1 : 0); + dest.writeByte(mCanPauseRecording ? (byte) 1 : 0); dest.writeInt(mTunerCount); dest.writeParcelable(mHdmiDeviceInfo, flags); dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0); @@ -648,6 +660,7 @@ public final class TvInputInfo implements Parcelable { mIconDisconnected = in.readParcelable(null); mSetupActivity = in.readString(); mCanRecord = in.readByte() == 1; + mCanPauseRecording = in.readByte() == 1; mTunerCount = in.readInt(); mHdmiDeviceInfo = in.readParcelable(null); mIsConnectedToHdmiSwitch = in.readByte() == 1; @@ -695,6 +708,7 @@ public final class TvInputInfo implements Parcelable { private Icon mIconDisconnected; private String mSetupActivity; private Boolean mCanRecord; + private Boolean mCanPauseRecording; private Integer mTunerCount; private TvInputHardwareInfo mTvInputHardwareInfo; private HdmiDeviceInfo mHdmiDeviceInfo; @@ -879,6 +893,18 @@ public final class TvInputInfo implements Parcelable { } /** + * Sets whether this TV input can pause recording TV programs or not. + * + * @param canPauseRecording Whether this TV input can pause recording TV programs. + * @return This Builder object to allow for chaining of calls to builder methods. + */ + @NonNull + public Builder setCanPauseRecording(boolean canPauseRecording) { + this.mCanPauseRecording = canPauseRecording; + return this; + } + + /** * Sets domain-specific extras associated with this TV input. * * @param extras Domain-specific extras associated with this TV input. Keys <em>must</em> be @@ -927,7 +953,9 @@ public final class TvInputInfo implements Parcelable { parseServiceMetadata(type); return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId, mIcon, mIconStandby, mIconDisconnected, mSetupActivity, - mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount, + mCanRecord == null ? false : mCanRecord, + mCanPauseRecording == null ? false : mCanPauseRecording, + mTunerCount == null ? 0 : mTunerCount, mHdmiDeviceInfo, isConnectedToHdmiSwitch, hdmiConnectionRelativePosition, mParentId, mExtras); } @@ -997,6 +1025,12 @@ public final class TvInputInfo implements Parcelable { mTunerCount = sa.getInt( com.android.internal.R.styleable.TvInputService_tunerCount, 1); } + if (mCanPauseRecording == null) { + mCanPauseRecording = sa.getBoolean( + com.android.internal.R.styleable.TvInputService_canPauseRecording, + false); + } + sa.recycle(); } catch (IOException | XmlPullParserException e) { throw new IllegalStateException("Failed reading meta-data for " + si.packageName, e); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 98a01a4cb449..6341dc263efd 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -2476,6 +2476,40 @@ public final class TvInputManager { } /** + * Pauses TV program recording in the current recording session. + * + * @param params A set of extra parameters which might be handled with this event. + */ + void pauseRecording(@NonNull Bundle params) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.pauseRecording(mToken, params, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Resumes TV program recording in the current recording session. + * + * @param params A set of extra parameters which might be handled with this event. + */ + void resumeRecording(@NonNull Bundle params) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.resumeRecording(mToken, params, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle) * TvInputService.Session.appPrivateCommand()} on the current TvView. * diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index abbf4780bcc1..0fe9d504b951 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -1852,6 +1852,28 @@ public abstract class TvInputService extends Service { /** + * Called when the application requests to pause TV program recording. Recording must pause + * immediately when this method is called. + * + * If the pause request cannot be fulfilled, the session must call + * {@link #notifyError(int)}. + * + * @param params Domain-specific data for recording request. + */ + public void onPauseRecording(@NonNull Bundle params) { } + + /** + * Called when the application requests to resume TV program recording. Recording must + * resume immediately when this method is called. + * + * If the resume request cannot be fulfilled, the session must call + * {@link #notifyError(int)}. + * + * @param params Domain-specific data for recording request. + */ + public void onResumeRecording(@NonNull Bundle params) { } + + /** * Called when the application requests to release all the resources held by this recording * session. */ @@ -1903,6 +1925,22 @@ public abstract class TvInputService extends Service { } /** + * Calls {@link #onPauseRecording(Bundle)}. + * + */ + void pauseRecording(@NonNull Bundle params) { + onPauseRecording(params); + } + + /** + * Calls {@link #onResumeRecording(Bundle)}. + * + */ + void resumeRecording(@NonNull Bundle params) { + onResumeRecording(params); + } + + /** * Calls {@link #onAppPrivateCommand(String, Bundle)}. */ void appPrivateCommand(String action, Bundle data) { diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java index 23fadac8a72b..180e2bd6845b 100644 --- a/media/java/android/media/tv/TvRecordingClient.java +++ b/media/java/android/media/tv/TvRecordingClient.java @@ -30,6 +30,7 @@ import android.util.Log; import android.util.Pair; import java.util.ArrayDeque; +import java.util.Objects; import java.util.Queue; /** @@ -49,6 +50,8 @@ public class TvRecordingClient { private boolean mIsRecordingStarted; private boolean mIsTuned; + private boolean mIsPaused; + private boolean mIsRecordingStopping; private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>(); /** @@ -113,17 +116,22 @@ public class TvRecordingClient { if (TextUtils.isEmpty(inputId)) { throw new IllegalArgumentException("inputId cannot be null or an empty string"); } - if (mIsRecordingStarted) { + if (mIsRecordingStarted && !mIsPaused) { throw new IllegalStateException("tune failed - recording already started"); } if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) { if (mSession != null) { + mSessionCallback.mChannelUri = channelUri; mSession.tune(channelUri, params); } else { mSessionCallback.mChannelUri = channelUri; mSessionCallback.mConnectionParams = params; } + mIsTuned = false; } else { + if (mIsPaused) { + throw new IllegalStateException("tune failed - inputId is changed during pause"); + } resetInternal(); mSessionCallback = new MySessionCallback(inputId, channelUri, params); if (mTvInputManager != null) { @@ -148,6 +156,8 @@ public class TvRecordingClient { mSession.release(); mIsTuned = false; mIsRecordingStarted = false; + mIsPaused = false; + mIsRecordingStopping = false; mSession = null; } } @@ -169,7 +179,8 @@ public class TvRecordingClient { * * @param programUri The URI for the TV program to record, built by * {@link TvContract#buildProgramUri(long)}. Can be {@code null}. - * @throws IllegalStateException If {@link #tune} request hasn't been handled yet. + * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during + * pause. */ public void startRecording(@Nullable Uri programUri) { startRecording(programUri, Bundle.EMPTY); @@ -195,11 +206,16 @@ public class TvRecordingClient { * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped * name, i.e. prefixed with a package name you own, so that different developers will * not create conflicting keys. - * @throws IllegalStateException If {@link #tune} request hasn't been handled yet. + * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during + * pause. */ public void startRecording(@Nullable Uri programUri, @NonNull Bundle params) { - if (!mIsTuned) { - throw new IllegalStateException("startRecording failed - not yet tuned"); + if (mIsRecordingStopping || !mIsTuned || mIsPaused) { + throw new IllegalStateException("startRecording failed -" + + "recording not yet stopped or not yet tuned or paused"); + } + if (mIsRecordingStarted) { + Log.w(TAG, "startRecording failed - recording already started"); } if (mSession != null) { mSession.startRecording(programUri, params); @@ -225,6 +241,103 @@ public class TvRecordingClient { } if (mSession != null) { mSession.stopRecording(); + if (mIsRecordingStarted) { + mIsRecordingStopping = true; + } + } + } + + /** + * Pause TV program recording in the current recording session. Recording is expected to pause + * immediately when this method is called. If recording has not yet started in the current + * recording session, this method does nothing. + * + * <p>In pause status, the application can tune during recording. To continue recording, + * please call {@link TvRecordingClient#resumeRecording()} to resume instead of + * {@link TvRecordingClient#startRecording(Uri)}. Application can stop + * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status. + * + * <p>If the pause request cannot be fulfilled, the recording session will respond by calling + * {@link RecordingCallback#onError(int)}. + */ + public void pauseRecording() { + pauseRecording(Bundle.EMPTY); + } + + /** + * Pause TV program recording in the current recording session. Recording is expected to pause + * immediately when this method is called. If recording has not yet started in the current + * recording session, this method does nothing. + * + * <p>In pause status, the application can tune during recording. To continue recording, + * please call {@link TvRecordingClient#resumeRecording()} to resume instead of + * {@link TvRecordingClient#startRecording(Uri)}. Application can stop + * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status. + * + * <p>If the pause request cannot be fulfilled, the recording session will respond by calling + * {@link RecordingCallback#onError(int)}. + * + * @param params Domain-specific data for this request. + */ + public void pauseRecording(@NonNull Bundle params) { + if (!mIsRecordingStarted || mIsRecordingStopping) { + throw new IllegalStateException( + "pauseRecording failed - recording not yet started or stopping"); + } + TvInputInfo info = mTvInputManager.getTvInputInfo(mSessionCallback.mInputId); + if (info == null || !info.canPauseRecording()) { + throw new UnsupportedOperationException( + "pauseRecording failed - operation not supported"); + } + if (mIsPaused) { + Log.w(TAG, "pauseRecording failed - recording already paused"); + } + if (mSession != null) { + mSession.pauseRecording(params); + mIsPaused = true; + } + } + + /** + * Resume TV program recording only in recording pause status in the current recording session. + * Recording is expected to resume immediately when this method is called. If recording has not + * yet paused in the current recording session, this method does nothing. + * + * <p>When record is resumed, the recording is continue and can not re-tune. Application can + * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed. + * + * <p>If the pause request cannot be fulfilled, the recording session will respond by calling + * {@link RecordingCallback#onError(int)}. + */ + public void resumeRecording() { + resumeRecording(Bundle.EMPTY); + } + + /** + * Resume TV program recording only in recording pause status in the current recording session. + * Recording is expected to resume immediately when this method is called. If recording has not + * yet paused in the current recording session, this method does nothing. + * + * <p>When record is resumed, the recording is continues and can not re-tune. Application can + * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed. + * + * <p>If the resume request cannot be fulfilled, the recording session will respond by calling + * {@link RecordingCallback#onError(int)}. + * + * @param params Domain-specific data for this request. + */ + public void resumeRecording(@NonNull Bundle params) { + if (!mIsRecordingStarted || mIsRecordingStopping || !mIsTuned) { + throw new IllegalStateException( + "resumeRecording failed - recording not yet started or stopping or " + + "not yet tuned"); + } + if (!mIsPaused) { + Log.w(TAG, "resumeRecording failed - recording not yet paused"); + } + if (mSession != null) { + mSession.resumeRecording(params); + mIsPaused = false; } } @@ -367,6 +480,10 @@ public class TvRecordingClient { Log.w(TAG, "onTuned - session not created"); return; } + if (mIsTuned || !Objects.equals(mChannelUri, channelUri)) { + Log.w(TAG, "onTuned - already tuned or not yet tuned to last channel"); + return; + } mIsTuned = true; mCallback.onTuned(channelUri); } @@ -382,6 +499,8 @@ public class TvRecordingClient { } mIsTuned = false; mIsRecordingStarted = false; + mIsPaused = false; + mIsRecordingStopping = false; mSessionCallback = null; mSession = null; if (mCallback != null) { @@ -398,7 +517,13 @@ public class TvRecordingClient { Log.w(TAG, "onRecordingStopped - session not created"); return; } + if (!mIsRecordingStarted) { + Log.w(TAG, "onRecordingStopped - recording not yet started"); + return; + } mIsRecordingStarted = false; + mIsPaused = false; + mIsRecordingStopping = false; mCallback.onRecordingStopped(recordedProgramUri); } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 741a6803a1e3..4b6862c6d186 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -156,6 +156,7 @@ <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" /> <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" /> <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" /> + <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" /> <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.SET_TIME" /> @@ -345,6 +346,9 @@ <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <!-- Permission required for CTS test - CtsSensorPrivacyTestCases --> + <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 309d4b04ebbf..c5a35eaf3e6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -29,7 +29,6 @@ import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.IConnectivityManager; import android.net.Network; -import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.Handler; import android.os.RemoteException; @@ -66,12 +65,8 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi private static final String TAG = "SecurityController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final NetworkRequest REQUEST = new NetworkRequest.Builder() - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .setUids(null) - .build(); + private static final NetworkRequest REQUEST = + new NetworkRequest.Builder().clearCapabilities().build(); private static final int NO_NETWORK = -1; private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED"; diff --git a/packages/services/CameraExtensionsProxy/OWNERS b/packages/services/CameraExtensionsProxy/OWNERS new file mode 100644 index 000000000000..f48a95c5b3a3 --- /dev/null +++ b/packages/services/CameraExtensionsProxy/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/av:/camera/OWNERS diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6b45abde74b4..7541833b1569 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -194,7 +194,6 @@ import com.android.server.connectivity.AutodestructReference; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; -import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; import com.android.server.connectivity.MockableSystemProperties; @@ -889,6 +888,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** + * Get a reference to the system keystore. + */ + public KeyStore getKeyStore() { + return KeyStore.getInstance(); + } + + /** * @see ProxyTracker */ public ProxyTracker makeProxyTracker(@NonNull Context context, @@ -918,14 +924,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return new MultinetworkPolicyTracker(c, h, r); } - /** - * @see IpConnectivityMetrics.Logger - */ - public IpConnectivityMetrics.Logger getMetricsLogger() { - return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class), - "no IpConnectivityMetrics service"); - } - public IBatteryStats getBatteryStatsService() { return BatteryStatsService.getService(); } @@ -990,7 +988,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler); mNetd = netd; - mKeyStore = KeyStore.getInstance(); + mKeyStore = mDeps.getKeyStore(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); @@ -1653,7 +1651,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) { if (nai == null) return null; synchronized (nai) { - if (nai.networkCapabilities == null) return null; return networkCapabilitiesRestrictedForCallerPermissions( nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid()); } @@ -2777,7 +2774,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) { - if (nai.network == null) return false; final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network); if (officialNai != null && officialNai.equals(nai)) return true; if (officialNai != null || VDBG) { @@ -3470,6 +3466,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // available until we've told netd to delete it below. mNetworkForNetId.remove(nai.network.getNetId()); } + propagateUnderlyingNetworkCapabilities(nai.network); // Remove all previously satisfied requests. for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest request = nai.requestAt(i); @@ -3482,7 +3479,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } } nai.clearLingerState(); - propagateUnderlyingNetworkCapabilities(nai.network); + // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given + // there's a full rematch right after. Currently, deleting it breaks tests that check for + // the default network disconnecting. Find out why, fix the rematch code, and delete this. if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) { mDefaultNetworkNai = null; updateDataActivityTracking(null /* newNetwork */, nai); @@ -4993,16 +4992,23 @@ public class ConnectivityService extends IConnectivityManager.Stub mVpnBlockedUidRanges = newVpnBlockedUidRanges; } + private boolean isLockdownVpnEnabled() { + return mKeyStore.contains(Credentials.LOCKDOWN_VPN); + } + @Override public boolean updateLockdownVpn() { - if (mDeps.getCallingUid() != Process.SYSTEM_UID) { - logw("Lockdown VPN only available to AID_SYSTEM"); + // Allow the system UID for the system server and for Settings. + // Also, for unit tests, allow the process that ConnectivityService is running in. + if (mDeps.getCallingUid() != Process.SYSTEM_UID + && Binder.getCallingPid() != Process.myPid()) { + logw("Lockdown VPN only available to system process or AID_SYSTEM"); return false; } synchronized (mVpns) { // Tear down existing lockdown if profile was removed - mLockdownEnabled = LockdownVpnTracker.isEnabled(); + mLockdownEnabled = isLockdownVpnEnabled(); if (mLockdownEnabled) { byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN); if (profileTag == null) { @@ -5023,7 +5029,8 @@ public class ConnectivityService extends IConnectivityManager.Stub logw("VPN for user " + user + " not ready yet. Skipping lockdown"); return false; } - setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile)); + setLockdownTracker( + new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn, profile)); } else { setLockdownTracker(null); } @@ -5111,7 +5118,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mVpns) { // Can't set always-on VPN if legacy VPN is already in lockdown mode. - if (LockdownVpnTracker.isEnabled()) { + if (isLockdownVpnEnabled()) { return false; } @@ -5217,7 +5224,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore); mVpns.put(userId, userVpn); - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { + if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) { updateLockdownVpn(); } } @@ -5301,7 +5308,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void onUserUnlocked(int userId) { synchronized (mVpns) { // User present may be sent because of an unlock, which might mean an unlocked keystore. - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { + if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) { updateLockdownVpn(); } else { startAlwaysOnVpn(userId); @@ -6068,6 +6075,10 @@ public class ConnectivityService extends IConnectivityManager.Stub public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { + Objects.requireNonNull(networkInfo, "networkInfo must not be null"); + Objects.requireNonNull(linkProperties, "linkProperties must not be null"); + Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null"); if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS); } else { @@ -6606,7 +6617,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Don't modify caller's NetworkCapabilities. - NetworkCapabilities newNc = new NetworkCapabilities(nc); + final NetworkCapabilities newNc = new NetworkCapabilities(nc); if (nai.lastValidated) { newNc.addCapability(NET_CAPABILITY_VALIDATED); } else { @@ -6694,26 +6705,21 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } - // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps - // never returns null), so mark the relevant members and functions in nai as @NonNull and - // remove this test - if (prevNc != null) { - final boolean oldMetered = prevNc.isMetered(); - final boolean newMetered = newNc.isMetered(); - final boolean meteredChanged = oldMetered != newMetered; + final boolean oldMetered = prevNc.isMetered(); + final boolean newMetered = newNc.isMetered(); + final boolean meteredChanged = oldMetered != newMetered; - if (meteredChanged) { - maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); - } + if (meteredChanged) { + maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, + mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); + } - final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) != - newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); + final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) + != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); - // Report changes that are interesting for network statistics tracking. - if (meteredChanged || roamingChanged) { - notifyIfacesChangedForNetworkStats(); - } + // Report changes that are interesting for network statistics tracking. + if (meteredChanged || roamingChanged) { + notifyIfacesChangedForNetworkStats(); } // This network might have been underlying another network. Propagate its capabilities. @@ -7588,10 +7594,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) { networkAgent.everConnected = true; - if (networkAgent.linkProperties == null) { - Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties"); - } - // NetworkCapabilities need to be set before sending the private DNS config to // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required. networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index f6b72d6bfe2c..d43b8a313c20 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -6,7 +6,7 @@ per-file VibratorService.java, DisplayThread.java = michaelwr@google.com per-file VibratorService.java, DisplayThread.java = ogunwale@google.com # Zram writeback -per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com +per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com # Userspace reboot per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com @@ -31,6 +31,7 @@ per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWN per-file MmsServiceBroker.java = file:/telephony/OWNERS per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS +per-file PinnerService.java = file:/apct-tests/perftests/OWNERS per-file TelephonyRegistry.java = file:/telephony/OWNERS per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index c8d457d370ff..5c34584d0adf 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1537,6 +1537,9 @@ class StorageManagerService extends IStorageManager.Stub mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (vol.type == VolumeInfo.TYPE_STUB) { + if (vol.disk.isStubVisible()) { + vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; + } vol.mountUserId = mCurrentUserId; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else { @@ -1606,7 +1609,6 @@ class StorageManagerService extends IStorageManager.Stub } } - private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) { synchronized (mLock) { // Remember that we saw this volume so we're ready to accept user @@ -3427,6 +3429,27 @@ class StorageManagerService extends IStorageManager.Stub } } + /* + * Disable storage's app data isolation for testing. + */ + @Override + public void disableAppDataIsolation(String pkgName, int pid, int userId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { + throw new SecurityException("no permission to enable app visibility"); + } + final String[] sharedPackages = + mPmInternal.getSharedUserPackagesForPackage(pkgName, userId); + final int uid = mPmInternal.getPackageUid(pkgName, 0, userId); + final String[] packages = + sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName}; + try { + mVold.unmountAppStorageDirs(uid, pid, packages); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + /** Not thread safe */ class AppFuseMountScope extends AppFuseBridge.MountScope { private boolean mMounted = false; diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 5f6e8df30f8d..5560f8137e4c 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -64,6 +64,7 @@ import android.telephony.DisconnectCause; import android.telephony.LocationAccessPolicy; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; +import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.PreciseDisconnectCause; @@ -78,6 +79,7 @@ import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.LocalLog; import android.util.Pair; @@ -99,10 +101,13 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * Since phone process can be restarted, this class provides a centralized place @@ -142,14 +147,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { int callerUid; int callerPid; - int events; + Set<Integer> eventList; int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - boolean matchPhoneStateListenerEvent(int events) { - return (callback != null) && ((events & this.events) != 0); + boolean matchPhoneStateListenerEvent(int event) { + return (callback != null) && (this.eventList.contains(event)); } boolean matchOnSubscriptionsChangedListener() { @@ -177,7 +182,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId - + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}"; + + " phoneId=" + phoneId + " events=" + eventList + "}"; } } @@ -306,6 +311,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private final LocalLog mListenLog = new LocalLog(200); + private List<PhysicalChannelConfig> mPhysicalChannelConfigs; + + private boolean mIsDataEnabled = false; + + private int mDataEnabledReason; + /** * Per-phone map of precise data connection state. The key of the map is the pair of transport * type and APN setting. This is the cache to prevent redundant callbacks to the listeners. @@ -315,39 +326,62 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>> mPreciseDataConnectionStates; - // Starting in Q, almost all cellular location requires FINE location enforcement. - // Prior to Q, cellular was available with COARSE location enforcement. Bits in this - // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later. - static final int ENFORCE_LOCATION_PERMISSION_MASK = - PhoneStateListener.LISTEN_CELL_LOCATION - | PhoneStateListener.LISTEN_CELL_INFO - | PhoneStateListener.LISTEN_REGISTRATION_FAILURE - | PhoneStateListener.LISTEN_BARRING_INFO; - - static final int ENFORCE_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR - | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR - | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST - | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED; - - static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_PRECISE_CALL_STATE - | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES - | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED - | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES - | PhoneStateListener.LISTEN_REGISTRATION_FAILURE - | PhoneStateListener.LISTEN_BARRING_INFO; - - static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK = - PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL - | PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS; - - static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT - | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED - | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED - | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE; + private static final Set<Integer> REQUIRE_PRECISE_PHONE_STATE_PERMISSION; + static { + REQUIRE_PRECISE_PHONE_STATE_PERMISSION = new HashSet<Integer>(); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + PhoneStateListener.EVENT_DATA_ENABLED_CHANGED); + } + + private boolean isLocationPermissionRequired(Set<Integer> events) { + return events.contains(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED) + || events.contains(PhoneStateListener.EVENT_CELL_INFO_CHANGED) + || events.contains(PhoneStateListener.EVENT_REGISTRATION_FAILURE) + || events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED); + } + + private boolean isPhoneStatePermissionRequired(Set<Integer> events) { + return events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED) + || events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED) + || events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED) + || events.contains(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED); + } + + private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) { + for (Integer requireEvent : REQUIRE_PRECISE_PHONE_STATE_PERMISSION) { + if (events.contains(requireEvent)) { + return true; + } + } + return false; + } + + private boolean isActiveEmergencySessionPermissionRequired(Set<Integer> events) { + return events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL) + || events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS); + } + + private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) { + return events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED) + || events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED) + || events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED); + } private static final int MSG_USER_SWITCHED = 1; private static final int MSG_UPDATE_DEFAULT_SUB = 2; @@ -495,6 +529,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mImsReasonInfo, mNumPhones); cutListToSize(mPreciseDataConnectionStates, mNumPhones); cutListToSize(mBarringInfo, mNumPhones); + cutListToSize(mPhysicalChannelConfigs, mNumPhones); return; } @@ -528,6 +563,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPreciseDataConnectionStates.add(new ArrayMap<>()); mBarringInfo.add(i, new BarringInfo()); mTelephonyDisplayInfos[i] = null; + mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); } } @@ -588,6 +624,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones]; mBarringInfo = new ArrayList<>(); mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones]; + mPhysicalChannelConfigs = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -617,6 +654,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPreciseDataConnectionStates.add(new ArrayMap<>()); mBarringInfo.add(i, new BarringInfo()); mTelephonyDisplayInfos[i] = null; + mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -659,7 +697,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); - r.events = 0; + r.eventList = new ArraySet<>(); if (DBG) { log("listen oscl: Register r=" + r); } @@ -713,7 +751,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); - r.events = 0; + r.eventList = new ArraySet<>(); if (DBG) { log("listen ooscl: Register r=" + r); } @@ -786,323 +824,337 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - @Deprecated @Override - public void listen(String callingPackage, IPhoneStateListener callback, int events, - boolean notifyNow) { - listenWithFeature(callingPackage, null, callback, events, notifyNow); - } - - @Override - public void listenWithFeature(String callingPackage, String callingFeatureId, - IPhoneStateListener callback, int events, boolean notifyNow) { - listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, callback, events, notifyNow); - } - - @Override - public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId, - IPhoneStateListener callback, int events, boolean notifyNow) { - listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId); + public void listenWithEventList(int subId, String callingPackage, String callingFeatureId, + IPhoneStateListener callback, int[] events, boolean notifyNow) { + Set<Integer> eventList = Arrays.stream(events).boxed().collect(Collectors.toSet()); + listen(callingPackage, callingFeatureId, callback, eventList, notifyNow, subId); } private void listen(String callingPackage, @Nullable String callingFeatureId, - IPhoneStateListener callback, int events, boolean notifyNow, int subId) { + IPhoneStateListener callback, Set<Integer> events, boolean notifyNow, int subId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid() - + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId=" - + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId; + + " events=" + events + " notifyNow=" + notifyNow + + " subId=" + subId + " myUserId=" + UserHandle.myUserId() + + " callerUserId=" + callerUserId; mListenLog.log(str); if (VDBG) { log(str); } - if (events != PhoneStateListener.LISTEN_NONE) { - // Checks permission and throws SecurityException for disallowed operations. For pre-M - // apps whose runtime permission has been revoked, we return immediately to skip sending - // events to the app without crashing it. - if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId, - "listen")) { - return; + if (events.isEmpty()) { + if (DBG) { + log("listen: Unregister"); } + events.clear(); + remove(callback.asBinder()); + return; + } - int phoneId = getPhoneIdFromSubId(subId); - synchronized (mRecords) { - // register - IBinder b = callback.asBinder(); - boolean doesLimitApply = - Binder.getCallingUid() != Process.SYSTEM_UID - && Binder.getCallingUid() != Process.PHONE_UID - && Binder.getCallingUid() != Process.myUid(); - Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply); + // Checks permission and throws SecurityException for disallowed operations. For pre-M + // apps whose runtime permission has been revoked, we return immediately to skip sending + // events to the app without crashing it. + if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId, + "listen")) { + return; + } - if (r == null) { - return; - } + int phoneId = getPhoneIdFromSubId(subId); + synchronized (mRecords) { + // register + IBinder b = callback.asBinder(); + boolean doesLimitApply = + Binder.getCallingUid() != Process.SYSTEM_UID + && Binder.getCallingUid() != Process.PHONE_UID + && Binder.getCallingUid() != Process.myUid(); + Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply); - r.context = mContext; - r.callback = callback; - r.callingPackage = callingPackage; - r.callingFeatureId = callingFeatureId; - r.callerUid = Binder.getCallingUid(); - r.callerPid = Binder.getCallingPid(); - // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, - // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - } else {//APP specify subID - r.subId = subId; - } - r.phoneId = phoneId; - r.events = events; - if (DBG) { - log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); - } - if (notifyNow && validatePhoneId(phoneId)) { - if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { - try { - if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); - ServiceState rawSs = new ServiceState(mServiceState[phoneId]); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onServiceStateChanged(rawSs); - } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onServiceStateChanged( - rawSs.createLocationInfoSanitizedCopy(false)); - } else { - r.callback.onServiceStateChanged( - rawSs.createLocationInfoSanitizedCopy(true)); - } - } catch (RemoteException ex) { - remove(r.binder); + if (r == null) { + return; + } + + r.context = mContext; + r.callback = callback; + r.callingPackage = callingPackage; + r.callingFeatureId = callingFeatureId; + r.callerUid = Binder.getCallingUid(); + r.callerPid = Binder.getCallingPid(); + // Legacy applications pass SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + // force all illegal subId to SubscriptionManager.DEFAULT_SUBSCRIPTION_ID + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + } else {//APP specify subID + r.subId = subId; + } + r.phoneId = phoneId; + r.eventList = events; + if (DBG) { + log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); + } + if (notifyNow && validatePhoneId(phoneId)) { + if (events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)) { + try { + if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); + ServiceState rawSs = new ServiceState(mServiceState[phoneId]); + if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged(rawSs); + } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(false)); + } else { + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(true)); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { - try { - if (mSignalStrength[phoneId] != null) { - int gsmSignalStrength = mSignalStrength[phoneId] - .getGsmSignalStrength(); - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) { + try { + if (mSignalStrength[phoneId] != null) { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { - try { - r.callback.onMessageWaitingIndicatorChanged( - mMessageWaiting[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains( + PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) { + try { + r.callback.onMessageWaitingIndicatorChanged( + mMessageWaiting[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { - try { - r.callback.onCallForwardingIndicatorChanged( - mCallForwarding[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains( + PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) { + try { + r.callback.onCallForwardingIndicatorChanged( + mCallForwarding[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { - try { - if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); - if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) - && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - // null will be translated to empty CellLocation object in client. - r.callback.onCellLocationChanged(mCellIdentity[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (validateEventAndUserLocked( + r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) { + try { + if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + // null will be translated to empty CellLocation object in client. + r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { - try { - r.callback.onCallStateChanged(mCallState[phoneId], - getCallIncomingNumber(r, phoneId)); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_CALL_STATE_CHANGED)) { + try { + r.callback.onCallStateChanged(mCallState[phoneId], + getCallIncomingNumber(r, phoneId)); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { - try { - r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], + } + if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) { + try { + r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], mDataConnectionNetworkType[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { - try { - r.callback.onDataActivity(mDataActivity[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)) { + try { + r.callback.onDataActivity(mDataActivity[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { - try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)) { + try { + if (mSignalStrength[phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) - != 0) { - updateReportSignalStrengthDecision(r.subId); - try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (events.contains( + PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { + updateReportSignalStrengthDecision(r.subId); + try { + if (mSignalStrength[phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); } + } catch (RemoteException ex) { + remove(r.binder); } - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { - try { - if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " - + mCellInfo.get(phoneId)); - if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) - && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (validateEventAndUserLocked( + r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) { + try { + if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " + + mCellInfo.get(phoneId)); + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) { - try { - r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)) { + try { + r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) { - try { - r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], - mCallPreciseDisconnectCause[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) { + try { + r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], + mCallPreciseDisconnectCause[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) { - try { - r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) { + try { + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) { - try { - for (PreciseDataConnectionState pdcs - : mPreciseDataConnectionStates.get(phoneId).values()) { - r.callback.onPreciseDataConnectionStateChanged(pdcs); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (events.contains( + PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) { + try { + for (PreciseDataConnectionState pdcs + : mPreciseDataConnectionStates.get(phoneId).values()) { + r.callback.onPreciseDataConnectionStateChanged(pdcs); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) { - try { - r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)) { + try { + r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) { - try { - r.callback.onVoiceActivationStateChanged( - mVoiceActivationState[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) { + try { + r.callback.onVoiceActivationStateChanged( + mVoiceActivationState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) { - try { - r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)) { + try { + r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) { - try { - r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) { + try { + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) { - try { - if (mTelephonyDisplayInfos[phoneId] != null) { - r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]); - } - } catch (RemoteException ex) { - remove(r.binder); + } + if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) { + try { + if (mTelephonyDisplayInfos[phoneId] != null) { + r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]); } + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) { - try { - r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) { + try { + r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) { - try { - r.callback.onPhoneCapabilityChanged(mPhoneCapability); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) { + try { + r.callback.onPhoneCapabilityChanged(mPhoneCapability); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener - .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) { - try { - r.callback.onActiveDataSubIdChanged(mActiveDataSubId); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains( + PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) { + try { + r.callback.onActiveDataSubIdChanged(mActiveDataSubId); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) { - try { - r.callback.onRadioPowerStateChanged(mRadioPowerState); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)) { + try { + r.callback.onRadioPowerStateChanged(mRadioPowerState); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) { - try { - r.callback.onSrvccStateChanged(mSrvccState[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)) { + try { + r.callback.onSrvccStateChanged(mSrvccState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) { - try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)) { + try { + r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); } - if ((events & PhoneStateListener.LISTEN_BARRING_INFO) != 0) { - BarringInfo barringInfo = mBarringInfo.get(phoneId); - BarringInfo biNoLocation = barringInfo != null - ? barringInfo.createLocationInfoSanitizedCopy() : null; - if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); - try { - r.callback.onBarringInfoChanged( - checkFineLocationAccess(r, Build.VERSION_CODES.BASE) - ? barringInfo : biNoLocation); - } catch (RemoteException ex) { - remove(r.binder); - } + } + if (events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED)) { + BarringInfo barringInfo = mBarringInfo.get(phoneId); + BarringInfo biNoLocation = barringInfo != null + ? barringInfo.createLocationInfoSanitizedCopy() : null; + if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); + try { + r.callback.onBarringInfoChanged( + checkFineLocationAccess(r, Build.VERSION_CODES.BASE) + ? barringInfo : biNoLocation); + } catch (RemoteException ex) { + remove(r.binder); + } + } + if (events.contains( + PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) { + try { + r.callback.onPhysicalChannelConfigChanged( + mPhysicalChannelConfigs); + } catch (RemoteException ex) { + remove(r.binder); + } + } + if (events.contains( + PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) { + try { + r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason); + } catch (RemoteException ex) { + remove(r.binder); } } } - } else { - if(DBG) log("listen: Unregister"); - remove(callback.asBinder()); } } @@ -1114,7 +1166,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // If any of the system clients wants to always listen to signal strength, // we need to set it on. if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) { + PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { telephonyManager.createForSubscriptionId(subscriptionId) .setAlwaysReportSignalStrength(true); return; @@ -1215,7 +1267,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // strength is removed from registry records, we need to check if // the signal strength decision needs to update on its slot. if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) { + PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { updateReportSignalStrengthDecision(r.subId); } return; @@ -1235,8 +1287,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { for (Record r : mRecords) { - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) && - (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { + if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED) + && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { try { // Ensure the listener has read call log permission; if they do not return // an empty phone number. @@ -1270,9 +1322,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallState[phoneId] = state; mCallIncomingNumber[phoneId] = incomingNumber; for (Record r : mRecords) { - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) && - (r.subId == subId) && - (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { + if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED) + && (r.subId == subId) + && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) { try { String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId); r.callback.onCallStateChanged(state, incomingNumberOrEmpty); @@ -1312,8 +1364,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId + " phoneId=" + phoneId + " state=" + state); } - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) && - idMatch(r.subId, subId, phoneId)) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_SERVICE_STATE_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { ServiceState stateToSend; @@ -1374,7 +1427,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if ((activationType == SIM_ACTIVATION_TYPE_VOICE) && r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) + PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { if (DBG) { log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r @@ -1385,7 +1438,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((activationType == SIM_ACTIVATION_TYPE_DATA) && r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) + PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { if (DBG) { log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r @@ -1424,9 +1477,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId + " phoneId=" + phoneId + " ss=" + signalStrength); } - if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) + if ((r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED) || r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) + PhoneStateListener. + EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) && idMatch(r.subId, subId, phoneId)) { try { if (DBG) { @@ -1439,8 +1494,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mRemoveList.add(r.binder); } } - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) && - idMatch(r.subId, subId, phoneId)) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); @@ -1486,8 +1542,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) && - idMatch(r.subId, subId, phoneId)) { + PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { r.callback.onCarrierNetworkChange(active); } catch (RemoteException ex) { @@ -1517,9 +1573,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validatePhoneId(phoneId)) { mCellInfo.set(phoneId, cellInfo); for (Record r : mRecords) { - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && - idMatch(r.subId, subId, phoneId) && - (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + if (validateEventAndUserLocked( + r, PhoneStateListener.EVENT_CELL_INFO_CHANGED) + && idMatch(r.subId, subId, phoneId) + && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { @@ -1551,8 +1608,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mMessageWaiting[phoneId] = mwi; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) && - idMatch(r.subId, subId, phoneId)) { + PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -1578,8 +1635,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mUserMobileDataState[phoneId] = state; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) && - idMatch(r.subId, subId, phoneId)) { + PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { r.callback.onUserMobileDataStateChanged(state); } catch (RemoteException ex) { @@ -1617,7 +1674,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mTelephonyDisplayInfos[phoneId] = telephonyDisplayInfo; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) + PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED) && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) { try { r.callback.onDisplayInfoChanged(telephonyDisplayInfo); @@ -1649,8 +1706,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallForwarding[phoneId] = cfi; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) && - idMatch(r.subId, subId, phoneId)) { + PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -1677,8 +1734,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataActivity[phoneId] = state; for (Record r : mRecords) { // Notify by correct subId. - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY) && - idMatch(r.subId, subId, phoneId)) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { r.callback.onDataActivity(state); } catch (RemoteException ex) { @@ -1725,7 +1783,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mLocalLog.log(str); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) + PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { if (DBG) { @@ -1747,12 +1805,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { preciseState.getApnSetting()); PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId) .remove(key); - log("Jack: oldState=" + oldState); - log("Jack: newState=" + preciseState); if (!Objects.equals(oldState, preciseState)) { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) + PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onPreciseDataConnectionStateChanged(preciseState); @@ -1797,9 +1853,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) { mCellIdentity[phoneId] = cellIdentity; for (Record r : mRecords) { - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && - idMatch(r.subId, subId, phoneId) && - (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + if (validateEventAndUserLocked( + r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED) + && idMatch(r.subId, subId, phoneId) + && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { @@ -1850,7 +1907,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } for (Record r : mRecords) { - if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE) + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); @@ -1859,7 +1917,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } if (notifyCallAttributes && r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) + PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); @@ -1908,7 +1966,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mImsReasonInfo.set(phoneId, imsReasonInfo); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) + PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { @@ -1940,8 +1998,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mSrvccState[phoneId] = state; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) && - idMatch(r.subId, subId, phoneId)) { + PhoneStateListener.EVENT_SRVCC_STATE_CHANGED) + && idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r); @@ -1969,7 +2027,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyOemHookRawEventForSubscriber: r=" + r + " subId=" + subId); } if ((r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) + PhoneStateListener.EVENT_OEM_HOOK_RAW)) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onOemHookRawEvent(rawData); @@ -1997,7 +2055,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE)) { + PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) { try { r.callback.onPhoneCapabilityChanged(capability); } catch (RemoteException ex) { @@ -2022,7 +2080,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)) { + PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) { try { r.callback.onActiveDataSubIdChanged(activeDataSubId); } catch (RemoteException ex) { @@ -2049,7 +2107,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) + PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onRadioPowerStateChanged(state); @@ -2078,7 +2136,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) + PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); @@ -2110,7 +2168,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { // Send to all listeners regardless of subscription if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) { + PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)) { try { r.callback.onOutgoingEmergencyCall(emergencyNumber, subId); } catch (RemoteException ex) { @@ -2134,7 +2192,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { // Send to all listeners regardless of subscription if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS)) { + PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS)) { try { r.callback.onOutgoingEmergencySms(emergencyNumber, subId); } catch (RemoteException ex) { @@ -2164,7 +2222,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) + PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); @@ -2195,7 +2253,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validatePhoneId(phoneId)) { for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_REGISTRATION_FAILURE) + PhoneStateListener.EVENT_REGISTRATION_FAILURE) && idMatch(r.subId, subId, phoneId)) { try { r.callback.onRegistrationFailed( @@ -2238,7 +2296,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( - PhoneStateListener.LISTEN_BARRING_INFO) + PhoneStateListener.EVENT_BARRING_INFO_CHANGED) && idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { @@ -2258,6 +2316,81 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + /** + * Send a notification to registrants that the configs of physical channel has changed for + * a particular subscription. + * + * @param subId the subId + * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel. + */ + public void notifyPhysicalChannelConfigForSubscriber( + int subId, List<PhysicalChannelConfig> configs) { + if (!checkNotifyPermission("notifyPhysicalChannelConfig()")) { + return; + } + + if (VDBG) { + log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs); + } + + synchronized (mRecords) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId)); + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED) + && idMatch(r.subId, subId, phoneId)) { + try { + if (DBG_LOC) { + log("notifyPhysicalChannelConfig: " + + "mPhysicalChannelConfigs=" + + configs + " r=" + r); + } + r.callback.onPhysicalChannelConfigChanged(configs); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + /** + * Notify that the data enabled has changed. + * + * @param enabled True if data is enabled, otherwise disabled. + * @param reason Reason for data enabled/disabled. See {@code DATA_*} in + * {@link TelephonyManager}. + */ + public void notifyDataEnabled(boolean enabled, + @TelephonyManager.DataEnabledReason int reason) { + if (!checkNotifyPermission("notifyDataEnabled()")) { + return; + } + + if (VDBG) { + log("notifyDataEnabled: enabled=" + enabled + " reason=" + reason); + } + + mIsDataEnabled = enabled; + mDataEnabledReason = reason; + synchronized (mRecords) { + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) { + try { + r.callback.onDataEnabledChanged(enabled, reason); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + handleRemoveListLocked(); + } + } @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { @@ -2310,6 +2443,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mEmergencyNumberList=" + mEmergencyNumberList); pw.println("mDefaultPhoneId=" + mDefaultPhoneId); pw.println("mDefaultSubId=" + mDefaultSubId); + pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs); + pw.println("mIsDataEnabled=" + mIsDataEnabled); + pw.println("mDataEnabledReason=" + mDataEnabledReason); pw.decreaseIndent(); @@ -2538,22 +2674,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { == PackageManager.PERMISSION_GRANTED; } - private boolean checkListenerPermission(int events, int subId, String callingPackage, + private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage, @Nullable String callingFeatureId, String message) { LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder = new LocationAccessPolicy.LocationPermissionQuery.Builder() - .setCallingPackage(callingPackage) - .setMethod(message + " events: " + events) - .setCallingPid(Binder.getCallingPid()) - .setCallingUid(Binder.getCallingUid()); + .setCallingPackage(callingPackage) + .setMethod(message + " events: " + events) + .setCallingPid(Binder.getCallingPid()) + .setCallingUid(Binder.getCallingUid()); + + boolean shouldCheckLocationPermissions = false; - if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) { + if (isLocationPermissionRequired(events)) { // Everything that requires fine location started in Q. So far... locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q); // If we're enforcing fine starting in Q, we also want to enforce coarse even for // older SDK versions. locationQueryBuilder.setMinSdkVersionForCoarse(0); + shouldCheckLocationPermissions = true; + } + + boolean isPermissionCheckSuccessful = true; + if (shouldCheckLocationPermissions) { LocationAccessPolicy.LocationPermissionResult result = LocationAccessPolicy.checkLocationPermission( mContext, locationQueryBuilder.build()); @@ -2562,18 +2705,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { throw new SecurityException("Unable to listen for events " + events + " due to " + "insufficient location permissions."); case DENIED_SOFT: - return false; + isPermissionCheckSuccessful = false; } } - if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { + if (isPhoneStatePermissionRequired(events)) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, subId, callingPackage, callingFeatureId, message)) { - return false; + isPermissionCheckSuccessful = false; } } - if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { + if (isPrecisePhoneStatePermissionRequired(events)) { // check if calling app has either permission READ_PRECISE_PHONE_STATE // or with carrier privileges try { @@ -2584,47 +2727,46 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) { + if (isActiveEmergencySessionPermissionRequired(events)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null); } - if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) { + if ((events.contains(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null); } - if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) { + if (isPrivilegedPhoneStatePermissionRequired(events)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); } - - return true; + return isPermissionCheckSuccessful; } private void handleRemoveListLocked() { int size = mRemoveList.size(); if (VDBG) log("handleRemoveListLocked: mRemoveList.size()=" + size); if (size > 0) { - for (IBinder b: mRemoveList) { + for (IBinder b : mRemoveList) { remove(b); } mRemoveList.clear(); } } - private boolean validateEventsAndUserLocked(Record r, int events) { + private boolean validateEventAndUserLocked(Record r, int event) { int foregroundUser; long callingIdentity = Binder.clearCallingIdentity(); boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); valid = UserHandle.getUserId(r.callerUid) == foregroundUser - && r.matchPhoneStateListenerEvent(events); + && r.matchPhoneStateListenerEvent(event); if (DBG | DBG_LOC) { - log("validateEventsAndUserLocked: valid=" + valid + log("validateEventAndUserLocked: valid=" + valid + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser - + " r.events=" + r.events + " events=" + events); + + " r.eventList=" + r.eventList + " event=" + event); } } finally { Binder.restoreCallingIdentity(callingIdentity); @@ -2677,6 +2819,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + /** + * Note -- this method should only be used at the site of a permission check if you need to + * explicitly allow apps below a certain SDK level access regardless of location permissions. + * If you don't need app compat logic, use {@link #checkFineLocationAccess(Record)}. + */ private boolean checkFineLocationAccess(Record r, int minSdk) { LocationAccessPolicy.LocationPermissionQuery query = new LocationAccessPolicy.LocationPermissionQuery.Builder() @@ -2695,6 +2842,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { }); } + /** + * Note -- this method should only be used at the site of a permission check if you need to + * explicitly allow apps below a certain SDK level access regardless of location permissions. + * If you don't need app compat logic, use {@link #checkCoarseLocationAccess(Record)}. + */ private boolean checkCoarseLocationAccess(Record r, int minSdk) { LocationAccessPolicy.LocationPermissionQuery query = new LocationAccessPolicy.LocationPermissionQuery.Builder() @@ -2714,9 +2866,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } private void checkPossibleMissNotify(Record r, int phoneId) { - int events = r.events; + Set<Integer> events = r.eventList; + + if (events == null || events.isEmpty()) { + log("checkPossibleMissNotify: events = null."); + return; + } - if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { + if ((events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED))) { try { if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" + mServiceState[phoneId]); @@ -2735,8 +2892,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0 - || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) { + if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED) + || events.contains( + PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { try { if (mSignalStrength[phoneId] != null) { SignalStrength signalStrength = mSignalStrength[phoneId]; @@ -2751,7 +2909,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { + if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) { try { if (mSignalStrength[phoneId] != null) { int gsmSignalStrength = mSignalStrength[phoneId] @@ -2768,7 +2926,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { + if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) { try { if (DBG_LOC) { log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " @@ -2783,7 +2941,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) { + if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) { try { if (VDBG) { log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId=" @@ -2795,7 +2953,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) { + if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) { try { if (VDBG) { log("checkPossibleMissNotify: onDisplayInfoChanged phoneId=" @@ -2809,7 +2967,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { + if (events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) { try { if (VDBG) { log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId=" @@ -2822,7 +2980,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { + if (events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) { try { if (VDBG) { log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId=" @@ -2835,7 +2993,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { + if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) { try { if (DBG_LOC) { log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = " @@ -2851,7 +3009,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { + if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) { try { if (DBG) { log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState" diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 1024556c17eb..26244e62696b 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -368,6 +368,7 @@ final public class IpConnectivityMetrics extends SystemService { @Override public void logDefaultNetworkValidity(boolean valid) { + NetworkStack.checkNetworkStackPermission(getContext()); mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid); } @@ -375,6 +376,7 @@ final public class IpConnectivityMetrics extends SystemService { public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated, LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork, int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) { + NetworkStack.checkNetworkStackPermission(getContext()); final long timeMs = SystemClock.elapsedRealtime(); mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, defaultNetwork, score, validated, lp, nc, previousDefaultNetwork, previousScore, previousLp, previousNc); diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index c1b1b6a2f26c..952193b77681 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -246,11 +246,6 @@ public class Nat464Xlat extends BaseNetworkObserver { return; } - if (mNetwork.linkProperties == null) { - Log.e(TAG, "startClat: Can't start clat with null LinkProperties"); - return; - } - String baseIface = mNetwork.linkProperties.getInterfaceName(); if (baseIface == null) { Log.e(TAG, "startClat: Can't start clat on null interface"); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index b0a73f105725..ba6cbcd3c796 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -136,12 +136,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // This Network object should always be used if possible, so as to encourage reuse of the // enclosed socket factory and connection pool. Avoid creating other Network objects. // This Network object is always valid. - public final Network network; - public LinkProperties linkProperties; + @NonNull public final Network network; + @NonNull public LinkProperties linkProperties; // This should only be modified by ConnectivityService, via setNetworkCapabilities(). // TODO: make this private with a getter. - public NetworkCapabilities networkCapabilities; - public final NetworkAgentConfig networkAgentConfig; + @NonNull public NetworkCapabilities networkCapabilities; + @NonNull public final NetworkAgentConfig networkAgentConfig; // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true. // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are @@ -329,6 +329,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, int creatorUid) { + Objects.requireNonNull(net); + Objects.requireNonNull(info); + Objects.requireNonNull(lp); + Objects.requireNonNull(nc); + Objects.requireNonNull(context); + Objects.requireNonNull(config); networkAgent = na; network = net; networkInfo = info; @@ -536,19 +542,22 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } @Override - public void sendNetworkCapabilities(NetworkCapabilities nc) { + public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) { + Objects.requireNonNull(nc); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget(); } @Override - public void sendLinkProperties(LinkProperties lp) { + public void sendLinkProperties(@NonNull LinkProperties lp) { + Objects.requireNonNull(lp); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget(); } @Override - public void sendNetworkInfo(NetworkInfo info) { + public void sendNetworkInfo(@NonNull NetworkInfo info) { + Objects.requireNonNull(info); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED, new Pair<>(NetworkAgentInfo.this, info)).sendToTarget(); } @@ -603,7 +612,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { * * @return the old capabilities of this network. */ - public synchronized NetworkCapabilities getAndSetNetworkCapabilities( + @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities( @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java index aadaf4d9584f..5dc8c1a00eaf 100644 --- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java +++ b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java @@ -16,6 +16,7 @@ package com.android.server.connectivity; +import android.annotation.NonNull; import android.annotation.WorkerThread; import android.app.AlarmManager; import android.app.PendingIntent; @@ -71,10 +72,6 @@ public class PacProxyInstaller { private static final int DELAY_LONG = 4; private static final long MAX_PAC_SIZE = 20 * 1000 * 1000; - // Return values for #setCurrentProxyScriptUrl - public static final boolean DONT_SEND_BROADCAST = false; - public static final boolean DO_SEND_BROADCAST = true; - private String mCurrentPac; @GuardedBy("mProxyLock") private volatile Uri mPacUrl = Uri.EMPTY; @@ -93,7 +90,7 @@ public class PacProxyInstaller { private volatile boolean mHasSentBroadcast; private volatile boolean mHasDownloaded; - private Handler mConnectivityHandler; + private final Handler mConnectivityHandler; private final int mProxyMessage; /** @@ -102,6 +99,13 @@ public class PacProxyInstaller { private final Object mProxyLock = new Object(); /** + * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the + * last URL and port, and the broadcast message being sent with the correct arguments. + * TODO : this should probably protect all instances of these variables + */ + private final Object mBroadcastStateLock = new Object(); + + /** * Runnable to download PAC script. * The behavior relies on the assumption it always runs on mNetThread to guarantee that the * latest data fetched from mPacUrl is stored in mProxyService. @@ -146,7 +150,7 @@ public class PacProxyInstaller { } } - public PacProxyInstaller(Context context, Handler handler, int proxyMessage) { + public PacProxyInstaller(@NonNull Context context, @NonNull Handler handler, int proxyMessage) { mContext = context; mLastPort = -1; final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller", @@ -176,31 +180,27 @@ public class PacProxyInstaller { * PacProxyInstaller will trigger a new broadcast when it is ready. * * @param proxy Proxy information that is about to be broadcast. - * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST */ - public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { - if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { - if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) { - // Allow to send broadcast, nothing to do. - return DO_SEND_BROADCAST; - } - mPacUrl = proxy.getPacFileUrl(); - mCurrentDelay = DELAY_1; - mHasSentBroadcast = false; - mHasDownloaded = false; - getAlarmManager().cancel(mPacRefreshIntent); - bind(); - return DONT_SEND_BROADCAST; - } else { - getAlarmManager().cancel(mPacRefreshIntent); - synchronized (mProxyLock) { - mPacUrl = Uri.EMPTY; - mCurrentPac = null; - if (mProxyService != null) { - unbind(); + public void setCurrentProxyScriptUrl(@NonNull ProxyInfo proxy) { + synchronized (mBroadcastStateLock) { + if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { + if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return; + mPacUrl = proxy.getPacFileUrl(); + mCurrentDelay = DELAY_1; + mHasSentBroadcast = false; + mHasDownloaded = false; + getAlarmManager().cancel(mPacRefreshIntent); + bind(); + } else { + getAlarmManager().cancel(mPacRefreshIntent); + synchronized (mProxyLock) { + mPacUrl = Uri.EMPTY; + mCurrentPac = null; + if (mProxyService != null) { + unbind(); + } } } - return DO_SEND_BROADCAST; } } @@ -275,6 +275,7 @@ public class PacProxyInstaller { getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent); } + @GuardedBy("mProxyLock") private void setCurrentProxyScript(String script) { if (mProxyService == null) { Log.e(TAG, "setCurrentProxyScript: no proxy service"); @@ -347,6 +348,9 @@ public class PacProxyInstaller { public void setProxyPort(int port) { if (mLastPort != -1) { // Always need to send if port changed + // TODO: Here lacks synchronization because this write cannot + // guarantee that it's visible from sendProxyIfNeeded() when + // it's called by a Runnable which is post by mNetThread. mHasSentBroadcast = false; } mLastPort = port; @@ -386,13 +390,15 @@ public class PacProxyInstaller { mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy)); } - private synchronized void sendProxyIfNeeded() { - if (!mHasDownloaded || (mLastPort == -1)) { - return; - } - if (!mHasSentBroadcast) { - sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort)); - mHasSentBroadcast = true; + private void sendProxyIfNeeded() { + synchronized (mBroadcastStateLock) { + if (!mHasDownloaded || (mLastPort == -1)) { + return; + } + if (!mHasSentBroadcast) { + sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort)); + mHasSentBroadcast = true; + } } } } diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index d83ff837d9be..b618d2b99a63 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -226,9 +226,9 @@ public class ProxyTracker { final ProxyInfo defaultProxy = getDefaultProxy(); final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList()); + mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo); - if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo) - == PacProxyInstaller.DONT_SEND_BROADCAST) { + if (!shouldSendBroadcast(proxyInfo)) { return; } if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo); @@ -244,6 +244,13 @@ public class ProxyTracker { } } + private boolean shouldSendBroadcast(ProxyInfo proxy) { + if (Uri.EMPTY.equals(proxy.getPacFileUrl())) return false; + if (proxy.getPacFileUrl().equals(proxy.getPacFileUrl()) + && (proxy.getPort() > 0)) return true; + return true; + } + /** * Sets the global proxy in memory. Also writes the values to the global settings of the device. * diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index a65f8097121d..fb1e8197ccff 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -439,6 +439,11 @@ public class Vpn { mEnableTeardown = enableTeardown; } + @VisibleForTesting + public boolean getEnableTeardown() { + return mEnableTeardown; + } + /** * Update current state, dispatching event to listeners. */ @@ -2146,6 +2151,11 @@ public class Vpn { // Start a new LegacyVpnRunner and we are done! mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile); + startLegacyVpnRunner(); + } + + @VisibleForTesting + protected void startLegacyVpnRunner() { mVpnRunner.start(); } diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 289290bab4dc..fbec91576ca1 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -224,6 +224,10 @@ class RebootEscrowManager { for (UserInfo user : rebootEscrowUsers) { allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk); } + + // Clear the old key in keystore. A new key will be generated by new RoR requests. + mKeyStoreManager.clearKeyStoreEncryptionKey(); + onEscrowRestoreComplete(allUsersUnlocked); } @@ -273,9 +277,6 @@ class RebootEscrowManager { } catch (IOException e) { Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e); return false; - } finally { - // Clear the old key in keystore. A new key will be generated by new RoR requests. - mKeyStoreManager.clearKeyStoreEncryptionKey(); } } diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index f882c57e49ba..edc9d7c64146 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -77,7 +77,7 @@ abstract class MediaRoute2Provider { @NonNull public List<RoutingSessionInfo> getSessionInfos() { synchronized (mLock) { - return mSessionInfos; + return new ArrayList<>(mSessionInfos); } } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 85af346aa88a..ab38dca2387d 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -108,8 +108,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider mLastDiscoveryPreference = discoveryPreference; if (mConnectionReady) { mActiveConnection.updateDiscoveryPreference(discoveryPreference); - updateBinding(); } + updateBinding(); } @Override @@ -205,9 +205,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } private boolean shouldBind() { - //TODO: Binding could be delayed until it's necessary. if (mRunning) { - return true; + // Bind when there is a discovery preference or an active route session. + return (mLastDiscoveryPreference != null + && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty()) + || !getSessionInfos().isEmpty(); } return false; } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 1114fe0d9bf8..31edf43679e9 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.media; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; @@ -73,10 +74,12 @@ class MediaRouter2ServiceImpl { // TODO: (In Android S or later) if we add callback methods for generic failures // in MediaRouter2, remove this constant and replace the usages with the real request IDs. private static final long DUMMY_REQUEST_ID = -1; + private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND; private final Context mContext; private final Object mLock = new Object(); final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1); + final ActivityManager mActivityManager; @GuardedBy("mLock") private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); @@ -87,8 +90,21 @@ class MediaRouter2ServiceImpl { @GuardedBy("mLock") private int mCurrentUserId = -1; + private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener = + (uid, importance) -> { + synchronized (mLock) { + final int count = mUserRecords.size(); + for (int i = 0; i < count; i++) { + mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid); + } + } + }; + MediaRouter2ServiceImpl(Context context) { mContext = context; + mActivityManager = mContext.getSystemService(ActivityManager.class); + mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener, + PACKAGE_IMPORTANCE_FOR_DISCOVERY); } //////////////////////////////////////////////////////////////// @@ -388,6 +404,30 @@ class MediaRouter2ServiceImpl { } } + public void startScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + startScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void stopScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + stopScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { Objects.requireNonNull(manager, "manager must not be null"); @@ -839,6 +879,24 @@ class MediaRouter2ServiceImpl { disposeUserIfNeededLocked(userRecord); // since manager removed from user } + private void startScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.startScan(); + } + + private void stopScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.stopScan(); + } + private void setRouteVolumeWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, @NonNull MediaRoute2Info route, int volume) { @@ -1122,6 +1180,7 @@ class MediaRouter2ServiceImpl { public final String mPackageName; public final int mManagerId; public SessionCreationRequest mLastSessionCreationRequest; + public boolean mIsScanning; ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager, int uid, int pid, String packageName) { @@ -1146,6 +1205,24 @@ class MediaRouter2ServiceImpl { pw.println(prefix + this); } + public void startScan() { + if (mIsScanning) { + return; + } + mIsScanning = true; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + + public void stopScan() { + if (!mIsScanning) { + return; + } + mIsScanning = false; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + @Override public String toString() { return "Manager " + mPackageName + " (pid " + mPid + ")"; @@ -1262,6 +1339,24 @@ class MediaRouter2ServiceImpl { return null; } + public void maybeUpdateDiscoveryPreferenceForUid(int uid) { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return; + } + boolean isUidRelevant; + synchronized (service.mLock) { + isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch( + router -> router.mUid == uid) + | mUserRecord.mManagerRecords.stream().anyMatch( + manager -> manager.mUid == uid); + } + if (isUidRelevant) { + sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, this)); + } + } + private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) { int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId()); MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo(); @@ -1767,6 +1862,16 @@ class MediaRouter2ServiceImpl { return managers; } + private List<RouterRecord> getRouterRecords() { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return Collections.emptyList(); + } + synchronized (service.mLock) { + return new ArrayList<>(mUserRecord.mRouterRecords); + } + } + private List<ManagerRecord> getManagerRecords() { MediaRouter2ServiceImpl service = mServiceRef.get(); if (service == null) { @@ -2001,13 +2106,28 @@ class MediaRouter2ServiceImpl { return; } List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>(); - synchronized (service.mLock) { - for (RouterRecord routerRecord : mUserRecord.mRouterRecords) { + List<RouterRecord> routerRecords = getRouterRecords(); + List<ManagerRecord> managerRecords = getManagerRecords(); + boolean isAnyManagerScanning = + managerRecords.stream().anyMatch(manager -> manager.mIsScanning + && service.mActivityManager.getPackageImportance(manager.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY); + + for (RouterRecord routerRecord : routerRecords) { + if (isAnyManagerScanning + || service.mActivityManager.getPackageImportance(routerRecord.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) { discoveryPreferences.add(routerRecord.mDiscoveryPreference); } - mUserRecord.mCompositeDiscoveryPreference = - new RouteDiscoveryPreference.Builder(discoveryPreferences) - .build(); + } + + synchronized (service.mLock) { + RouteDiscoveryPreference newPreference = + new RouteDiscoveryPreference.Builder(discoveryPreferences).build(); + if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) { + return; + } + mUserRecord.mCompositeDiscoveryPreference = newPreference; } for (MediaRoute2Provider provider : mRouteProviders) { provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference); diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 0e52a67c8d39..b6d6cc48d0cd 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -544,6 +544,18 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void startScan(IMediaRouter2Manager manager) { + mService2.startScan(manager); + } + + // Binder call + @Override + public void stopScan(IMediaRouter2Manager manager) { + mService2.stopScan(manager); + } + + // Binder call + @Override public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { mService2.setRouteVolumeWithManager(manager, requestId, route, volume); diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index ea1d8da74185..ea2788c0c3d8 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -34,7 +34,6 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Handler; -import android.security.Credentials; import android.security.KeyStore; import android.text.TextUtils; import android.util.Log; @@ -70,6 +69,7 @@ public class LockdownVpnTracker { @NonNull private final Handler mHandler; @NonNull private final Vpn mVpn; @NonNull private final VpnProfile mProfile; + @NonNull private final KeyStore mKeyStore; @NonNull private final Object mStateLock = new Object(); @@ -81,13 +81,10 @@ public class LockdownVpnTracker { private int mErrorCount; - public static boolean isEnabled() { - return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN); - } - public LockdownVpnTracker(@NonNull Context context, @NonNull ConnectivityService connService, @NonNull Handler handler, + @NonNull KeyStore keyStore, @NonNull Vpn vpn, @NonNull VpnProfile profile) { mContext = Objects.requireNonNull(context); @@ -95,6 +92,7 @@ public class LockdownVpnTracker { mHandler = Objects.requireNonNull(handler); mVpn = Objects.requireNonNull(vpn); mProfile = Objects.requireNonNull(profile); + mKeyStore = Objects.requireNonNull(keyStore); mNotificationManager = mContext.getSystemService(NotificationManager.class); final Intent configIntent = new Intent(ACTION_VPN_SETTINGS); @@ -157,7 +155,7 @@ public class LockdownVpnTracker { try { // Use the privileged method because Lockdown VPN is initiated by the system, so // no additional permission checks are necessary. - mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp); + mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp); } catch (IllegalStateException e) { mAcceptedEgressIface = null; Log.e(TAG, "Failed to start VPN", e); diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java index dd507a3b1f81..ef0f0eeb56f8 100644 --- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java +++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java @@ -21,6 +21,7 @@ import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.BugreportParams; @@ -31,6 +32,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserManager; +import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.Slog; @@ -53,11 +55,13 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { private final Object mLock = new Object(); private final Context mContext; private final AppOpsManager mAppOps; + private final TelephonyManager mTelephonyManager; private final ArraySet<String> mBugreportWhitelistedPackages; BugreportManagerServiceImpl(Context context) { mContext = context; - mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mAppOps = context.getSystemService(AppOpsManager.class); + mTelephonyManager = context.getSystemService(TelephonyManager.class); mBugreportWhitelistedPackages = SystemConfig.getInstance().getBugreportWhitelistedPackages(); } @@ -67,11 +71,14 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { public void startBugreport(int callingUidUnused, String callingPackage, FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport"); Objects.requireNonNull(callingPackage); Objects.requireNonNull(bugreportFd); Objects.requireNonNull(listener); validateBugreportMode(bugreportMode); + + int callingUid = Binder.getCallingUid(); + enforcePermission(callingPackage, callingUid, bugreportMode + == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */); final long identity = Binder.clearCallingIdentity(); try { ensureIsPrimaryUser(); @@ -79,13 +86,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { Binder.restoreCallingIdentity(identity); } - int callingUid = Binder.getCallingUid(); - mAppOps.checkPackage(callingUid, callingPackage); - - if (!mBugreportWhitelistedPackages.contains(callingPackage)) { - throw new SecurityException( - callingPackage + " is not whitelisted to use Bugreport API"); - } synchronized (mLock) { startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode, listener, isScreenshotRequested); @@ -93,10 +93,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } @Override - @RequiresPermission(android.Manifest.permission.DUMP) - public void cancelBugreport() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, - "cancelBugreport"); + @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges + public void cancelBugreport(int callingUidUnused, String callingPackage) { + int callingUid = Binder.getCallingUid(); + enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */); + synchronized (mLock) { IDumpstate ds = getDumpstateBinderServiceLocked(); if (ds == null) { @@ -104,7 +105,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { return; } try { - ds.cancelBugreport(); + // Note: this may throw SecurityException back out to the caller if they aren't + // allowed to cancel the report, in which case we should NOT be setting ctl.stop, + // since that would unintentionally kill some other app's bugreport, which we + // specifically disallow. + ds.cancelBugreport(callingUid, callingPackage); } catch (RemoteException e) { Slog.e(TAG, "RemoteException in cancelBugreport", e); } @@ -127,6 +132,34 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } } + private void enforcePermission( + String callingPackage, int callingUid, boolean checkCarrierPrivileges) { + mAppOps.checkPackage(callingUid, callingPackage); + + // To gain access through the DUMP permission, the OEM has to allow this package explicitly + // via sysconfig and privileged permissions. + if (mBugreportWhitelistedPackages.contains(callingPackage) + && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + == PackageManager.PERMISSION_GRANTED) { + return; + } + // For carrier privileges, this can include user-installed apps. This is essentially a + // function of the current active SIM(s) in the device to let carrier apps through. + if (checkCarrierPrivileges + && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return; + } + + String message = + callingPackage + + " does not hold the DUMP permission or is not bugreport-whitelisted " + + (checkCarrierPrivileges ? "and does not have carrier privileges " : "") + + "to request a bugreport"; + Slog.w(TAG, message); + throw new SecurityException(message); + } + /** * Validates that the current user is the primary user. * @@ -182,7 +215,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { // lifecycle correctly. If we don't subsequent callers will get // BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS error. // Note that listener will be notified by the death recipient below. - cancelBugreport(); + cancelBugreport(callingUid, callingPackage); } } diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java index 0d059ae389e9..8345424712dd 100644 --- a/services/core/java/com/android/server/storage/StorageSessionController.java +++ b/services/core/java/com/android/server/storage/StorageSessionController.java @@ -361,7 +361,11 @@ public final class StorageSessionController { } } + private static boolean isSupportedVolume(VolumeInfo vol) { + return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB; + } + private boolean shouldHandle(@Nullable VolumeInfo vol) { - return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol)); + return mIsFuseEnabled && !mIsResetting && (vol == null || isSupportedVolume(vol)); } } diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java index 42f12eb23d39..07725038255e 100644 --- a/services/core/java/com/android/server/tv/TvInputHal.java +++ b/services/core/java/com/android/server/tv/TvInputHal.java @@ -51,7 +51,8 @@ final class TvInputHal implements Handler.Callback { public interface Callback { void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs); void onDeviceUnavailable(int deviceId); - void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs); + void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs, + int cableConnectionStatus); void onFirstFrameCaptured(int deviceId, int streamId); } @@ -142,8 +143,9 @@ final class TvInputHal implements Handler.Callback { mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget(); } - private void streamConfigsChangedFromNative(int deviceId) { - mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget(); + private void streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus) { + mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, + cableConnectionStatus).sendToTarget(); } private void firstFrameCapturedFromNative(int deviceId, int streamId) { @@ -184,6 +186,7 @@ final class TvInputHal implements Handler.Callback { case EVENT_STREAM_CONFIGURATION_CHANGED: { TvStreamConfig[] configs; int deviceId = msg.arg1; + int cableConnectionStatus = msg.arg2; synchronized (mLock) { if (DEBUG) { Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); @@ -191,7 +194,7 @@ final class TvInputHal implements Handler.Callback { retrieveStreamConfigsLocked(deviceId); configs = mStreamConfigs.get(deviceId); } - mCallback.onStreamConfigurationChanged(deviceId, configs); + mCallback.onStreamConfigurationChanged(deviceId, configs, cableConnectionStatus); break; } diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 2314afc787c3..3dfb99e5c0fc 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -156,6 +156,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { synchronized (mLock) { Connection connection = new Connection(info); connection.updateConfigsLocked(configs); + connection.updateCableConnectionStatusLocked(info.getCableConnectionStatus()); mConnections.put(info.getDeviceId(), connection); buildHardwareListLocked(); mHandler.obtainMessage( @@ -202,7 +203,8 @@ class TvInputHardwareManager implements TvInputHal.Callback { } @Override - public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) { + public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs, + int cableConnectionStatus) { synchronized (mLock) { Connection connection = mConnections.get(deviceId); if (connection == null) { @@ -211,12 +213,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { return; } int previousConfigsLength = connection.getConfigsLengthLocked(); + int previousCableConnectionStatus = connection.getInputStateLocked(); connection.updateConfigsLocked(configs); String inputId = mHardwareInputIdMap.get(deviceId); - if (inputId != null - && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) { - mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - connection.getInputStateLocked(), 0, inputId).sendToTarget(); + if (inputId != null) { + if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) { + if (previousCableConnectionStatus != connection.getInputStateLocked()) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + connection.getInputStateLocked(), 0, inputId).sendToTarget(); + } + } else { + if ((previousConfigsLength == 0) + != (connection.getConfigsLengthLocked() == 0)) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + connection.getInputStateLocked(), 0, inputId).sendToTarget(); + } + } } ITvInputHardwareCallback callback = connection.getCallbackLocked(); if (callback != null) { @@ -624,7 +636,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } private class Connection implements IBinder.DeathRecipient { - private final TvInputHardwareInfo mHardwareInfo; + private TvInputHardwareInfo mHardwareInfo; private TvInputInfo mInfo; private TvInputHardwareImpl mHardware = null; private ITvInputHardwareCallback mCallback; @@ -633,6 +645,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { private Integer mResolvedUserId = null; private Runnable mOnFirstFrameCaptured; private ResourceClientProfile mResourceClientProfile = null; + private boolean mIsCableConnectionStatusUpdated = false; public Connection(TvInputHardwareInfo hardwareInfo) { mHardwareInfo = hardwareInfo; @@ -735,6 +748,17 @@ class TvInputHardwareManager implements TvInputHal.Callback { + " }"; } + public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) { + // Update connection status only if it's not default value + if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN + || mIsCableConnectionStatusUpdated) { + mIsCableConnectionStatusUpdated = true; + mHardwareInfo = mHardwareInfo.toBuilder() + .cableConnectionStatus(cableConnectionStatus).build(); + } + return mIsCableConnectionStatusUpdated; + } + private int getConfigsLengthLocked() { return mConfigs == null ? 0 : mConfigs.length; } @@ -742,7 +766,9 @@ class TvInputHardwareManager implements TvInputHal.Callback { private int getInputStateLocked() { int configsLength = getConfigsLengthLocked(); if (configsLength > 0) { - return INPUT_STATE_CONNECTED; + if (!mIsCableConnectionStatusUpdated) { + return INPUT_STATE_CONNECTED; + } } switch (mHardwareInfo.getCableConnectionStatus()) { case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED: diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 6cd02581ee67..d858ae41cee8 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -20,6 +20,7 @@ import static android.media.AudioManager.DEVICE_NONE; import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED; import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -1728,6 +1729,46 @@ public final class TvInputManagerService extends SystemService { } @Override + public void pauseRecording(IBinder sessionToken, @NonNull Bundle params, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "pauseRecording"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .pauseRecording(params); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in pauseRecording", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void resumeRecording(IBinder sessionToken, @NonNull Bundle params, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "resumeRecording"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .resumeRecording(params); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in resumeRecording", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public List<TvInputHardwareInfo> getHardwareList() throws RemoteException { if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE) != PackageManager.PERMISSION_GRANTED) { diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index 4e1a23416330..a5311f33eb36 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -261,7 +261,7 @@ public: void onDeviceAvailable(const TvInputDeviceInfo& info); void onDeviceUnavailable(int deviceId); - void onStreamConfigurationsChanged(int deviceId); + void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus); void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded); private: @@ -519,7 +519,7 @@ void JTvInputHal::onDeviceUnavailable(int deviceId) { deviceId); } -void JTvInputHal::onStreamConfigurationsChanged(int deviceId) { +void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) { { Mutex::Autolock autoLock(&mLock); KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); @@ -529,10 +529,8 @@ void JTvInputHal::onStreamConfigurationsChanged(int deviceId) { connections.clear(); } JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod( - mThiz, - gTvInputHalClassInfo.streamConfigsChanged, - deviceId); + env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId, + cableConnectionStatus); } void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) { @@ -572,7 +570,8 @@ void JTvInputHal::NotifyHandler::handleMessage(const Message& message) { mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId); } break; case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: { - mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId); + int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus); + mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus); } break; default: ALOGE("Unrecognizable event"); @@ -688,9 +687,8 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) { "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V"); GET_METHOD_ID( gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V"); - GET_METHOD_ID( - gTvInputHalClassInfo.streamConfigsChanged, clazz, - "streamConfigsChangedFromNative", "(I)V"); + GET_METHOD_ID(gTvInputHalClassInfo.streamConfigsChanged, clazz, + "streamConfigsChangedFromNative", "(II)V"); GET_METHOD_ID( gTvInputHalClassInfo.firstFrameCaptured, clazz, "firstFrameCapturedFromNative", "(II)V"); diff --git a/services/searchui/OWNERS b/services/searchui/OWNERS new file mode 100644 index 000000000000..92835c2b0626 --- /dev/null +++ b/services/searchui/OWNERS @@ -0,0 +1,2 @@ +hyunyoungs@google.com +sfufa@google.com diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 724a9e477b95..e55720c6dc7e 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -109,6 +109,20 @@ import java.util.concurrent.ConcurrentHashMap; */ public abstract class Connection extends Conferenceable { + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "STATE_", value = { + STATE_INITIALIZING, + STATE_NEW, + STATE_RINGING, + STATE_DIALING, + STATE_ACTIVE, + STATE_HOLDING, + STATE_DISCONNECTED, + STATE_PULLING_CALL + }) + public @interface ConnectionState {} + /** * The connection is initializing. This is generally the first state for a {@code Connection} * returned by a {@link ConnectionService}. diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java index b785037e51c1..6571858fc4ae 100644 --- a/telephony/java/android/telephony/PhoneCapability.java +++ b/telephony/java/android/telephony/PhoneCapability.java @@ -28,8 +28,6 @@ import java.util.Objects; /** * Define capability of a modem group. That is, the capabilities * are shared between those modems defined by list of modem IDs. - * - * @hide */ public final class PhoneCapability implements Parcelable { // Hardcoded default DSDS capability. diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index af62ba4b93a1..327d6313c4dc 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -17,6 +17,8 @@ package android.telephony; import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -26,12 +28,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Objects; -/** - * @hide - */ public final class PhysicalChannelConfig implements Parcelable { // TODO(b/72993578) consolidate these enums in a central location. + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING, CONNECTION_UNKNOWN}) public @interface ConnectionStatus {} @@ -47,7 +47,13 @@ public final class PhysicalChannelConfig implements Parcelable { public static final int CONNECTION_SECONDARY_SERVING = 2; /** Connection status is unknown. */ - public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE; + public static final int CONNECTION_UNKNOWN = -1; + + /** Channel number is unknown. */ + public static final int CHANNEL_NUMBER_UNKNOWN = -1; + + /** Physical Cell Id is unknown. */ + public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; /** * Connection status of the cell. @@ -75,7 +81,7 @@ public final class PhysicalChannelConfig implements Parcelable { private int mFrequencyRange; /** - * The absolute radio frequency channel number, {@link Integer#MAX_VALUE} if unknown. + * The absolute radio frequency channel number, {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. */ private int mChannelNumber; @@ -86,7 +92,7 @@ public final class PhysicalChannelConfig implements Parcelable { private int[] mContextIds; /** - * The physical cell identifier for this cell - PCI, PSC, {@link Integer#MAX_VALUE} if known. + * The physical cell identifier for this cell - PCI, PSC, {@link #PHYSICAL_CELL_ID_UNKNOWN} */ private int mPhysicalCellId; @@ -96,7 +102,7 @@ public final class PhysicalChannelConfig implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mCellConnectionStatus); dest.writeInt(mCellBandwidthDownlinkKhz); dest.writeInt(mRat); @@ -120,6 +126,7 @@ public final class PhysicalChannelConfig implements Parcelable { * physical channel has no data call mapped to it. * * @return an integer list indicates the data call ids. + * @hide */ public int[] getContextIds() { return mContextIds; @@ -131,6 +138,7 @@ public final class PhysicalChannelConfig implements Parcelable { * @see {@link ServiceState#FREQUENCY_RANGE_MID} * @see {@link ServiceState#FREQUENCY_RANGE_HIGH} * @see {@link ServiceState#FREQUENCY_RANGE_MMWAVE} + * @hide */ @ServiceState.FrequencyRange public int getFrequencyRange() { @@ -139,7 +147,7 @@ public final class PhysicalChannelConfig implements Parcelable { /** * @return the absolute radio frequency channel number for this physical channel, - * {@link Integer#MAX_VALUE} if unknown. + * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. */ public int getChannelNumber() { return mChannelNumber; @@ -152,18 +160,20 @@ public final class PhysicalChannelConfig implements Parcelable { * In EUTRAN, this value is physical layer cell identity. The range is [0, 503]. * Reference: 3GPP TS 36.211 section 6.11. * - * In 5G RAN, this value is physical layer cell identity. The range is [0, 1008]. + * In 5G RAN, this value is physical layer cell identity. The range is [0, 1007]. * Reference: 3GPP TS 38.211 section 7.4.2.1. * - * @return the physical cell identifier for this cell, {@link Integer#MAX_VALUE} if unknown. + * @return the physical cell identifier for this cell, {@link #PHYSICAL_CELL_ID_UNKNOWN} + * if {@link android.telephony.CellInfo#UNAVAILABLE}. */ + @IntRange(from = 0, to = 1007) public int getPhysicalCellId() { return mPhysicalCellId; } /**The radio technology for this physical channel. */ @NetworkType - public int getRat() { + public int getNetworkType() { return mRat; } @@ -181,7 +191,10 @@ public final class PhysicalChannelConfig implements Parcelable { return mCellConnectionStatus; } - /** @return String representation of the connection status */ + /** + * @return String representation of the connection status + * @hide + */ private String getConnectionStatusString() { switch(mCellConnectionStatus) { case CONNECTION_PRIMARY_SERVING: @@ -274,7 +287,10 @@ public final class PhysicalChannelConfig implements Parcelable { mPhysicalCellId = builder.mPhysicalCellId; } - /** The builder of {@code PhysicalChannelConfig}. */ + /** + * The builder of {@code PhysicalChannelConfig}. + * @hide + */ public static final class Builder { private int mRat; private int mFrequencyRange; @@ -284,60 +300,51 @@ public final class PhysicalChannelConfig implements Parcelable { private int[] mContextIds; private int mPhysicalCellId; - /** @hide */ public Builder() { mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN; - mChannelNumber = Integer.MAX_VALUE; + mChannelNumber = CHANNEL_NUMBER_UNKNOWN; mCellBandwidthDownlinkKhz = 0; mCellConnectionStatus = CONNECTION_UNKNOWN; mContextIds = new int[0]; - mPhysicalCellId = Integer.MAX_VALUE; + mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN; } - /** @hide */ public PhysicalChannelConfig build() { return new PhysicalChannelConfig(this); } - /** @hide */ public Builder setRat(int rat) { this.mRat = rat; return this; } - /** @hide */ public Builder setFrequencyRange(int frequencyRange) { this.mFrequencyRange = frequencyRange; return this; } - /** @hide */ public Builder setChannelNumber(int channelNumber) { this.mChannelNumber = channelNumber; return this; } - /** @hide */ public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) { this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; return this; } - /** @hide */ public Builder setCellConnectionStatus(int connectionStatus) { this.mCellConnectionStatus = connectionStatus; return this; } - /** @hide */ public Builder setContextIds(int[] contextIds) { if (contextIds != null) Arrays.sort(contextIds); this.mContextIds = contextIds; return this; } - /** @hide */ public Builder setPhysicalCellId(int physicalCellId) { this.mPhysicalCellId = physicalCellId; return this; diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java new file mode 100644 index 000000000000..2a1640234144 --- /dev/null +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java @@ -0,0 +1,251 @@ +/* + * 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.telephony; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength + * breach the specified thresholds. + */ +public final class SignalStrengthUpdateRequest implements Parcelable { + /** + * List of SignalThresholdInfo for the request. + */ + private final List<SignalThresholdInfo> mSignalThresholdInfos; + + /** + * Whether the reporting is required for thresholds in the request while device is idle. + */ + private final boolean mIsReportingRequestedWhileIdle; + + /** + * Whether the reporting requested for system thresholds while device is idle. + * + * System signal thresholds are loaded from carrier config items and mainly used for UI + * displaying. By default, they are ignored when device is idle. When setting the value to true, + * modem will continue reporting signal strength changes over the system signal thresholds even + * device is idle. + * + * This should only set to true by the system caller. + */ + private final boolean mIsSystemThresholdReportingRequestedWhileIdle; + + private SignalStrengthUpdateRequest( + @NonNull List<SignalThresholdInfo> signalThresholdInfos, + boolean isReportingRequestedWhileIdle, + boolean isSystemThresholdReportingRequestedWhileIdle) { + validate(signalThresholdInfos); + + mSignalThresholdInfos = signalThresholdInfos; + mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; + mIsSystemThresholdReportingRequestedWhileIdle = + isSystemThresholdReportingRequestedWhileIdle; + } + + /** + * Builder class to create {@link SignalStrengthUpdateRequest} object. + */ + public static final class Builder { + private List<SignalThresholdInfo> mSignalThresholdInfos = null; + private boolean mIsReportingRequestedWhileIdle = false; + private boolean mIsSystemThresholdReportingRequestedWhileIdle = false; + + /** + * Set the collection of SignalThresholdInfo for the builder object + * + * @param signalThresholdInfos the collection of SignalThresholdInfo + * + * @return the builder to facilitate the chaining + */ + public @NonNull Builder setSignalThresholdInfos( + @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) { + Objects.requireNonNull(signalThresholdInfos, + "SignalThresholdInfo collection must not be null"); + for (SignalThresholdInfo info : signalThresholdInfos) { + Objects.requireNonNull(info, + "SignalThresholdInfo in the collection must not be null"); + } + + mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos); + // Sort the collection with RAN ascending order, make the ordering not matter for equals + mSignalThresholdInfos.sort( + Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType)); + return this; + } + + /** + * Set the builder object if require reporting on thresholds in this request when device is + * idle. + * + * @param isReportingRequestedWhileIdle true if request reporting when device is idle + * + * @return the builder to facilitate the chaining + */ + public @NonNull Builder setReportingRequestedWhileIdle( + boolean isReportingRequestedWhileIdle) { + mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; + return this; + } + + /** + * Set the builder object if require reporting on the system thresholds when device is idle. + * + * This can only used by the system caller. + * + * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the + * system thresholds when device is idle + * @return the builder to facilitate the chaining + * @hide + */ + public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( + boolean isSystemThresholdReportingRequestedWhileIdle) { + mIsSystemThresholdReportingRequestedWhileIdle = + isSystemThresholdReportingRequestedWhileIdle; + return this; + } + + /** + * Build a {@link SignalStrengthUpdateRequest} object. + * + * @return the SignalStrengthUpdateRequest object + * + * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the + * radio access network type in the collection is not unique + */ + public @NonNull SignalStrengthUpdateRequest build() { + return new SignalStrengthUpdateRequest(mSignalThresholdInfos, + mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle); + } + } + + private SignalStrengthUpdateRequest(Parcel in) { + mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR); + mIsReportingRequestedWhileIdle = in.readBoolean(); + mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean(); + } + + /** + * Get the collection of SignalThresholdInfo in the request. + * + * @return the collection of SignalThresholdInfo + */ + @NonNull + public Collection<SignalThresholdInfo> getSignalThresholdInfos() { + return Collections.unmodifiableList(mSignalThresholdInfos); + } + + /** + * Get whether reporting is requested for the threshold in the request while device is idle. + * + * @return true if reporting requested while device is idle + */ + public boolean isReportingRequestedWhileIdle() { + return mIsReportingRequestedWhileIdle; + } + + /** + * @return true if reporting requested for system thresholds while device is idle + * + * @hide + */ + public boolean isSystemThresholdReportingRequestedWhileIdle() { + return mIsSystemThresholdReportingRequestedWhileIdle; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedList(mSignalThresholdInfos); + dest.writeBoolean(mIsReportingRequestedWhileIdle); + dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle); + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + + if (!(other instanceof SignalStrengthUpdateRequest)) { + return false; + } + + SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other; + return request.mSignalThresholdInfos.equals(mSignalThresholdInfos) + && request.mIsReportingRequestedWhileIdle == mIsReportingRequestedWhileIdle + && request.mIsSystemThresholdReportingRequestedWhileIdle + == mIsSystemThresholdReportingRequestedWhileIdle; + } + + @Override + public int hashCode() { + return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle, + mIsSystemThresholdReportingRequestedWhileIdle); + } + + public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR = + new Parcelable.Creator<SignalStrengthUpdateRequest>() { + @Override + public SignalStrengthUpdateRequest createFromParcel(Parcel source) { + return new SignalStrengthUpdateRequest(source); + } + + @Override + public SignalStrengthUpdateRequest[] newArray(int size) { + return new SignalStrengthUpdateRequest[size]; + } + }; + + @Override + public String toString() { + return new StringBuilder("SignalStrengthUpdateRequest{") + .append("mSignalThresholdInfos=") + .append(mSignalThresholdInfos) + .append(" mIsReportingRequestedWhileIdle=") + .append(mIsReportingRequestedWhileIdle) + .append(" mIsSystemThresholdReportingRequestedWhileIdle=") + .append(mIsSystemThresholdReportingRequestedWhileIdle) + .append("}").toString(); + } + + /** + * Throw IAE when the RAN in the collection is not unique. + */ + private static void validate(Collection<SignalThresholdInfo> infos) { + Set<Integer> uniqueRan = new HashSet<>(infos.size()); + for (SignalThresholdInfo info : infos) { + final int ran = info.getRadioAccessNetworkType(); + if (!uniqueRan.add(ran)) { + throw new IllegalArgumentException("RAN: " + ran + " is not unique"); + } + } + } +} diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java index 8a472adb9e03..0059ad6c2426 100644 --- a/telephony/java/android/telephony/SignalThresholdInfo.java +++ b/telephony/java/android/telephony/SignalThresholdInfo.java @@ -28,13 +28,11 @@ import java.util.Objects; /** * Defines the threshold value of the signal strength. - * @hide */ public final class SignalThresholdInfo implements Parcelable { /** * Unknown signal measurement type. - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0; @@ -44,7 +42,6 @@ public final class SignalThresholdInfo implements Parcelable { * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#GERAN}, * {@link AccessNetworkConstants.AccessNetworkType#CDMA2000} * Reference: 3GPP TS 27.007 section 8.5. - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1; @@ -53,7 +50,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -120 dBm to -25 dBm; * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#UTRAN} * Reference: 3GPP TS 25.123, section 9.1.1.1 - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2; @@ -62,7 +58,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -140 dBm to -44 dBm; * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN} * Reference: 3GPP TS 36.133 9.1.4 - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3; @@ -71,7 +66,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -34 dB to 3 dB; * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN} * Reference: 3GPP TS 36.133 9.1.7 - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4; @@ -79,7 +73,6 @@ public final class SignalThresholdInfo implements Parcelable { * Reference Signal Signal to Noise Ratio * Range: -20 dB to 30 dB; * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN} - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5; @@ -88,7 +81,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -140 dBm to -44 dBm. * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN} * Reference: 3GPP TS 38.215. - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6; @@ -97,7 +89,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -43 dB to 20 dB. * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN} * Reference: 3GPP TS 38.133 section 10.1.11.1. - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7; @@ -106,7 +97,6 @@ public final class SignalThresholdInfo implements Parcelable { * Range: -23 dB to 40 dB * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN} * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1. - * @hide */ public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; @@ -290,6 +280,20 @@ public final class SignalThresholdInfo implements Parcelable { public static final int SIGNAL_SSSINR_MAX_VALUE = 40; /** + * The minimum number of thresholds allowed in each SignalThresholdInfo. + * + * @hide + */ + public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1; + + /** + * The maximum number of thresholds allowed in each SignalThresholdInfo. + * + * @hide + */ + public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4; + + /** * Constructor * * @param ran Radio Access Network type @@ -316,8 +320,6 @@ public final class SignalThresholdInfo implements Parcelable { /** * Builder class to create {@link SignalThresholdInfo} objects. - * - * @hide */ public static final class Builder { private int mRan = AccessNetworkConstants.AccessNetworkType.UNKNOWN; @@ -378,21 +380,58 @@ public final class SignalThresholdInfo implements Parcelable { } /** - * Set the signal threshold values of the corresponding signal measurement type. + * Set the signal strength thresholds of the corresponding signal measurement type. * - * The range and unit must reference specific SignalMeasurementType. + * The range and unit must reference specific SignalMeasurementType. The length of the + * thresholds should between the numbers return from + * {@link #getMinimumNumberOfThresholdsAllowed()} and + * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw + * otherwise. * * @param thresholds array of integer as the signal threshold values * @return the builder to facilitate the chaining + * + * @see #SIGNAL_MEASUREMENT_TYPE_RSSI + * @see #SIGNAL_MEASUREMENT_TYPE_RSCP + * @see #SIGNAL_MEASUREMENT_TYPE_RSRP + * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ + * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR + * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP + * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ + * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR + * @see #getThresholds() for more details on signal strength thresholds */ public @NonNull Builder setThresholds(@NonNull int[] thresholds) { Objects.requireNonNull(thresholds, "thresholds must not be null"); + if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) { + throw new IllegalArgumentException( + "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED); + } mThresholds = thresholds.clone(); Arrays.sort(mThresholds); return this; } /** + * Set the signal strength thresholds for the corresponding signal measurement type without + * the length limitation. + * + * @param thresholds array of integer as the signal threshold values + * @return the builder to facilitate the chaining + * + * @hide + */ + public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) { + Objects.requireNonNull(thresholds, "thresholds must not be null"); + mThresholds = thresholds.clone(); + Arrays.sort(mThresholds); + return this; + } + + + /** * Set if the modem should trigger the report based on the criteria. * * @param isEnabled true if the modem should trigger the report based on the criteria @@ -423,8 +462,6 @@ public final class SignalThresholdInfo implements Parcelable { * Get the radio access network type. * * @return radio access network type - * - * @hide */ public @AccessNetworkConstants.RadioAccessNetworkType int getRadioAccessNetworkType() { return mRan; @@ -434,8 +471,6 @@ public final class SignalThresholdInfo implements Parcelable { * Get the signal measurement type. * * @return the SignalMeasurementType value - * - * @hide */ public @SignalMeasurementType int getSignalMeasurementType() { return mSignalMeasurementType; @@ -457,16 +492,47 @@ public final class SignalThresholdInfo implements Parcelable { } /** - * Get the signal threshold values. + * Get the signal strength thresholds. + * + * Signal strength thresholds are a list of integer used for suggesting signal level and signal + * reporting criteria. The range and unit must reference specific SignalMeasurementType. + * + * Please refer to https://source.android.com/devices/tech/connect/signal-strength on how signal + * strength thresholds are used for signal strength reporting. * * @return array of integer of the signal thresholds * - * @hide + * @see #SIGNAL_MEASUREMENT_TYPE_RSSI + * @see #SIGNAL_MEASUREMENT_TYPE_RSCP + * @see #SIGNAL_MEASUREMENT_TYPE_RSRP + * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ + * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR + * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP + * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ + * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR */ public @NonNull int[] getThresholds() { return mThresholds.clone(); } + /** + * Get the minimum number of thresholds allowed in each SignalThresholdInfo. + * + * @return the minimum number of thresholds allowed + */ + public static int getMinimumNumberOfThresholdsAllowed() { + return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED; + } + + /** + * Get the maximum number of threshold allowed in each SignalThresholdInfo. + * + * @return the maximum number of thresholds allowed + */ + public static int getMaximumNumberOfThresholdsAllowed() { + return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED; + } + @Override public int describeContents() { return 0; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index cedd6f369160..f39ee095758c 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -124,6 +124,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -155,6 +156,7 @@ import java.util.function.Consumer; public class TelephonyManager { private static final String TAG = "TelephonyManager"; + private TelephonyRegistryManager mTelephonyRegistryMgr; /** * To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and * {@link TelephonyManager#setPreferredOpportunisticDataSubscription}. @@ -5569,8 +5571,7 @@ public class TelephonyManager { // /** - * Registers a listener object to receive notification of changes - * in specified telephony states. + * Registers a listener object to receive notification of changes in specified telephony states. * <p> * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony * state of interest in the events argument. @@ -5580,13 +5581,15 @@ public class TelephonyManager { * values. * <p> * To un-register a listener, pass the listener object and set the events argument to - * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). + * {@link PhoneStateListener#LISTEN_NONE} (0). * * If this TelephonyManager object has been created with {@link #createForSubscriptionId}, * applies to the given subId. Otherwise, applies to - * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds, + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds, * pass a separate listener object to each TelephonyManager object created with - * {@link #createForSubscriptionId}. + * {@link #createForSubscriptionId}. Only {@link PhoneStateListener#LISTEN_CALL_STATE} event can + * be used to receive changes for all subIds through + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. * * Note: if you call this method while in the middle of a binder transaction, you <b>must</b> * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A @@ -5596,23 +5599,28 @@ public class TelephonyManager { * instability. If a process has registered too many listeners without unregistering them, it * may encounter an {@link IllegalStateException} when trying to register more listeners. * - * @param listener The {@link PhoneStateListener} object to register - * (or unregister) - * @param events The telephony state(s) of interest to the listener, - * as a bitwise-OR combination of {@link PhoneStateListener} - * LISTEN_ flags. + * @param listener The {@link PhoneStateListener} object to register (or unregister) + * @param events The telephony state(s) of interest to the listener, as a bitwise-OR combination + * of {@link PhoneStateListener} LISTEN_ flags. + * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}. */ + @Deprecated public void listen(PhoneStateListener listener, int events) { - if (mContext == null) return; - boolean notifyNow = (getITelephony() != null); - TelephonyRegistryManager telephonyRegistry = - (TelephonyRegistryManager) - mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); - if (telephonyRegistry != null) { - telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(), - listener, events, notifyNow); + if (!listener.isExecutorSet()) { + throw new IllegalStateException("PhoneStateListener should be created on a thread " + + "with Looper.myLooper() != null"); + } + boolean notifyNow = getITelephony() != null; + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr != null) { + if (events != PhoneStateListener.LISTEN_NONE) { + mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId, + getOpPackageName(), getAttributionTag(), listener, events, notifyNow); + } else { + unregisterPhoneStateListener(listener); + } } else { - Rlog.w(TAG, "telephony registry not ready."); + throw new IllegalStateException("telephony service is null."); } } @@ -14593,4 +14601,71 @@ public class TelephonyManager { e.execute(() -> callback.onAuthenticationFailure(GBA_FAILURE_REASON_FEATURE_NOT_READY)); } } + + /** + * Registers a listener object to receive notification of changes in specified telephony states. + * <p> + * To register a listener, pass a {@link PhoneStateListener} which implements + * interfaces of events. For example, + * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements + * {@link PhoneStateListener.ServiceStateChangedListener}. + * + * At registration, and when a specified telephony state changes, the telephony manager invokes + * the appropriate callback method on the listener object and passes the current (updated) + * values. + * <p> + * + * If this TelephonyManager object has been created with {@link #createForSubscriptionId}, + * applies to the given subId. Otherwise, applies to + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds, + * pass a separate listener object to each TelephonyManager object created with + * {@link #createForSubscriptionId}. Only {@link PhoneStateListener.CallStateChangedListener} + * can be used to receive changes for all subIds through + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. + * + * Note: if you call this method while in the middle of a binder transaction, you <b>must</b> + * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A + * {@link SecurityException} will be thrown otherwise. + * + * This API should be used sparingly -- large numbers of listeners will cause system + * instability. If a process has registered too many listeners without unregistering them, it + * may encounter an {@link IllegalStateException} when trying to register more listeners. + * + * @param executor The executor of where the callback will execute. + * @param listener The {@link PhoneStateListener} object to register. + */ + public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, + @NonNull PhoneStateListener listener) { + if (executor == null || listener == null) { + throw new IllegalArgumentException("PhoneStateListener and executor must be non-null"); + } + mTelephonyRegistryMgr = (TelephonyRegistryManager) + mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); + if (mTelephonyRegistryMgr != null) { + mTelephonyRegistryMgr.registerPhoneStateListener(executor, mSubId, + getOpPackageName(), getAttributionTag(), listener, getITelephony() != null); + } else { + throw new IllegalStateException("telephony service is null."); + } + } + + /** + * Unregister an existing {@link PhoneStateListener}. + * + * @param listener The {@link PhoneStateListener} object to unregister. + */ + public void unregisterPhoneStateListener(@NonNull PhoneStateListener listener) { + + if (mContext == null) { + throw new IllegalStateException("telephony service is null."); + } + + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr != null) { + mTelephonyRegistryMgr.unregisterPhoneStateListener(mSubId, getOpPackageName(), + getAttributionTag(), listener, getITelephony() != null); + } else { + throw new IllegalStateException("telephony service is null."); + } + } } diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java index 66281edc0de1..fd206c1e803f 100644 --- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java +++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java @@ -320,4 +320,11 @@ public final class DelegateRegistrationState implements Parcelable { public int hashCode() { return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags); } + + @Override + public String toString() { + return "DelegateRegistrationState{ registered={" + mRegisteredTags + + "}, deregistering={" + mDeregisteringTags + "}, deregistered={" + + mDeregisteredTags + "}}"; + } } diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java index d2cb9761a028..d9734a7475c0 100644 --- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -18,15 +18,12 @@ package android.telephony.ims.stub; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.net.Uri; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.RcsFeature; -import java.util.List; - /** * The interface of the capabilities event listener for ImsService to notify the framework of the * UCE request and status updated. @@ -84,25 +81,4 @@ public interface CapabilityExchangeEventListener { * Telephony stack has crashed. */ void onUnpublish() throws ImsException; - - /** - * Inform the framework of a query for this device's UCE capabilities. - * <p> - * The framework will respond via the - * {@link OptionsRequestCallback#onRespondToCapabilityRequest} or - * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError} - * @param contactUri The URI associated with the remote contact that is - * requesting capabilities. - * @param remoteCapabilities The remote contact's capability information. - * @param callback The callback of this request which is sent from the remote user. - * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not - * currently connected to the framework. This can happen if the {@link RcsFeature} is not - * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received - * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare - * cases when the Telephony stack has crashed. - * @hide - */ - void onRemoteCapabilityRequest(@NonNull Uri contactUri, - @NonNull List<String> remoteCapabilities, - @NonNull OptionsRequestCallback callback) throws ImsException; } diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt index 8710d23730b6..b2bcfeb9019d 100644 --- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt +++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt @@ -18,12 +18,15 @@ package android.net import android.os.Build import androidx.test.filters.SmallTest +import com.android.modules.utils.build.SdkLevel import com.android.testutils.assertParcelSane import com.android.testutils.assertParcelingIsLossless +import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals @@ -33,6 +36,9 @@ import kotlin.test.assertNotEquals @RunWith(DevSdkIgnoreRunner::class) @IgnoreUpTo(Build.VERSION_CODES.Q) class CaptivePortalDataTest { + @Rule @JvmField + val ignoreRule = DevSdkIgnoreRule() + private val data = CaptivePortalData.Builder() .setRefreshTime(123L) .setUserPortalUrl(Uri.parse("https://portal.example.com/test")) @@ -41,14 +47,19 @@ class CaptivePortalDataTest { .setBytesRemaining(456L) .setExpiryTime(789L) .setCaptive(true) - .setVenueFriendlyName("venue friendly name") + .apply { + if (SdkLevel.isAtLeastS()) { + setVenueFriendlyName("venue friendly name") + } + } .build() private fun makeBuilder() = CaptivePortalData.Builder(data) @Test fun testParcelUnparcel() { - assertParcelSane(data, fieldCount = 8) + val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7 + assertParcelSane(data, fieldCount) assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build()) assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build()) @@ -67,8 +78,11 @@ class CaptivePortalDataTest { assertNotEqualsAfterChange { it.setBytesRemaining(789L) } assertNotEqualsAfterChange { it.setExpiryTime(12L) } assertNotEqualsAfterChange { it.setCaptive(false) } - assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") } - assertNotEqualsAfterChange { it.setVenueFriendlyName(null) } + + if (SdkLevel.isAtLeastS()) { + assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") } + assertNotEqualsAfterChange { it.setVenueFriendlyName(null) } + } } @Test @@ -111,7 +125,7 @@ class CaptivePortalDataTest { assertFalse(makeBuilder().setCaptive(false).build().isCaptive) } - @Test + @Test @IgnoreUpTo(Build.VERSION_CODES.R) fun testVenueFriendlyName() { assertEquals("venue friendly name", data.venueFriendlyName) } diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 8e1875168a84..16c486562f53 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -46,8 +46,6 @@ import com.android.server.ConnectivityService import com.android.server.LocalServices import com.android.server.NetworkAgentWrapper import com.android.server.TestNetIdManager -import com.android.server.connectivity.DefaultNetworkMetrics -import com.android.server.connectivity.IpConnectivityMetrics import com.android.server.connectivity.MockableSystemProperties import com.android.server.connectivity.ProxyTracker import com.android.server.net.NetworkPolicyManagerInternal @@ -92,10 +90,6 @@ class ConnectivityServiceIntegrationTest { private lateinit var netd: INetd @Mock private lateinit var dnsResolver: IDnsResolver - @Mock - private lateinit var metricsLogger: IpConnectivityMetrics.Logger - @Mock - private lateinit var defaultMetrics: DefaultNetworkMetrics @Spy private var context = TestableContext(realContext) @@ -149,7 +143,6 @@ class ConnectivityServiceIntegrationTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) - doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics() doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any()) networkStackClient = TestNetworkStackClient(realContext) @@ -173,7 +166,6 @@ class ConnectivityServiceIntegrationTest { private fun makeDependencies(): ConnectivityService.Dependencies { val deps = spy(ConnectivityService.Dependencies()) doReturn(networkStackClient).`when`(deps).networkStack - doReturn(metricsLogger).`when`(deps).metricsLogger doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any()) doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager() diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b6e6816ca531..37307a46b8ac 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Intent.ACTION_USER_ADDED; import static android.content.Intent.ACTION_USER_REMOVED; +import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; @@ -221,6 +222,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Credentials; import android.security.KeyStore; import android.system.Os; import android.telephony.TelephonyManager; @@ -237,14 +239,13 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IBatteryStats; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; +import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.connectivity.ConnectivityConstants; -import com.android.server.connectivity.DefaultNetworkMetrics; -import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; @@ -281,6 +282,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -367,8 +369,6 @@ public class ConnectivityServiceTest { private HandlerThread mAlarmManagerThread; private TestNetIdManager mNetIdManager; - @Mock IpConnectivityMetrics.Logger mMetricsService; - @Mock DefaultNetworkMetrics mDefaultNetworkMetrics; @Mock DeviceIdleInternal mDeviceIdleInternal; @Mock INetworkManagementService mNetworkManagementService; @Mock INetworkStatsService mStatsService; @@ -388,6 +388,7 @@ public class ConnectivityServiceTest { @Mock MockableSystemProperties mSystemProperties; @Mock EthernetManager mEthernetManager; @Mock NetworkPolicyManager mNetworkPolicyManager; + @Mock KeyStore mKeyStore; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -1066,6 +1067,15 @@ public class ConnectivityServiceTest { private int mVpnType = VpnManager.TYPE_VPN_SERVICE; private VpnInfo mVpnInfo; + // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started. + // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the + // test expects two starts in a row, or even if the production code calls start twice in a + // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into + // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has + // extensive access into the internals of Vpn. + private ConditionVariable mStartLegacyVpnCv = new ConditionVariable(); + private ConditionVariable mStopVpnRunnerCv = new ConditionVariable(); + public MockVpn(int userId) { super(startHandlerThreadAndReturnLooper(), mServiceContext, new Dependencies() { @@ -1079,7 +1089,7 @@ public class ConnectivityServiceTest { return mDeviceIdleInternal; } }, - mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class)); + mNetworkManagementService, mMockNetd, userId, mKeyStore); } public void setUids(Set<UidRange> uids) { @@ -1191,10 +1201,44 @@ public class ConnectivityServiceTest { } mAgentRegistered = false; setUids(null); + // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on. + mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET); mInterface = null; } @Override + public void startLegacyVpnRunner() { + mStartLegacyVpnCv.open(); + } + + public void expectStartLegacyVpnRunner() { + assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms", + mStartLegacyVpnCv.block(TIMEOUT_MS)); + + // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just + // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect + // that the VpnRunner is stopped and immediately restarted by calling + // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back. + mStopVpnRunnerCv = new ConditionVariable(); + } + + @Override + public void stopVpnRunnerPrivileged() { + if (mVpnRunner != null) { + super.stopVpnRunnerPrivileged(); + disconnect(); + mStartLegacyVpnCv = new ConditionVariable(); + } + mVpnRunner = null; + mStopVpnRunnerCv.open(); + } + + public void expectStopVpnRunnerPrivileged() { + assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms", + mStopVpnRunnerCv.block(TIMEOUT_MS)); + } + + @Override public synchronized VpnInfo getVpnInfo() { if (mVpnInfo != null) return mVpnInfo; @@ -1275,10 +1319,19 @@ public class ConnectivityServiceTest { } } - private static final int VPN_USER = 0; - private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100); - private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101); - private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043); + private static final int PRIMARY_USER = 0; + private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100); + private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101); + private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043); + private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "", + UserInfo.FLAG_PRIMARY); + + private static final int RESTRICTED_USER = 1; + private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "", + UserInfo.FLAG_RESTRICTED); + static { + RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER; + } @Before public void setUp() throws Exception { @@ -1287,12 +1340,14 @@ public class ConnectivityServiceTest { mContext = InstrumentationRegistry.getContext(); MockitoAnnotations.initMocks(this); - when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics); - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(VPN_USER, "", 0), - })); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO)); + when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO); + // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context + // it was started from, i.e., PRIMARY_USER. + when(mUserManager.canHaveRestrictedProfile()).thenReturn(true); + when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO); + final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) @@ -1362,9 +1417,9 @@ public class ConnectivityServiceTest { doReturn(mNetworkStack).when(deps).getNetworkStack(); doReturn(mSystemProperties).when(deps).getSystemProperties(); doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); - doReturn(mMetricsService).when(deps).getMetricsLogger(); doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); doReturn(mBatteryStatsService).when(deps).getBatteryStatsService(); + doReturn(mKeyStore).when(deps).getKeyStore(); doAnswer(inv -> { mPolicyTracker = new WrappedMultinetworkPolicyTracker( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); @@ -1533,7 +1588,7 @@ public class ConnectivityServiceTest { waitForIdle(); try { final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS); - fail("Unexpected broadcast: " + intent.getAction()); + fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras()); } catch (TimeoutException expected) { } finally { mServiceContext.unregisterReceiver(mReceiver); @@ -2074,10 +2129,6 @@ public class ConnectivityServiceTest { @Test public void testOwnerUidCannotChange() throws Exception { - // Owner UIDs are not visible without location permission. - setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, - Manifest.permission.ACCESS_FINE_LOCATION); - final NetworkCapabilities ncTemplate = new NetworkCapabilities(); final int originalOwnerUid = Process.myUid(); ncTemplate.setOwnerUid(originalOwnerUid); @@ -2097,6 +2148,10 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); waitForIdle(); + // Owner UIDs are not visible without location permission. + setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); + // Check that the capability change has been applied but the owner UID is not modified. NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); assertEquals(originalOwnerUid, nc.getOwnerUid()); @@ -5837,6 +5892,131 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(callback); } + private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) { + // What Chromium used to do before https://chromium-review.googlesource.com/2605304 + assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())", + expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected()); + } + + @Test + public void testVpnUnderlyingNetworkSuspended() throws Exception { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + + // Connect a VPN. + mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */, + false /* isStrictMode */); + callback.expectAvailableCallbacksUnvalidated(mMockVpn); + + // Connect cellular data. + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(false /* validated */); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); + + // Suspend the cellular network and expect the VPN to be suspended. + mCellNetworkAgent.suspend(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn); + callback.assertNoCallback(); + + assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + // VPN's main underlying network is suspended, so no connectivity. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Switch to another network. The VPN should no longer be suspended. + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false /* validated */); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_WIFI)); + + // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent. + // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); // BUG: VPN caps have NOT_SUSPENDED. + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + // BUG: the device has connectivity, so this should return true. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Unsuspend cellular and then switch back to it. + // The same bug happens in the opposite direction: the VPN's capabilities correctly have + // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED. + mCellNetworkAgent.resume(); + callback.assertNoCallback(); + mWiFiNetworkAgent.disconnect(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + // Spurious double callback? + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); // BUG: VPN caps have NOT_SUSPENDED. + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + // BUG: the device has connectivity, so this should return true. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Re-suspending the current network fixes the problem. + mCellNetworkAgent.suspend(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn); + callback.assertNoCallback(); + + assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + mCellNetworkAgent.resume(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.RESUMED, mMockVpn); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); + } + @Test public void testVpnNetworkActive() throws Exception { final int uid = Process.myUid(); @@ -6315,7 +6495,7 @@ public class ConnectivityServiceTest { } @Test - public void testVpnRestrictedUsers() throws Exception { + public void testRestrictedProfileAffectsVpnUidRanges() throws Exception { // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities. mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); @@ -6347,19 +6527,11 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps) -> caps.hasCapability(NET_CAPABILITY_VALIDATED)); - // Create a fake restricted profile whose parent is our user ID. - final int userId = UserHandle.getUserId(uid); - when(mUserManager.canHaveRestrictedProfile()).thenReturn(true); - final int restrictedUserId = userId + 1; - final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED); - info.restrictedProfileParentId = userId; - assertTrue(info.isRestricted()); - when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info); - when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId)) - .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID)); + when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER)) + .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)); final Intent addedIntent = new Intent(ACTION_USER_ADDED); - addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); // Send a USER_ADDED broadcast for it. // The BroadcastReceiver for this broadcast checks that is being run on the handler thread. @@ -6371,7 +6543,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(restrictedUserId)) + && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); @@ -6381,13 +6553,13 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(restrictedUserId)) + && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user. final Intent removedIntent = new Intent(ACTION_USER_REMOVED); - removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); + removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); // Expect that the VPN gains the UID range for the restricted user, and that the capability @@ -6397,53 +6569,72 @@ public class ConnectivityServiceTest { && caps.getUids().contains(new UidRange(uid, uid)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); + } - // Test lockdown with restricted profiles. + @Test + public void testLockdownVpnWithRestrictedProfiles() throws Exception { + // For ConnectivityService#setAlwaysOnVpnPackage. mServiceContext.setPermission( Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED); + // For call Vpn#setAlwaysOnPackage. mServiceContext.setPermission( Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED); + // Necessary to see the UID ranges in NetworkCapabilities. mServiceContext.setPermission( Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + final NetworkRequest request = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + final int uid = Process.myUid(); + // Connect wifi and check that UIDs in the main and restricted profiles have network access. - mMockVpn.disconnect(); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true /* validated */); - final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */); + final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */); assertNotNull(mCm.getActiveNetworkForUid(uid)); assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); // Enable always-on VPN lockdown. The main user loses network access because no VPN is up. final ArrayList<String> allowList = new ArrayList<>(); - mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */, + allowList); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); + // This is arguably overspecified: a UID that is not running doesn't have an active network. + // But it's useful to check that non-default users do not lose network access, and to prove + // that the loss of connectivity below is indeed due to the restricted profile coming up. assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); // Start the restricted profile, and check that the UID within it loses network access. - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(userId, "", 0), - info - })); + when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER)) + .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO, + RESTRICTED_USER_INFO)); // TODO: check that VPN app within restricted profile still has access, etc. + final Intent addedIntent = new Intent(ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); + final Handler handler = new Handler(mCsHandlerThread.getLooper()); handler.post(() -> mServiceContext.sendBroadcast(addedIntent)); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); assertNull(mCm.getActiveNetworkForUid(restrictedUid)); // Stop the restricted profile, and check that the UID within it has network access again. - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(userId, "", 0), - })); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO)); + + // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user. + final Intent removedIntent = new Intent(ACTION_USER_REMOVED); + removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); - mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); + mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList); waitForIdle(); } @@ -6784,6 +6975,7 @@ public class ConnectivityServiceTest { final int userId = UserHandle.getUserId(uid); final ArrayList<String> allowList = new ArrayList<>(); mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + waitForIdle(); UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1); UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999); @@ -6805,10 +6997,10 @@ public class ConnectivityServiceTest { // Disable lockdown, expect to see the network unblocked. mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); - expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf); callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); vpnUidCallback.assertNoCallback(); + expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -6851,9 +7043,11 @@ public class ConnectivityServiceTest { // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown. // Everything should now be blocked. mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); + waitForIdle(); expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3); allowList.clear(); mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + waitForIdle(); expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf); defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); @@ -6931,6 +7125,200 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(vpnUidCallback); } + private void setupLegacyLockdownVpn() { + final String profileName = "testVpnProfile"; + final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8); + when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true); + when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag); + + final VpnProfile profile = new VpnProfile(profileName); + profile.name = "My VPN"; + profile.server = "192.0.2.1"; + profile.dnsServers = "8.8.8.8"; + profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK; + final byte[] encodedProfile = profile.encode(); + when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile); + } + + @Test + public void testLegacyLockdownVpn() throws Exception { + mServiceContext.setPermission( + Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED); + + final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + // Pretend lockdown VPN was configured. + setupLegacyLockdownVpn(); + + // LockdownVpnTracker disables the Vpn teardown code and enables lockdown. + // Check the VPN's state before it does so. + assertTrue(mMockVpn.getEnableTeardown()); + assertFalse(mMockVpn.getLockdown()); + + // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker. + final int userId = UserHandle.getUserId(Process.myUid()); + final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + final Handler handler = new Handler(mCsHandlerThread.getLooper()); + handler.post(() -> mServiceContext.sendBroadcast(addedIntent)); + waitForIdle(); + + // Lockdown VPN disables teardown and enables lockdown. + assertFalse(mMockVpn.getEnableTeardown()); + assertTrue(mMockVpn.getLockdown()); + + // Bring up a network. + // Expect nothing to happen because the network does not have an IPv4 default route: legacy + // VPN only supports IPv4. + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName("rmnet0"); + cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64")); + cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0")); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellNetworkAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + waitForIdle(); + assertNull(mMockVpn.getAgent()); + + // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls + // LockdownVpnTracker#handleStateChangedLocked. This is a bug. + // TODO: consider fixing this. + cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25")); + cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0")); + mCellNetworkAgent.sendLinkProperties(cellLp); + callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + waitForIdle(); + assertNull(mMockVpn.getAgent()); + + // Disconnect, then try again with a network that supports IPv4 at connection time. + // Expect lockdown VPN to come up. + ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); + mCellNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + b1.expectBroadcast(); + + // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten + // with the state of the VPN network. So expect a CONNECTING broadcast. + b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellNetworkAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + b1.expectBroadcast(); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + + // TODO: it would be nice if we could simply rely on the production code here, and have + // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with + // ConnectivityService, etc. That would require duplicating a fair bit of code from the + // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not + // work for at least two reasons: + // 1. In this test, calling registerNetworkAgent does not actually result in an agent being + // registered. This is because nothing calls onNetworkMonitorCreated, which is what + // actually ends up causing handleRegisterNetworkAgent to be called. Code in this test + // that wants to register an agent must use TestNetworkAgentWrapper. + // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call + // the TestNetworkAgentWrapper code, this would deadlock because the + // TestNetworkAgentWrapper code cannot be called on the handler thread since it calls + // waitForIdle(). + mMockVpn.expectStartLegacyVpnRunner(); + b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); + ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); + mMockVpn.establishForMyUid(); + callback.expectAvailableThenValidatedCallbacks(mMockVpn); + defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); + b1.expectBroadcast(); + b2.expectBroadcast(); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect. + final LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName("wlan0"); + wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25")); + wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0")); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + + b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); + // Wifi is CONNECTING because the VPN isn't up yet. + b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING); + ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); + mWiFiNetworkAgent.connect(false /* validated */); + b1.expectBroadcast(); + b2.expectBroadcast(); + b3.expectBroadcast(); + mMockVpn.expectStopVpnRunnerPrivileged(); + mMockVpn.expectStartLegacyVpnRunner(); + + // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still + // connected, so the network is not considered blocked by the lockdown UID ranges? But the + // fact that a VPN is connected should only result in the VPN itself being unblocked, not + // any other network. Bug in isUidBlockedByVpn? + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI)); + callback.expectCallback(CallbackEntry.LOST, mMockVpn); + defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI)); + defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); + + // While the VPN is reconnecting on the new network, everything is blocked. + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + + // The VPN comes up again on wifi. + b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); + b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); + mMockVpn.establishForMyUid(); + callback.expectAvailableThenValidatedCallbacks(mMockVpn); + defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); + b1.expectBroadcast(); + b2.expectBroadcast(); + + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + // Disconnect cell. Nothing much happens since it's not the default network. + // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any + // NetworkInfo is updated. This is probably a bug. + // TODO: consider fixing this. + b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); + mCellNetworkAgent.disconnect(); + b1.expectBroadcast(); + callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + defaultCallback.assertNoCallback(); + + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); + mWiFiNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); + b1.expectBroadcast(); + callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI)); + b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); + mMockVpn.expectStopVpnRunnerPrivileged(); + callback.expectCallback(CallbackEntry.LOST, mMockVpn); + b2.expectBroadcast(); + } + @Test public final void testLoseTrusted() throws Exception { final NetworkRequest trustedRequest = new NetworkRequest.Builder() @@ -7605,7 +7993,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -7633,7 +8021,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -7649,7 +8037,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -7664,7 +8052,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -7716,7 +8104,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final UidRange vpnRange = UidRange.createForUser(VPN_USER); + final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -7781,8 +8169,22 @@ public class ConnectivityServiceTest { naExtraInfo.unregister(); } + // To avoid granting location permission bypass. + private void denyAllLocationPrivilegedPermissions() { + mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + PERMISSION_DENIED); + mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, + PERMISSION_DENIED); + mServiceContext.setPermission(Manifest.permission.NETWORK_STACK, + PERMISSION_DENIED); + mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD, + PERMISSION_DENIED); + } + private void setupLocationPermissions( int targetSdk, boolean locationToggle, String op, String perm) throws Exception { + denyAllLocationPrivilegedPermissions(); + final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = targetSdk; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) @@ -7900,7 +8302,7 @@ public class ConnectivityServiceTest { private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); mMockVpn.setVpnType(vpnType); @@ -8104,11 +8506,18 @@ public class ConnectivityServiceTest { assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder)); } + public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) { + final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + ConnectivityManager.getNetworkTypeName(TYPE_MOBILE), + TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE)); + return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(), + nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null, + 0, INVALID_UID); + } + @Test public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission( android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED); @@ -8121,9 +8530,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -8136,9 +8543,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -8151,22 +8556,17 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception { - final Network network = new Network(NET_ID); - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); - - setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, - Manifest.permission.ACCESS_FINE_LOCATION); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mMockVpn.establishForMyUid(); assertUidRangesUpdatedForMyUid(true); // Wait for networks to connect and broadcasts to be sent before removing permissions. waitForIdle(); - mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); + setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION); - assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); + assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network})); waitForIdle(); assertTrue( "Active VPN permission not applied", @@ -8187,9 +8587,7 @@ public class ConnectivityServiceTest { public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setAdministratorUids(new int[] {Process.myUid()}); - final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithUid = fakeMobileNai(nc); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -8206,9 +8604,7 @@ public class ConnectivityServiceTest { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setOwnerUid(Process.myUid()); nc.setAdministratorUids(new int[] {Process.myUid()}); - final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithUid = fakeMobileNai(nc); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -8429,6 +8825,7 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(genericRequest, genericNetworkCallback); mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); + waitForIdle(); final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById(); @@ -8474,7 +8871,7 @@ public class ConnectivityServiceTest { lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); - final UidRange vpnRange = UidRange.createForUser(VPN_USER); + final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -8490,4 +8887,20 @@ public class ConnectivityServiceTest { assertVpnUidRangesUpdated(true, newRanges, VPN_UID); assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID); } + + @Test + public void testInvalidRequestTypes() { + final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(), + NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length}; + final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI); + + for (int reqTypeInt : invalidReqTypeInts) { + assertThrows("Expect throws for invalid request type " + reqTypeInt, + IllegalArgumentException.class, + () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null, + ConnectivityManager.TYPE_NONE, mContext.getPackageName(), + getAttributionTag()) + ); + } + } } diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 96c56e32f156..4d151afecd63 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -34,7 +34,9 @@ import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; +import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; @@ -353,9 +355,10 @@ public class LingerMonitorTest { NetworkCapabilities caps = new NetworkCapabilities(); caps.addCapability(0); caps.addTransportType(transport); - NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null, - caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, - NetworkProvider.ID_NONE, Binder.getCallingUid()); + NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, + new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */, + mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE, + Binder.getCallingUid()); nai.everValidated = true; return nai; } diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java new file mode 100644 index 000000000000..31561901be9e --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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.net.vcn; + +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; + +import android.net.wifi.WifiInfo; +import android.os.Parcel; + +import org.junit.Test; + +public class VcnTransportInfoTest { + private static final int SUB_ID = 1; + private static final int NETWORK_ID = 5; + private static final WifiInfo WIFI_INFO = + new WifiInfo.Builder().setNetworkId(NETWORK_ID).build(); + + private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID); + private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO); + + @Test + public void testGetWifiInfo() { + assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); + + assertNull(CELL_UNDERLYING_INFO.getWifiInfo()); + } + + @Test + public void testGetSubId() { + assertEquals(SUB_ID, CELL_UNDERLYING_INFO.getSubId()); + + assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId()); + } + + @Test + public void testEquals() { + assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO); + assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); + assertNotEquals(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO); + } + + @Test + public void testParcelUnparcel() { + verifyParcelingIsNull(CELL_UNDERLYING_INFO); + verifyParcelingIsNull(WIFI_UNDERLYING_INFO); + } + + private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) { + Parcel parcel = Parcel.obtain(); + vcnTransportInfo.writeToParcel(parcel, 0 /* flags */); + assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel)); + } +} |