diff options
231 files changed, 9524 insertions, 2733 deletions
diff --git a/Android.bp b/Android.bp index d4b15caf3047..4d781125f56a 100644 --- a/Android.bp +++ b/Android.bp @@ -248,6 +248,7 @@ java_library { "core/java/android/service/euicc/IGetEuiccInfoCallback.aidl", "core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl", "core/java/android/service/euicc/IGetOtaStatusCallback.aidl", + "core/java/android/service/euicc/IOtaStatusChangedCallback.aidl", "core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl", "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl", "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl", @@ -454,6 +455,8 @@ java_library { "telecomm/java/com/android/internal/telecom/IInCallService.aidl", "telecomm/java/com/android/internal/telecom/ITelecomService.aidl", "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl", + "telephony/java/android/telephony/data/IDataService.aidl", + "telephony/java/android/telephony/data/IDataServiceCallback.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsCallSessionListener.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl", @@ -461,8 +464,6 @@ java_library { "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl", - "telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl", - "telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl", "telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl", @@ -482,6 +483,8 @@ java_library { "telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl", "telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl", "telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl", + "telephony/java/com/android/ims/internal/IImsRegistration.aidl", + "telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl", "telephony/java/com/android/ims/internal/IImsRcsFeature.aidl", "telephony/java/com/android/ims/internal/IImsService.aidl", "telephony/java/com/android/ims/internal/IImsServiceController.aidl", @@ -509,7 +512,30 @@ java_library { "telephony/java/com/android/internal/telephony/ITelephony.aidl", "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl", "telephony/java/com/android/internal/telephony/IWapPushManager.aidl", + "telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl", "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl", + "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl", "wifi/java/android/net/wifi/IWifiManager.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl", @@ -595,6 +621,7 @@ java_library { "android.hardware.vibrator-V1.0-java-constants", "android.hardware.vibrator-V1.1-java-constants", "android.hardware.wifi-V1.0-java-constants", + "android.hardware.radio-V1.0-java", ], // Loaded with System.loadLibrary by android.view.textclassifier diff --git a/Android.mk b/Android.mk index 98775570a64b..7d5afcdd45b8 100644 --- a/Android.mk +++ b/Android.mk @@ -82,7 +82,7 @@ framework_base_android_test_runner_excluding_mock_src_files := \ # to document and check apis files_to_check_apis := \ $(call find-other-java-files, \ - legacy-test/src \ + test-base/src \ $(non_base_dirs) \ ) @@ -699,3 +699,4 @@ include $(call first-makefiles-under,$(LOCAL_PATH)) endif endif # ANDROID_BUILD_EMBEDDED + diff --git a/api/current.txt b/api/current.txt index c54447022f39..40452b763663 100644 --- a/api/current.txt +++ b/api/current.txt @@ -19873,6 +19873,13 @@ package android.icu.util { ctor public ICUUncheckedIOException(java.lang.String, java.lang.Throwable); } + public class IllformedLocaleException extends java.lang.RuntimeException { + ctor public IllformedLocaleException(); + ctor public IllformedLocaleException(java.lang.String); + ctor public IllformedLocaleException(java.lang.String, int); + method public int getErrorIndex(); + } + public class IndianCalendar extends android.icu.util.Calendar { ctor public IndianCalendar(); ctor public IndianCalendar(android.icu.util.TimeZone); @@ -19957,6 +19964,32 @@ package android.icu.util { field public static final int TAISHO; } + public final class LocaleData { + method public static android.icu.util.VersionInfo getCLDRVersion(); + method public java.lang.String getDelimiter(int); + method public static final android.icu.util.LocaleData getInstance(android.icu.util.ULocale); + method public static final android.icu.util.LocaleData getInstance(); + method public static final android.icu.util.LocaleData.MeasurementSystem getMeasurementSystem(android.icu.util.ULocale); + method public boolean getNoSubstitute(); + method public static final android.icu.util.LocaleData.PaperSize getPaperSize(android.icu.util.ULocale); + method public void setNoSubstitute(boolean); + field public static final int ALT_QUOTATION_END = 3; // 0x3 + field public static final int ALT_QUOTATION_START = 2; // 0x2 + field public static final int QUOTATION_END = 1; // 0x1 + field public static final int QUOTATION_START = 0; // 0x0 + } + + public static final class LocaleData.MeasurementSystem { + field public static final android.icu.util.LocaleData.MeasurementSystem SI; + field public static final android.icu.util.LocaleData.MeasurementSystem UK; + field public static final android.icu.util.LocaleData.MeasurementSystem US; + } + + public static final class LocaleData.PaperSize { + method public int getHeight(); + method public int getWidth(); + } + public class Measure { ctor public Measure(java.lang.Number, android.icu.util.MeasureUnit); method public java.lang.Number getNumber(); @@ -25781,12 +25814,18 @@ package android.net { } public final class IpSecManager { - method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; - method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; - method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; + method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; + method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + method public void applyTransportModeTransform(java.net.Socket, int, android.net.IpSecTransform) throws java.io.IOException; + method public void applyTransportModeTransform(java.net.DatagramSocket, int, android.net.IpSecTransform) throws java.io.IOException; + method public void applyTransportModeTransform(java.io.FileDescriptor, int, android.net.IpSecTransform) throws java.io.IOException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; - method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; + method public void removeTransportModeTransforms(java.net.Socket) throws java.io.IOException; + method public void removeTransportModeTransforms(java.net.DatagramSocket) throws java.io.IOException; + method public void removeTransportModeTransforms(java.io.FileDescriptor) throws java.io.IOException; + field public static final int DIRECTION_IN = 0; // 0x0 + field public static final int DIRECTION_OUT = 1; // 0x1 } public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException { @@ -25809,18 +25848,15 @@ package android.net { public final class IpSecTransform implements java.lang.AutoCloseable { method public void close(); - field public static final int DIRECTION_IN = 0; // 0x0 - field public static final int DIRECTION_OUT = 1; // 0x1 } public static class IpSecTransform.Builder { ctor public IpSecTransform.Builder(android.content.Context); - method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; - method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm); - method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm); - method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm); + method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(android.net.IpSecAlgorithm); + method public android.net.IpSecTransform.Builder setAuthentication(android.net.IpSecAlgorithm); + method public android.net.IpSecTransform.Builder setEncryption(android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int); - method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex); } public class LinkAddress implements android.os.Parcelable { @@ -25840,7 +25876,9 @@ package android.net { method public android.net.ProxyInfo getHttpProxy(); method public java.lang.String getInterfaceName(); method public java.util.List<android.net.LinkAddress> getLinkAddresses(); + method public java.lang.String getPrivateDnsServerName(); method public java.util.List<android.net.RouteInfo> getRoutes(); + method public boolean isPrivateDnsActive(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR; } @@ -25903,10 +25941,10 @@ package android.net { } public final class MacAddress implements android.os.Parcelable { - method public int addressType(); method public int describeContents(); method public static android.net.MacAddress fromBytes(byte[]); method public static android.net.MacAddress fromString(java.lang.String); + method public int getAddressType(); method public boolean isLocallyAssigned(); method public byte[] toByteArray(); method public java.lang.String toOuiString(); @@ -25916,7 +25954,6 @@ package android.net { field public static final int TYPE_BROADCAST = 3; // 0x3 field public static final int TYPE_MULTICAST = 2; // 0x2 field public static final int TYPE_UNICAST = 1; // 0x1 - field public static final int TYPE_UNKNOWN = 0; // 0x0 } public class MailTo { @@ -35516,7 +35553,7 @@ package android.provider { public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final java.lang.String APN = "apn"; field public static final java.lang.String AUTH_TYPE = "authtype"; - field public static final java.lang.String BEARER = "bearer"; + field public static final deprecated java.lang.String BEARER = "bearer"; field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String CURRENT = "current"; @@ -35529,6 +35566,7 @@ package android.provider { field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data"; field public static final java.lang.String MVNO_TYPE = "mvno_type"; field public static final java.lang.String NAME = "name"; + field public static final java.lang.String NETWORK_TYPE_BITMASK = "network_type_bitmask"; field public static final java.lang.String NUMERIC = "numeric"; field public static final java.lang.String PASSWORD = "password"; field public static final java.lang.String PORT = "port"; @@ -37410,6 +37448,7 @@ package android.service.carrier { public class CarrierIdentifier implements android.os.Parcelable { ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); + ctor public CarrierIdentifier(byte[], java.lang.String, java.lang.String); method public int describeContents(); method public java.lang.String getGid1(); method public java.lang.String getGid2(); @@ -39428,12 +39467,15 @@ package android.telecom { method public final void addConference(android.telecom.Conference); method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection); method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); + method public final void connectionServiceFocusReleased(); method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final java.util.Collection<android.telecom.Conference> getAllConferences(); method public final java.util.Collection<android.telecom.Connection> getAllConnections(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); + method public void onConnectionServiceFocusGained(); + method public void onConnectionServiceFocusLost(); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); @@ -39833,6 +39875,113 @@ package android.telecom { package android.telephony { + public final class AccessNetworkConstants { + ctor public AccessNetworkConstants(); + } + + public static final class AccessNetworkConstants.AccessNetworkType { + ctor public AccessNetworkConstants.AccessNetworkType(); + field public static final int CDMA2000 = 4; // 0x4 + field public static final int EUTRAN = 3; // 0x3 + field public static final int GERAN = 1; // 0x1 + field public static final int IWLAN = 5; // 0x5 + field public static final int UTRAN = 2; // 0x2 + } + + public static final class AccessNetworkConstants.EutranBand { + ctor public AccessNetworkConstants.EutranBand(); + field public static final int BAND_1 = 1; // 0x1 + field public static final int BAND_10 = 10; // 0xa + field public static final int BAND_11 = 11; // 0xb + field public static final int BAND_12 = 12; // 0xc + field public static final int BAND_13 = 13; // 0xd + field public static final int BAND_14 = 14; // 0xe + field public static final int BAND_17 = 17; // 0x11 + field public static final int BAND_18 = 18; // 0x12 + field public static final int BAND_19 = 19; // 0x13 + field public static final int BAND_2 = 2; // 0x2 + field public static final int BAND_20 = 20; // 0x14 + field public static final int BAND_21 = 21; // 0x15 + field public static final int BAND_22 = 22; // 0x16 + field public static final int BAND_23 = 23; // 0x17 + field public static final int BAND_24 = 24; // 0x18 + field public static final int BAND_25 = 25; // 0x19 + field public static final int BAND_26 = 26; // 0x1a + field public static final int BAND_27 = 27; // 0x1b + field public static final int BAND_28 = 28; // 0x1c + field public static final int BAND_3 = 3; // 0x3 + field public static final int BAND_30 = 30; // 0x1e + field public static final int BAND_31 = 31; // 0x1f + field public static final int BAND_33 = 33; // 0x21 + field public static final int BAND_34 = 34; // 0x22 + field public static final int BAND_35 = 35; // 0x23 + field public static final int BAND_36 = 36; // 0x24 + field public static final int BAND_37 = 37; // 0x25 + field public static final int BAND_38 = 38; // 0x26 + field public static final int BAND_39 = 39; // 0x27 + field public static final int BAND_4 = 4; // 0x4 + field public static final int BAND_40 = 40; // 0x28 + field public static final int BAND_41 = 41; // 0x29 + field public static final int BAND_42 = 42; // 0x2a + field public static final int BAND_43 = 43; // 0x2b + field public static final int BAND_44 = 44; // 0x2c + field public static final int BAND_45 = 45; // 0x2d + field public static final int BAND_46 = 46; // 0x2e + field public static final int BAND_47 = 47; // 0x2f + field public static final int BAND_48 = 48; // 0x30 + field public static final int BAND_5 = 5; // 0x5 + field public static final int BAND_6 = 6; // 0x6 + field public static final int BAND_65 = 65; // 0x41 + field public static final int BAND_66 = 66; // 0x42 + field public static final int BAND_68 = 68; // 0x44 + field public static final int BAND_7 = 7; // 0x7 + field public static final int BAND_70 = 70; // 0x46 + field public static final int BAND_8 = 8; // 0x8 + field public static final int BAND_9 = 9; // 0x9 + } + + public static final class AccessNetworkConstants.GeranBand { + ctor public AccessNetworkConstants.GeranBand(); + field public static final int BAND_450 = 3; // 0x3 + field public static final int BAND_480 = 4; // 0x4 + field public static final int BAND_710 = 5; // 0x5 + field public static final int BAND_750 = 6; // 0x6 + field public static final int BAND_850 = 8; // 0x8 + field public static final int BAND_DCS1800 = 12; // 0xc + field public static final int BAND_E900 = 10; // 0xa + field public static final int BAND_ER900 = 14; // 0xe + field public static final int BAND_P900 = 9; // 0x9 + field public static final int BAND_PCS1900 = 13; // 0xd + field public static final int BAND_R900 = 11; // 0xb + field public static final int BAND_T380 = 1; // 0x1 + field public static final int BAND_T410 = 2; // 0x2 + field public static final int BAND_T810 = 7; // 0x7 + } + + public static final class AccessNetworkConstants.UtranBand { + ctor public AccessNetworkConstants.UtranBand(); + field public static final int BAND_1 = 1; // 0x1 + field public static final int BAND_10 = 10; // 0xa + field public static final int BAND_11 = 11; // 0xb + field public static final int BAND_12 = 12; // 0xc + field public static final int BAND_13 = 13; // 0xd + field public static final int BAND_14 = 14; // 0xe + field public static final int BAND_19 = 19; // 0x13 + field public static final int BAND_2 = 2; // 0x2 + field public static final int BAND_20 = 20; // 0x14 + field public static final int BAND_21 = 21; // 0x15 + field public static final int BAND_22 = 22; // 0x16 + field public static final int BAND_25 = 25; // 0x19 + field public static final int BAND_26 = 26; // 0x1a + field public static final int BAND_3 = 3; // 0x3 + field public static final int BAND_4 = 4; // 0x4 + field public static final int BAND_5 = 5; // 0x5 + field public static final int BAND_6 = 6; // 0x6 + field public static final int BAND_7 = 7; // 0x7 + field public static final int BAND_8 = 8; // 0x8 + field public static final int BAND_9 = 9; // 0x9 + } + public class CarrierConfigManager { method public android.os.PersistableBundle getConfig(); method public android.os.PersistableBundle getConfigForSubId(int); @@ -39981,8 +40130,13 @@ package android.telephony { field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; } - public final class CellIdentityCdma implements android.os.Parcelable { + public abstract class CellIdentity implements android.os.Parcelable { method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR; + } + + public final class CellIdentityCdma extends android.telephony.CellIdentity { method public int getBasestationId(); method public int getLatitude(); method public int getLongitude(); @@ -39994,8 +40148,7 @@ package android.telephony { field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR; } - public final class CellIdentityGsm implements android.os.Parcelable { - method public int describeContents(); + public final class CellIdentityGsm extends android.telephony.CellIdentity { method public int getArfcn(); method public int getBsic(); method public int getCid(); @@ -40012,8 +40165,7 @@ package android.telephony { field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR; } - public final class CellIdentityLte implements android.os.Parcelable { - method public int describeContents(); + public final class CellIdentityLte extends android.telephony.CellIdentity { method public int getCi(); method public int getEarfcn(); method public deprecated int getMcc(); @@ -40029,8 +40181,17 @@ package android.telephony { field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR; } - public final class CellIdentityWcdma implements android.os.Parcelable { - method public int describeContents(); + public final class CellIdentityTdscdma extends android.telephony.CellIdentity { + method public int getCid(); + method public int getCpid(); + method public int getLac(); + method public java.lang.String getMccStr(); + method public java.lang.String getMncStr(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR; + } + + public final class CellIdentityWcdma extends android.telephony.CellIdentity { method public int getCid(); method public int getLac(); method public deprecated int getMcc(); @@ -40331,6 +40492,7 @@ package android.telephony { method public void onServiceStateChanged(android.telephony.ServiceState); method public deprecated void onSignalStrengthChanged(int); method public void onSignalStrengthsChanged(android.telephony.SignalStrength); + method public void onUserMobileDataStateChanged(boolean); 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 @@ -40342,6 +40504,7 @@ package android.telephony { field public static final int LISTEN_SERVICE_STATE = 1; // 0x1 field public static final deprecated 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 } public final class RadioAccessSpecifier implements android.os.Parcelable { @@ -40354,111 +40517,6 @@ package android.telephony { field public static final android.os.Parcelable.Creator<android.telephony.RadioAccessSpecifier> CREATOR; } - public final class RadioNetworkConstants { - ctor public RadioNetworkConstants(); - } - - public static final class RadioNetworkConstants.EutranBands { - ctor public RadioNetworkConstants.EutranBands(); - field public static final int BAND_1 = 1; // 0x1 - field public static final int BAND_10 = 10; // 0xa - field public static final int BAND_11 = 11; // 0xb - field public static final int BAND_12 = 12; // 0xc - field public static final int BAND_13 = 13; // 0xd - field public static final int BAND_14 = 14; // 0xe - field public static final int BAND_17 = 17; // 0x11 - field public static final int BAND_18 = 18; // 0x12 - field public static final int BAND_19 = 19; // 0x13 - field public static final int BAND_2 = 2; // 0x2 - field public static final int BAND_20 = 20; // 0x14 - field public static final int BAND_21 = 21; // 0x15 - field public static final int BAND_22 = 22; // 0x16 - field public static final int BAND_23 = 23; // 0x17 - field public static final int BAND_24 = 24; // 0x18 - field public static final int BAND_25 = 25; // 0x19 - field public static final int BAND_26 = 26; // 0x1a - field public static final int BAND_27 = 27; // 0x1b - field public static final int BAND_28 = 28; // 0x1c - field public static final int BAND_3 = 3; // 0x3 - field public static final int BAND_30 = 30; // 0x1e - field public static final int BAND_31 = 31; // 0x1f - field public static final int BAND_33 = 33; // 0x21 - field public static final int BAND_34 = 34; // 0x22 - field public static final int BAND_35 = 35; // 0x23 - field public static final int BAND_36 = 36; // 0x24 - field public static final int BAND_37 = 37; // 0x25 - field public static final int BAND_38 = 38; // 0x26 - field public static final int BAND_39 = 39; // 0x27 - field public static final int BAND_4 = 4; // 0x4 - field public static final int BAND_40 = 40; // 0x28 - field public static final int BAND_41 = 41; // 0x29 - field public static final int BAND_42 = 42; // 0x2a - field public static final int BAND_43 = 43; // 0x2b - field public static final int BAND_44 = 44; // 0x2c - field public static final int BAND_45 = 45; // 0x2d - field public static final int BAND_46 = 46; // 0x2e - field public static final int BAND_47 = 47; // 0x2f - field public static final int BAND_48 = 48; // 0x30 - field public static final int BAND_5 = 5; // 0x5 - field public static final int BAND_6 = 6; // 0x6 - field public static final int BAND_65 = 65; // 0x41 - field public static final int BAND_66 = 66; // 0x42 - field public static final int BAND_68 = 68; // 0x44 - field public static final int BAND_7 = 7; // 0x7 - field public static final int BAND_70 = 70; // 0x46 - field public static final int BAND_8 = 8; // 0x8 - field public static final int BAND_9 = 9; // 0x9 - } - - public static final class RadioNetworkConstants.GeranBands { - ctor public RadioNetworkConstants.GeranBands(); - field public static final int BAND_450 = 3; // 0x3 - field public static final int BAND_480 = 4; // 0x4 - field public static final int BAND_710 = 5; // 0x5 - field public static final int BAND_750 = 6; // 0x6 - field public static final int BAND_850 = 8; // 0x8 - field public static final int BAND_DCS1800 = 12; // 0xc - field public static final int BAND_E900 = 10; // 0xa - field public static final int BAND_ER900 = 14; // 0xe - field public static final int BAND_P900 = 9; // 0x9 - field public static final int BAND_PCS1900 = 13; // 0xd - field public static final int BAND_R900 = 11; // 0xb - field public static final int BAND_T380 = 1; // 0x1 - field public static final int BAND_T410 = 2; // 0x2 - field public static final int BAND_T810 = 7; // 0x7 - } - - public static final class RadioNetworkConstants.RadioAccessNetworks { - ctor public RadioNetworkConstants.RadioAccessNetworks(); - field public static final int EUTRAN = 3; // 0x3 - field public static final int GERAN = 1; // 0x1 - field public static final int UTRAN = 2; // 0x2 - } - - public static final class RadioNetworkConstants.UtranBands { - ctor public RadioNetworkConstants.UtranBands(); - field public static final int BAND_1 = 1; // 0x1 - field public static final int BAND_10 = 10; // 0xa - field public static final int BAND_11 = 11; // 0xb - field public static final int BAND_12 = 12; // 0xc - field public static final int BAND_13 = 13; // 0xd - field public static final int BAND_14 = 14; // 0xe - field public static final int BAND_19 = 19; // 0x13 - field public static final int BAND_2 = 2; // 0x2 - field public static final int BAND_20 = 20; // 0x14 - field public static final int BAND_21 = 21; // 0x15 - field public static final int BAND_22 = 22; // 0x16 - field public static final int BAND_25 = 25; // 0x19 - field public static final int BAND_26 = 26; // 0x1a - field public static final int BAND_3 = 3; // 0x3 - field public static final int BAND_4 = 4; // 0x4 - field public static final int BAND_5 = 5; // 0x5 - field public static final int BAND_6 = 6; // 0x6 - field public static final int BAND_7 = 7; // 0x7 - field public static final int BAND_8 = 8; // 0x8 - field public static final int BAND_9 = 9; // 0x9 - } - public class ServiceState implements android.os.Parcelable { ctor public ServiceState(); ctor public ServiceState(android.telephony.ServiceState); @@ -40466,11 +40524,13 @@ package android.telephony { method protected void copyFrom(android.telephony.ServiceState); method public int describeContents(); method public boolean getIsManualSelection(); + method public int getNetworkId(); method public java.lang.String getOperatorAlphaLong(); method public java.lang.String getOperatorAlphaShort(); method public java.lang.String getOperatorNumeric(); method public boolean getRoaming(); method public int getState(); + method public int getSystemId(); method public void setIsManualSelection(boolean); method public void setOperatorName(java.lang.String, java.lang.String, java.lang.String); method public void setRoaming(boolean); @@ -40483,6 +40543,7 @@ package android.telephony { field public static final int STATE_IN_SERVICE = 0; // 0x0 field public static final int STATE_OUT_OF_SERVICE = 1; // 0x1 field public static final int STATE_POWER_OFF = 3; // 0x3 + field public static final int UNKNOWN_ID = -1; // 0xffffffff } public class SignalStrength implements android.os.Parcelable { @@ -40713,6 +40774,8 @@ package android.telephony { method public int getSimState(); method public int getSimState(int); method public java.lang.String getSubscriberId(); + method public int getSubscriptionCarrierId(); + method public java.lang.String getSubscriptionCarrierName(); method public java.lang.String getVisualVoicemailPackageName(); method public java.lang.String getVoiceMailAlphaTag(); method public java.lang.String getVoiceMailNumber(); @@ -40727,11 +40790,12 @@ package android.telephony { method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String); method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String); method public boolean isConcurrentVoiceAndDataSupported(); - method public boolean isDataEnabled(); + method public deprecated boolean isDataEnabled(); method public boolean isHearingAidCompatibilitySupported(); method public boolean isNetworkRoaming(); method public boolean isSmsCapable(); method public deprecated boolean isTtyModeSupported(); + method public boolean isUserMobileDataEnabled(); method public boolean isVoiceCapable(); method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle); method public boolean isWorldPhone(); @@ -40741,12 +40805,13 @@ package android.telephony { method public java.lang.String sendEnvelopeWithStatus(java.lang.String); method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent); - method public void setDataEnabled(boolean); + method public deprecated void setDataEnabled(boolean); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); method public void setNetworkSelectionModeAutomatic(); method public boolean setNetworkSelectionModeManual(java.lang.String, boolean); method public boolean setOperatorBrandOverride(java.lang.String); method public boolean setPreferredNetworkTypeToGlobal(); + method public void setUserMobileDataEnabled(boolean); method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings); method public boolean setVoiceMailNumber(java.lang.String, java.lang.String); method public deprecated void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri); @@ -40755,6 +40820,7 @@ package android.telephony { field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; + field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 field public static final int APPTYPE_RUIM = 3; // 0x3 @@ -40775,6 +40841,8 @@ package android.telephony { field public static final int DATA_DISCONNECTED = 0; // 0x0 field public static final int DATA_SUSPENDED = 3; // 0x3 field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT"; + field public static final java.lang.String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID"; + field public static final java.lang.String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS"; field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number"; field public static final java.lang.String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH"; @@ -40785,6 +40853,7 @@ package android.telephony { field public static final java.lang.String EXTRA_STATE_IDLE; field public static final java.lang.String EXTRA_STATE_OFFHOOK; field public static final java.lang.String EXTRA_STATE_RINGING; + field public static final java.lang.String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID"; field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU"; field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 @@ -40820,6 +40889,7 @@ package android.telephony { field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3 field public static final int SIM_STATE_READY = 5; // 0x5 field public static final int SIM_STATE_UNKNOWN = 0; // 0x0 + field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm"; @@ -40907,6 +40977,78 @@ package android.telephony.cdma { } +package android.telephony.data { + + public class ApnSetting implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getApnName(); + method public int getAuthType(); + method public java.lang.String getEntryName(); + method public int getId(); + method public int getMmsPort(); + method public java.net.InetAddress getMmsProxy(); + method public java.net.URL getMmsc(); + method public java.lang.String getMvnoType(); + method public java.lang.String getOperatorNumeric(); + method public java.lang.String getPassword(); + method public int getPort(); + method public java.lang.String getProtocol(); + method public java.net.InetAddress getProxy(); + method public java.lang.String getRoamingProtocol(); + method public java.util.List<java.lang.String> getTypes(); + method public java.lang.String getUser(); + method public boolean isEnabled(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int AUTH_TYPE_CHAP = 2; // 0x2 + field public static final int AUTH_TYPE_NONE = 0; // 0x0 + field public static final int AUTH_TYPE_PAP = 1; // 0x1 + field public static final int AUTH_TYPE_PAP_OR_CHAP = 3; // 0x3 + field public static final android.os.Parcelable.Creator<android.telephony.data.ApnSetting> CREATOR; + field public static final java.lang.String MVNO_TYPE_GID = "gid"; + field public static final java.lang.String MVNO_TYPE_ICCID = "iccid"; + field public static final java.lang.String MVNO_TYPE_IMSI = "imsi"; + field public static final java.lang.String MVNO_TYPE_SPN = "spn"; + field public static final java.lang.String PROTOCOL_IP = "IP"; + field public static final java.lang.String PROTOCOL_IPV4V6 = "IPV4V6"; + field public static final java.lang.String PROTOCOL_IPV6 = "IPV6"; + field public static final java.lang.String PROTOCOL_PPP = "PPP"; + field public static final java.lang.String TYPE_ALL = "*"; + field public static final java.lang.String TYPE_CBS = "cbs"; + field public static final java.lang.String TYPE_DEFAULT = "default"; + field public static final java.lang.String TYPE_DUN = "dun"; + field public static final java.lang.String TYPE_EMERGENCY = "emergency"; + field public static final java.lang.String TYPE_FOTA = "fota"; + field public static final java.lang.String TYPE_HIPRI = "hipri"; + field public static final java.lang.String TYPE_IA = "ia"; + field public static final java.lang.String TYPE_IMS = "ims"; + field public static final java.lang.String TYPE_MMS = "mms"; + field public static final java.lang.String TYPE_SUPL = "supl"; + } + + public static class ApnSetting.Builder { + ctor public ApnSetting.Builder(); + method public android.telephony.data.ApnSetting build(); + method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setAuthType(int); + method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean); + method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setId(int); + method public android.telephony.data.ApnSetting.Builder setMmsPort(int); + method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL); + method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setPort(int); + method public android.telephony.data.ApnSetting.Builder setProtocol(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setProxy(java.net.InetAddress); + method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(java.lang.String); + method public android.telephony.data.ApnSetting.Builder setTypes(java.util.List<java.lang.String>); + method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String); + } + +} + package android.telephony.gsm { public class GsmCellLocation extends android.telephony.CellLocation { diff --git a/api/system-current.txt b/api/system-current.txt index 6ee98a7c0b9b..282dfaa6a25f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -628,6 +628,9 @@ package android.bluetooth { method public boolean isEncrypted(); method public boolean removeBond(); method public boolean setPhonebookAccessPermission(int); + field public static final int ACCESS_ALLOWED = 1; // 0x1 + field public static final int ACCESS_REJECTED = 2; // 0x2 + field public static final int ACCESS_UNKNOWN = 0; // 0x0 } public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { @@ -636,6 +639,11 @@ package android.bluetooth { method public boolean setPriority(android.bluetooth.BluetoothDevice, int); } + public abstract interface BluetoothProfile { + field public static final int PRIORITY_OFF = 0; // 0x0 + field public static final int PRIORITY_ON = 100; // 0x64 + } + } package android.bluetooth.le { @@ -4039,7 +4047,7 @@ package android.telephony { method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); method public boolean needsOtaServiceProvisioning(); method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); - method public void setDataEnabled(int, boolean); + method public deprecated void setDataEnabled(int, boolean); method public boolean setRadio(boolean); method public boolean setRadioPower(boolean); method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean); @@ -4068,11 +4076,11 @@ package android.telephony { package android.telephony.data { public final class DataCallResponse implements android.os.Parcelable { - ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.telephony.data.InterfaceAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int); + ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.net.LinkAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int); ctor public DataCallResponse(android.os.Parcel); method public int describeContents(); method public int getActive(); - method public java.util.List<android.telephony.data.InterfaceAddress> getAddresses(); + method public java.util.List<android.net.LinkAddress> getAddresses(); method public int getCallId(); method public java.util.List<java.net.InetAddress> getDnses(); method public java.util.List<java.net.InetAddress> getGateways(); @@ -4115,15 +4123,36 @@ package android.telephony.data { field public static final int TYPE_COMMON = 0; // 0x0 } - public final class InterfaceAddress implements android.os.Parcelable { - ctor public InterfaceAddress(java.net.InetAddress, int); - ctor public InterfaceAddress(java.lang.String, int) throws java.net.UnknownHostException; - ctor public InterfaceAddress(android.os.Parcel); - method public int describeContents(); - method public java.net.InetAddress getAddress(); - method public int getNetworkPrefixLength(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.telephony.data.InterfaceAddress> CREATOR; + public abstract class DataService extends android.app.Service { + method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int); + field public static final java.lang.String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID"; + field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService"; + } + + public class DataService.DataServiceProvider { + ctor public DataService.DataServiceProvider(int); + method public void deactivateDataCall(int, boolean, boolean, android.telephony.data.DataServiceCallback); + method public void getDataCallList(android.telephony.data.DataServiceCallback); + method public final int getSlotId(); + method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); + method protected void onDestroy(); + method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, android.telephony.data.DataServiceCallback); + method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, android.telephony.data.DataServiceCallback); + method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, boolean, android.net.LinkProperties, android.telephony.data.DataServiceCallback); + } + + public class DataServiceCallback { + method public void onDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); + method public void onDeactivateDataCallComplete(int); + method public void onGetDataCallListComplete(int, java.util.List<android.telephony.data.DataCallResponse>); + method public void onSetDataProfileComplete(int); + method public void onSetInitialAttachApnComplete(int); + method public void onSetupDataCallComplete(int, android.telephony.data.DataCallResponse); + field public static final int RESULT_ERROR_BUSY = 3; // 0x3 + field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4 + field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2 + field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1 + field public static final int RESULT_SUCCESS = 0; // 0x0 } } diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java index adbe9d015626..34f6d7de0cc9 100644 --- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java +++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java @@ -18,6 +18,7 @@ package com.android.commands.svc; import android.content.Context; import android.hardware.usb.IUsbManager; +import android.hardware.usb.UsbManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -38,6 +39,9 @@ public class UsbCommand extends Svc.Command { + "\n" + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n" + " Set the current usb function and optionally the data lock state.\n\n" + + " svc usb setScreenUnlockedFunctions [function]\n" + + " Sets the functions which, if the device was charging," + + " become current on screen unlock.\n" + " svc usb getFunction\n" + " Gets the list of currently enabled functions\n"; } @@ -62,6 +66,16 @@ public class UsbCommand extends Svc.Command { } else if ("getFunction".equals(args[1])) { System.err.println(SystemProperties.get("sys.usb.config")); return; + } else if ("setScreenUnlockedFunctions".equals(args[1])) { + IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( + Context.USB_SERVICE)); + try { + usbMgr.setScreenUnlockedFunctions((args.length >= 3 ? args[2] : + UsbManager.USB_FUNCTION_NONE)); + } catch (RemoteException e) { + System.err.println("Error communicating with UsbManager: " + e); + } + return; } } System.err.println(longHelp()); diff --git a/core/java/Android.bp b/core/java/Android.bp index 42b0f6bad0ae..fb27f74211fb 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -2,3 +2,8 @@ filegroup { name: "IKeyAttestationApplicationIdProvider.aidl", srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"], } + +filegroup { + name: "IDropBoxManagerService.aidl", + srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"], +} diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c8d983933fc6..f2160e192623 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -268,4 +268,11 @@ public abstract class ActivityManagerInternal { * @param token The IApplicationToken for the activity */ public abstract void setFocusedActivity(IBinder token); + + public interface ScreenObserver { + public void onAwakeStateChanged(boolean isAwake); + public void onKeyguardStateChanged(boolean isShowing); + } + + public abstract void registerScreenObserver(ScreenObserver observer); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 45f7eba2af02..2ecd3120345d 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -366,7 +366,7 @@ public final class ActivityThread { ActivityInfo activityInfo; CompatibilityInfo compatInfo; - LoadedApk packageInfo; + LoadedApk loadedApk; List<ResultInfo> pendingResults; List<ReferrerIntent> pendingIntents; @@ -542,7 +542,7 @@ public final class ActivityThread { } static final class AppBindData { - LoadedApk info; + LoadedApk loadedApk; String processName; ApplicationInfo appInfo; List<ProviderInfo> providers; @@ -1584,7 +1584,7 @@ public final class ActivityThread { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; - r.packageInfo = getPackageInfoNoCheck( + r.loadedApk = getLoadedApkNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -1832,9 +1832,11 @@ public final class ActivityThread { handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1, (IVoiceInteractor) ((SomeArgs) msg.obj).arg2); break; - case ATTACH_AGENT: - handleAttachAgent((String) msg.obj); + case ATTACH_AGENT: { + Application app = getApplication(); + handleAttachAgent((String) msg.obj, app != null ? app.mLoadedApk : null); break; + } case APPLICATION_INFO_CHANGED: mUpdatingSystemConfig = true; try { @@ -1971,13 +1973,13 @@ public final class ActivityThread { return mH; } - public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo, - int flags) { - return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId()); + public final LoadedApk getLoadedApkForPackageName(String packageName, + CompatibilityInfo compatInfo, int flags) { + return getLoadedApkForPackageName(packageName, compatInfo, flags, UserHandle.myUserId()); } - public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo, - int flags, int userId) { + public final LoadedApk getLoadedApkForPackageName(String packageName, + CompatibilityInfo compatInfo, int flags, int userId) { final boolean differentUser = (UserHandle.myUserId() != userId); synchronized (mResourcesManager) { WeakReference<LoadedApk> ref; @@ -1990,13 +1992,13 @@ public final class ActivityThread { ref = mResourcePackages.get(packageName); } - LoadedApk packageInfo = ref != null ? ref.get() : null; - //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo); - //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir - // + ": " + packageInfo.mResources.getAssets().isUpToDate()); - if (packageInfo != null && (packageInfo.mResources == null - || packageInfo.mResources.getAssets().isUpToDate())) { - if (packageInfo.isSecurityViolation() + LoadedApk loadedApk = ref != null ? ref.get() : null; + //Slog.i(TAG, "getLoadedApkForPackageName " + packageName + ": " + loadedApk); + //if (loadedApk != null) Slog.i(TAG, "isUptoDate " + loadedApk.mResDir + // + ": " + loadedApk.mResources.getAssets().isUpToDate()); + if (loadedApk != null && (loadedApk.mResources == null + || loadedApk.mResources.getAssets().isUpToDate())) { + if (loadedApk.isSecurityViolation() && (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) { throw new SecurityException( "Requesting code from " + packageName @@ -2004,7 +2006,7 @@ public final class ActivityThread { + mBoundApplication.processName + "/" + mBoundApplication.appInfo.uid); } - return packageInfo; + return loadedApk; } } @@ -2019,13 +2021,13 @@ public final class ActivityThread { } if (ai != null) { - return getPackageInfo(ai, compatInfo, flags); + return getLoadedApk(ai, compatInfo, flags); } return null; } - public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo, + public final LoadedApk getLoadedApk(ApplicationInfo ai, CompatibilityInfo compatInfo, int flags) { boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0; boolean securityViolation = includeCode && ai.uid != 0 @@ -2047,16 +2049,16 @@ public final class ActivityThread { throw new SecurityException(msg); } } - return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode, + return getLoadedApk(ai, compatInfo, null, securityViolation, includeCode, registerPackage); } - public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, + public final LoadedApk getLoadedApkNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo) { - return getPackageInfo(ai, compatInfo, null, false, true, false); + return getLoadedApk(ai, compatInfo, null, false, true, false); } - public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) { + public final LoadedApk peekLoadedApk(String packageName, boolean includeCode) { synchronized (mResourcesManager) { WeakReference<LoadedApk> ref; if (includeCode) { @@ -2068,7 +2070,7 @@ public final class ActivityThread { } } - private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, + private LoadedApk getLoadedApk(ApplicationInfo aInfo, CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode, boolean registerPackage) { final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid)); @@ -2083,35 +2085,35 @@ public final class ActivityThread { ref = mResourcePackages.get(aInfo.packageName); } - LoadedApk packageInfo = ref != null ? ref.get() : null; - if (packageInfo == null || (packageInfo.mResources != null - && !packageInfo.mResources.getAssets().isUpToDate())) { + LoadedApk loadedApk = ref != null ? ref.get() : null; + if (loadedApk == null || (loadedApk.mResources != null + && !loadedApk.mResources.getAssets().isUpToDate())) { if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package " : "Loading resource-only package ") + aInfo.packageName + " (in " + (mBoundApplication != null ? mBoundApplication.processName : null) + ")"); - packageInfo = + loadedApk = new LoadedApk(this, aInfo, compatInfo, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage); if (mSystemThread && "android".equals(aInfo.packageName)) { - packageInfo.installSystemApplicationInfo(aInfo, - getSystemContext().mPackageInfo.getClassLoader()); + loadedApk.installSystemApplicationInfo(aInfo, + getSystemContext().mLoadedApk.getClassLoader()); } if (differentUser) { // Caching not supported across users } else if (includeCode) { mPackages.put(aInfo.packageName, - new WeakReference<LoadedApk>(packageInfo)); + new WeakReference<LoadedApk>(loadedApk)); } else { mResourcePackages.put(aInfo.packageName, - new WeakReference<LoadedApk>(packageInfo)); + new WeakReference<LoadedApk>(loadedApk)); } } - return packageInfo; + return loadedApk; } } @@ -2645,8 +2647,8 @@ public final class ActivityThread { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; - if (r.packageInfo == null) { - r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, + if (r.loadedApk == null) { + r.loadedApk = getLoadedApk(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } @@ -2683,15 +2685,15 @@ public final class ActivityThread { } try { - Application app = r.packageInfo.makeApplication(false, mInstrumentation); + Application app = r.loadedApk.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() - + ", pkg=" + r.packageInfo.getPackageName() + + ", pkg=" + r.loadedApk.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() - + ", dir=" + r.packageInfo.getAppDir()); + + ", dir=" + r.loadedApk.getAppDir()); if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); @@ -2809,7 +2811,7 @@ public final class ActivityThread { } ContextImpl appContext = ContextImpl.createActivityContext( - this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig); + this, r.loadedApk, r.activityInfo, r.token, displayId, r.overrideConfig); final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); // For debugging purposes, if the activity's package name contains the value of @@ -2817,7 +2819,7 @@ public final class ActivityThread { // its content on a secondary display if there is one. String pkgName = SystemProperties.get("debug.second-display.pkg"); if (pkgName != null && !pkgName.isEmpty() - && r.packageInfo.mPackageName.contains(pkgName)) { + && r.loadedApk.mPackageName.contains(pkgName)) { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { Display display = @@ -3119,11 +3121,23 @@ public final class ActivityThread { } } - static final void handleAttachAgent(String agent) { + private static boolean attemptAttachAgent(String agent, ClassLoader classLoader) { try { - VMDebug.attachAgent(agent); + VMDebug.attachAgent(agent, classLoader); + return true; } catch (IOException e) { - Slog.e(TAG, "Attaching agent failed: " + agent); + Slog.e(TAG, "Attaching agent with " + classLoader + " failed: " + agent); + return false; + } + } + + static void handleAttachAgent(String agent, LoadedApk loadedApk) { + ClassLoader classLoader = loadedApk != null ? loadedApk.getClassLoader() : null; + if (attemptAttachAgent(agent, classLoader)) { + return; + } + if (classLoader != null) { + attemptAttachAgent(agent, null); } } @@ -3145,7 +3159,7 @@ public final class ActivityThread { String component = data.intent.getComponent().getClassName(); - LoadedApk packageInfo = getPackageInfoNoCheck( + LoadedApk loadedApk = getLoadedApkNoCheck( data.info.applicationInfo, data.compatInfo); IActivityManager mgr = ActivityManager.getService(); @@ -3154,7 +3168,7 @@ public final class ActivityThread { BroadcastReceiver receiver; ContextImpl context; try { - app = packageInfo.makeApplication(false, mInstrumentation); + app = loadedApk.makeApplication(false, mInstrumentation); context = (ContextImpl) app.getBaseContext(); if (data.info.splitName != null) { context = (ContextImpl) context.createContextForSplit(data.info.splitName); @@ -3178,9 +3192,9 @@ public final class ActivityThread { TAG, "Performing receive of " + data.intent + ": app=" + app + ", appName=" + app.getPackageName() - + ", pkg=" + packageInfo.getPackageName() + + ", pkg=" + loadedApk.getPackageName() + ", comp=" + data.intent.getComponent().toShortString() - + ", dir=" + packageInfo.getAppDir()); + + ", dir=" + loadedApk.getAppDir()); sCurrentBroadcastIntent.set(data.intent); receiver.setPendingResult(data); @@ -3225,8 +3239,8 @@ public final class ActivityThread { unscheduleGcIdler(); // instantiate the BackupAgent class named in the manifest - LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); - String packageName = packageInfo.mPackageName; + LoadedApk loadedApk = getLoadedApkNoCheck(data.appInfo, data.compatInfo); + String packageName = loadedApk.mPackageName; if (packageName == null) { Slog.d(TAG, "Asked to create backup agent for nonexistent package"); return; @@ -3252,11 +3266,11 @@ public final class ActivityThread { try { if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname); - java.lang.ClassLoader cl = packageInfo.getClassLoader(); + java.lang.ClassLoader cl = loadedApk.getClassLoader(); agent = (BackupAgent) cl.loadClass(classname).newInstance(); // set up the agent's context - ContextImpl context = ContextImpl.createAppContext(this, packageInfo); + ContextImpl context = ContextImpl.createAppContext(this, loadedApk); context.setOuterContext(agent); agent.attach(context); @@ -3292,8 +3306,8 @@ public final class ActivityThread { private void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); - LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); - String packageName = packageInfo.mPackageName; + LoadedApk loadedApk = getLoadedApkNoCheck(data.appInfo, data.compatInfo); + String packageName = loadedApk.mPackageName; BackupAgent agent = mBackupAgents.get(packageName); if (agent != null) { try { @@ -3313,11 +3327,11 @@ public final class ActivityThread { // we are back active so skip it. unscheduleGcIdler(); - LoadedApk packageInfo = getPackageInfoNoCheck( + LoadedApk loadedApk = getLoadedApkNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { - java.lang.ClassLoader cl = packageInfo.getClassLoader(); + java.lang.ClassLoader cl = loadedApk.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { @@ -3330,10 +3344,10 @@ public final class ActivityThread { try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); - ContextImpl context = ContextImpl.createAppContext(this, packageInfo); + ContextImpl context = ContextImpl.createAppContext(this, loadedApk); context.setOuterContext(service); - Application app = packageInfo.makeApplication(false, mInstrumentation); + Application app = loadedApk.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); service.onCreate(); @@ -3943,7 +3957,7 @@ public final class ActivityThread { Bundle.dumpStats(pw, persistentState); if (ex instanceof TransactionTooLargeException - && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) { + && activity.loadedApk.getTargetSdkVersion() < Build.VERSION_CODES.N) { Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex); return; } @@ -4238,11 +4252,11 @@ public final class ActivityThread { } private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) { - LoadedApk apk = peekPackageInfo(data.pkg, false); + LoadedApk apk = peekLoadedApk(data.pkg, false); if (apk != null) { apk.setCompatibilityInfo(data.info); } - apk = peekPackageInfo(data.pkg, true); + apk = peekLoadedApk(data.pkg, true); if (apk != null) { apk.setCompatibilityInfo(data.info); } @@ -4739,7 +4753,7 @@ public final class ActivityThread { if (a != null) { Configuration thisConfig = applyConfigCompatMainThread( mCurDefaultDisplayDpi, newConfig, - ar.packageInfo.getCompatibilityInfo()); + ar.loadedApk.getCompatibilityInfo()); if (!ar.activity.mFinished && (allActivities || !ar.paused)) { // If the activity is currently resumed, its configuration // needs to change right now. @@ -5209,7 +5223,7 @@ public final class ActivityThread { } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { - boolean hasPkgInfo = false; + boolean hasLoadedApk = false; switch (cmd) { case ApplicationThreadConstants.PACKAGE_REMOVED: case ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL: @@ -5220,14 +5234,14 @@ public final class ActivityThread { } synchronized (mResourcesManager) { for (int i = packages.length - 1; i >= 0; i--) { - if (!hasPkgInfo) { + if (!hasLoadedApk) { WeakReference<LoadedApk> ref = mPackages.get(packages[i]); if (ref != null && ref.get() != null) { - hasPkgInfo = true; + hasLoadedApk = true; } else { ref = mResourcePackages.get(packages[i]); if (ref != null && ref.get() != null) { - hasPkgInfo = true; + hasLoadedApk = true; } } } @@ -5247,21 +5261,21 @@ public final class ActivityThread { synchronized (mResourcesManager) { for (int i = packages.length - 1; i >= 0; i--) { WeakReference<LoadedApk> ref = mPackages.get(packages[i]); - LoadedApk pkgInfo = ref != null ? ref.get() : null; - if (pkgInfo != null) { - hasPkgInfo = true; + LoadedApk loadedApk = ref != null ? ref.get() : null; + if (loadedApk != null) { + hasLoadedApk = true; } else { ref = mResourcePackages.get(packages[i]); - pkgInfo = ref != null ? ref.get() : null; - if (pkgInfo != null) { - hasPkgInfo = true; + loadedApk = ref != null ? ref.get() : null; + if (loadedApk != null) { + hasLoadedApk = true; } } // If the package is being replaced, yet it still has a valid // LoadedApk object, the package was updated with _DONT_KILL. // Adjust it's internal references to the application info and // resources. - if (pkgInfo != null) { + if (loadedApk != null) { try { final String packageName = packages[i]; final ApplicationInfo aInfo = @@ -5275,13 +5289,13 @@ public final class ActivityThread { if (ar.activityInfo.applicationInfo.packageName .equals(packageName)) { ar.activityInfo.applicationInfo = aInfo; - ar.packageInfo = pkgInfo; + ar.loadedApk = loadedApk; } } } final List<String> oldPaths = sPackageManager.getPreviousCodePaths(packageName); - pkgInfo.updateApplicationInfo(aInfo, oldPaths); + loadedApk.updateApplicationInfo(aInfo, oldPaths); } catch (RemoteException e) { } } @@ -5290,7 +5304,7 @@ public final class ActivityThread { break; } } - ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo); + ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasLoadedApk); } final void handleLowMemory() { @@ -5441,12 +5455,16 @@ public final class ActivityThread { mCompatConfiguration = new Configuration(data.config); mProfiler = new Profiler(); + String agent = null; if (data.initProfilerInfo != null) { mProfiler.profileFile = data.initProfilerInfo.profileFile; mProfiler.profileFd = data.initProfilerInfo.profileFd; mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval; mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler; mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput; + if (data.initProfilerInfo.attachAgentDuringBind) { + agent = data.initProfilerInfo.agent; + } } // send up app name; do this *before* waiting for debugger @@ -5494,7 +5512,11 @@ public final class ActivityThread { applyCompatConfiguration(mCurDefaultDisplayDpi); } - data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); + data.loadedApk = getLoadedApkNoCheck(data.appInfo, data.compatInfo); + + if (agent != null) { + handleAttachAgent(agent, data.loadedApk); + } /** * Switch this process to density compatibility mode if needed. @@ -5562,7 +5584,7 @@ public final class ActivityThread { // XXX should have option to change the port. Debug.changeDebugPort(8100); if (data.debugMode == ApplicationThreadConstants.DEBUG_WAIT) { - Slog.w(TAG, "Application " + data.info.getPackageName() + Slog.w(TAG, "Application " + data.loadedApk.getPackageName() + " is waiting for the debugger on port 8100..."); IActivityManager mgr = ActivityManager.getService(); @@ -5581,7 +5603,7 @@ public final class ActivityThread { } } else { - Slog.w(TAG, "Application " + data.info.getPackageName() + Slog.w(TAG, "Application " + data.loadedApk.getPackageName() + " can be debugged on port 8100..."); } } @@ -5629,14 +5651,14 @@ public final class ActivityThread { mInstrumentationAppDir = ii.sourceDir; mInstrumentationSplitAppDirs = ii.splitSourceDirs; mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii); - mInstrumentedAppDir = data.info.getAppDir(); - mInstrumentedSplitAppDirs = data.info.getSplitAppDirs(); - mInstrumentedLibDir = data.info.getLibDir(); + mInstrumentedAppDir = data.loadedApk.getAppDir(); + mInstrumentedSplitAppDirs = data.loadedApk.getSplitAppDirs(); + mInstrumentedLibDir = data.loadedApk.getLibDir(); } else { ii = null; } - final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); + final ContextImpl appContext = ContextImpl.createAppContext(this, data.loadedApk); updateLocaleListFromAppContext(appContext, mResourcesManager.getConfiguration().getLocales()); @@ -5666,9 +5688,9 @@ public final class ActivityThread { final ApplicationInfo instrApp = new ApplicationInfo(); ii.copyTo(instrApp); instrApp.initForUser(UserHandle.myUserId()); - final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, + final LoadedApk loadedApk = getLoadedApk(instrApp, data.compatInfo, appContext.getClassLoader(), false, true, false); - final ContextImpl instrContext = ContextImpl.createAppContext(this, pi); + final ContextImpl instrContext = ContextImpl.createAppContext(this, loadedApk); try { final ClassLoader cl = instrContext.getClassLoader(); @@ -5712,7 +5734,7 @@ public final class ActivityThread { try { // If the app is being launched for full backup or restore, bring it up in // a restricted environment with the base application class. - app = data.info.makeApplication(data.restrictedBackupMode, null); + app = data.loadedApk.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; // don't bring up providers in restricted mode; they may depend on the @@ -5766,7 +5788,7 @@ public final class ActivityThread { final int preloadedFontsResource = info.metaData.getInt( ApplicationInfo.METADATA_PRELOADED_FONTS, 0); if (preloadedFontsResource != 0) { - data.info.getResources().preloadFonts(preloadedFontsResource); + data.loadedApk.getResources().preloadFonts(preloadedFontsResource); } } } catch (RemoteException e) { @@ -6361,8 +6383,8 @@ public final class ActivityThread { try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( - this, getSystemContext().mPackageInfo); - mInitialApplication = context.mPackageInfo.makeApplication(true, null); + this, getSystemContext().mLoadedApk); + mInitialApplication = context.mLoadedApk.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { throw new RuntimeException( diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 156df36a600c..5822f5c8f6c1 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -187,7 +187,7 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { */ /* package */ final void attach(Context context) { attachBaseContext(context); - mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; + mLoadedApk = ContextImpl.getImpl(context).mLoadedApk; } /* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 0eafdec6bb0f..4d47d82260c2 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1379,7 +1379,7 @@ public class ApplicationPackageManager extends PackageManager { sameUid ? app.sourceDir : app.publicSourceDir, sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs, app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY, - mContext.mPackageInfo); + mContext.mLoadedApk); if (r != null) { return r; } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5f3432264ca0..64ddfbceeda4 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -159,7 +159,7 @@ class ContextImpl extends Context { private ArrayMap<String, File> mSharedPrefsPaths; final @NonNull ActivityThread mMainThread; - final @NonNull LoadedApk mPackageInfo; + final @NonNull LoadedApk mLoadedApk; private @Nullable ClassLoader mClassLoader; private final @Nullable IBinder mActivityToken; @@ -252,8 +252,8 @@ class ContextImpl extends Context { @Override public Context getApplicationContext() { - return (mPackageInfo != null) ? - mPackageInfo.getApplication() : mMainThread.getApplication(); + return (mLoadedApk != null) ? + mLoadedApk.getApplication() : mMainThread.getApplication(); } @Override @@ -297,15 +297,15 @@ class ContextImpl extends Context { @Override public ClassLoader getClassLoader() { - return mClassLoader != null ? mClassLoader : (mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader()); + return mClassLoader != null ? mClassLoader : (mLoadedApk != null ? mLoadedApk.getClassLoader() : ClassLoader.getSystemClassLoader()); } @Override public String getPackageName() { - if (mPackageInfo != null) { - return mPackageInfo.getPackageName(); + if (mLoadedApk != null) { + return mLoadedApk.getPackageName(); } - // No mPackageInfo means this is a Context for the system itself, + // No mLoadedApk means this is a Context for the system itself, // and this here is its name. return "android"; } @@ -324,24 +324,24 @@ class ContextImpl extends Context { @Override public ApplicationInfo getApplicationInfo() { - if (mPackageInfo != null) { - return mPackageInfo.getApplicationInfo(); + if (mLoadedApk != null) { + return mLoadedApk.getApplicationInfo(); } throw new RuntimeException("Not supported in system context"); } @Override public String getPackageResourcePath() { - if (mPackageInfo != null) { - return mPackageInfo.getResDir(); + if (mLoadedApk != null) { + return mLoadedApk.getResDir(); } throw new RuntimeException("Not supported in system context"); } @Override public String getPackageCodePath() { - if (mPackageInfo != null) { - return mPackageInfo.getAppDir(); + if (mLoadedApk != null) { + return mLoadedApk.getAppDir(); } throw new RuntimeException("Not supported in system context"); } @@ -351,7 +351,7 @@ class ContextImpl extends Context { // At least one application in the world actually passes in a null // name. This happened to work because when we generated the file name // we would stringify it to "null.xml". Nice. - if (mPackageInfo.getApplicationInfo().targetSdkVersion < + if (mLoadedApk.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.KITKAT) { if (name == null) { name = "null"; @@ -1093,11 +1093,11 @@ class ContextImpl extends Context { warnIfCallingFromSystemProcess(); IIntentReceiver rd = null; if (resultReceiver != null) { - if (mPackageInfo != null) { + if (mLoadedApk != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = mPackageInfo.getReceiverDispatcher( + rd = mLoadedApk.getReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, mMainThread.getInstrumentation(), false); } else { @@ -1197,11 +1197,11 @@ class ContextImpl extends Context { Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { IIntentReceiver rd = null; if (resultReceiver != null) { - if (mPackageInfo != null) { + if (mLoadedApk != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = mPackageInfo.getReceiverDispatcher( + rd = mLoadedApk.getReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, mMainThread.getInstrumentation(), false); } else { @@ -1251,11 +1251,11 @@ class ContextImpl extends Context { warnIfCallingFromSystemProcess(); IIntentReceiver rd = null; if (resultReceiver != null) { - if (mPackageInfo != null) { + if (mLoadedApk != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = mPackageInfo.getReceiverDispatcher( + rd = mLoadedApk.getReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, mMainThread.getInstrumentation(), false); } else { @@ -1333,11 +1333,11 @@ class ContextImpl extends Context { Bundle initialExtras) { IIntentReceiver rd = null; if (resultReceiver != null) { - if (mPackageInfo != null) { + if (mLoadedApk != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = mPackageInfo.getReceiverDispatcher( + rd = mLoadedApk.getReceiverDispatcher( resultReceiver, getOuterContext(), scheduler, mMainThread.getInstrumentation(), false); } else { @@ -1414,11 +1414,11 @@ class ContextImpl extends Context { Handler scheduler, Context context, int flags) { IIntentReceiver rd = null; if (receiver != null) { - if (mPackageInfo != null && context != null) { + if (mLoadedApk != null && context != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = mPackageInfo.getReceiverDispatcher( + rd = mLoadedApk.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { @@ -1445,8 +1445,8 @@ class ContextImpl extends Context { @Override public void unregisterReceiver(BroadcastReceiver receiver) { - if (mPackageInfo != null) { - IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher( + if (mLoadedApk != null) { + IIntentReceiver rd = mLoadedApk.forgetReceiverDispatcher( getOuterContext(), receiver); try { ActivityManager.getService().unregisterReceiver(rd); @@ -1579,7 +1579,7 @@ class ContextImpl extends Context { @Override public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler, int flags) { - return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); + return mLoadedApk.getServiceDispatcher(conn, getOuterContext(), handler, flags); } /** @hide */ @@ -1601,16 +1601,16 @@ class ContextImpl extends Context { if (conn == null) { throw new IllegalArgumentException("connection is null"); } - if (mPackageInfo != null) { - sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); + if (mLoadedApk != null) { + sd = mLoadedApk.getServiceDispatcher(conn, getOuterContext(), handler, flags); } else { throw new RuntimeException("Not supported in system context"); } validateServiceIntent(service); try { IBinder token = getActivityToken(); - if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null - && mPackageInfo.getApplicationInfo().targetSdkVersion + if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mLoadedApk != null + && mLoadedApk.getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { flags |= BIND_WAIVE_PRIORITY; } @@ -1634,8 +1634,8 @@ class ContextImpl extends Context { if (conn == null) { throw new IllegalArgumentException("connection is null"); } - if (mPackageInfo != null) { - IServiceConnection sd = mPackageInfo.forgetServiceDispatcher( + if (mLoadedApk != null) { + IServiceConnection sd = mLoadedApk.forgetServiceDispatcher( getOuterContext(), conn); try { ActivityManager.getService().unbindService(sd); @@ -1980,40 +1980,20 @@ class ContextImpl extends Context { } } - private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName, - int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) { - final String[] splitResDirs; - final ClassLoader classLoader; - try { - splitResDirs = pi.getSplitPaths(splitName); - classLoader = pi.getSplitClassLoader(splitName); - } catch (NameNotFoundException e) { - throw new RuntimeException(e); - } - return ResourcesManager.getInstance().getResources(activityToken, - pi.getResDir(), - splitResDirs, - pi.getOverlayDirs(), - pi.getApplicationInfo().sharedLibraryFiles, - displayId, - overrideConfig, - compatInfo, - classLoader); - } - @Override public Context createApplicationContext(ApplicationInfo application, int flags) throws NameNotFoundException { - LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(), + LoadedApk loadedApk = mMainThread.getLoadedApk(application, + mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE); - if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, + if (loadedApk != null) { + ContextImpl c = new ContextImpl(this, mMainThread, loadedApk, null, mActivityToken, new UserHandle(UserHandle.getUserId(application.uid)), flags, null); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - c.setResources(createResources(mActivityToken, pi, null, displayId, null, + c.setResources(loadedApk.createResources(mActivityToken, null, displayId, null, getDisplayAdjustments(displayId).getCompatibilityInfo())); if (c.mResources != null) { return c; @@ -2037,20 +2017,21 @@ class ContextImpl extends Context { if (packageName.equals("system") || packageName.equals("android")) { // The system resources are loaded in every application, so we can safely copy // the context without reloading Resources. - return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user, + return new ContextImpl(this, mMainThread, mLoadedApk, null, mActivityToken, user, flags, null); } - LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), + LoadedApk loadedApk = mMainThread.getLoadedApkForPackageName(packageName, + mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); - if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user, + if (loadedApk != null) { + ContextImpl c = new ContextImpl(this, mMainThread, loadedApk, null, mActivityToken, user, flags, null); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - c.setResources(createResources(mActivityToken, pi, null, displayId, null, + c.setResources(loadedApk.createResources(mActivityToken, null, displayId, null, getDisplayAdjustments(displayId).getCompatibilityInfo())); if (c.mResources != null) { return c; @@ -2064,30 +2045,21 @@ class ContextImpl extends Context { @Override public Context createContextForSplit(String splitName) throws NameNotFoundException { - if (!mPackageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) { + if (!mLoadedApk.getApplicationInfo().requestsIsolatedSplitLoading()) { // All Splits are always loaded. return this; } - final ClassLoader classLoader = mPackageInfo.getSplitClassLoader(splitName); - final String[] paths = mPackageInfo.getSplitPaths(splitName); + final ClassLoader classLoader = mLoadedApk.getSplitClassLoader(splitName); - final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName, + final ContextImpl context = new ContextImpl(this, mMainThread, mLoadedApk, splitName, mActivityToken, mUser, mFlags, classLoader); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - context.setResources(ResourcesManager.getInstance().getResources( - mActivityToken, - mPackageInfo.getResDir(), - paths, - mPackageInfo.getOverlayDirs(), - mPackageInfo.getApplicationInfo().sharedLibraryFiles, - displayId, - null, - mPackageInfo.getCompatibilityInfo(), - classLoader)); + context.setResources(mLoadedApk.getOrCreateResourcesForSplit(splitName, + mActivityToken, displayId)); return context; } @@ -2097,11 +2069,11 @@ class ContextImpl extends Context { throw new IllegalArgumentException("overrideConfiguration must not be null"); } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, + ContextImpl context = new ContextImpl(this, mMainThread, mLoadedApk, mSplitName, mActivityToken, mUser, mFlags, mClassLoader); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, + context.setResources(mLoadedApk.createResources(mActivityToken, mSplitName, displayId, overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo())); return context; } @@ -2112,11 +2084,11 @@ class ContextImpl extends Context { throw new IllegalArgumentException("display must not be null"); } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, + ContextImpl context = new ContextImpl(this, mMainThread, mLoadedApk, mSplitName, mActivityToken, mUser, mFlags, mClassLoader); final int displayId = display.getDisplayId(); - context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, + context.setResources(mLoadedApk.createResources(mActivityToken, mSplitName, displayId, null, getDisplayAdjustments(displayId).getCompatibilityInfo())); context.mDisplay = display; return context; @@ -2126,7 +2098,7 @@ class ContextImpl extends Context { public Context createDeviceProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, + return new ContextImpl(this, mMainThread, mLoadedApk, mSplitName, mActivityToken, mUser, flags, mClassLoader); } @@ -2134,7 +2106,7 @@ class ContextImpl extends Context { public Context createCredentialProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, + return new ContextImpl(this, mMainThread, mLoadedApk, mSplitName, mActivityToken, mUser, flags, mClassLoader); } @@ -2183,14 +2155,14 @@ class ContextImpl extends Context { @Override public File getDataDir() { - if (mPackageInfo != null) { + if (mLoadedApk != null) { File res = null; if (isCredentialProtectedStorage()) { - res = mPackageInfo.getCredentialProtectedDataDirFile(); + res = mLoadedApk.getCredentialProtectedDataDirFile(); } else if (isDeviceProtectedStorage()) { - res = mPackageInfo.getDeviceProtectedDataDirFile(); + res = mLoadedApk.getDeviceProtectedDataDirFile(); } else { - res = mPackageInfo.getDataDirFile(); + res = mLoadedApk.getDataDirFile(); } if (res != null) { @@ -2241,10 +2213,10 @@ class ContextImpl extends Context { } static ContextImpl createSystemContext(ActivityThread mainThread) { - LoadedApk packageInfo = new LoadedApk(mainThread); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, + LoadedApk loadedApk = new LoadedApk(mainThread); + ContextImpl context = new ContextImpl(null, mainThread, loadedApk, null, null, null, 0, null); - context.setResources(packageInfo.getResources()); + context.setResources(loadedApk.getResources()); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetrics()); return context; @@ -2255,35 +2227,35 @@ class ContextImpl extends Context { * Make sure that the created system UI context shares the same LoadedApk as the system context. */ static ContextImpl createSystemUiContext(ContextImpl systemContext) { - final LoadedApk packageInfo = systemContext.mPackageInfo; - ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, + final LoadedApk loadedApk = systemContext.mLoadedApk; + ContextImpl context = new ContextImpl(null, systemContext.mMainThread, loadedApk, null, null, null, 0, null); - context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, - packageInfo.getCompatibilityInfo())); + context.setResources(loadedApk.createResources(null, null, Display.DEFAULT_DISPLAY, null, + loadedApk.getCompatibilityInfo())); return context; } - static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { - if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk loadedApk) { + if (loadedApk == null) throw new IllegalArgumentException("loadedApk"); + ContextImpl context = new ContextImpl(null, mainThread, loadedApk, null, null, null, 0, null); - context.setResources(packageInfo.getResources()); + context.setResources(loadedApk.getResources()); return context; } static ContextImpl createActivityContext(ActivityThread mainThread, - LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, + LoadedApk loadedApk, ActivityInfo activityInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) { - if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); + if (loadedApk == null) throw new IllegalArgumentException("loadedApk"); - String[] splitDirs = packageInfo.getSplitResDirs(); - ClassLoader classLoader = packageInfo.getClassLoader(); + String[] splitDirs = loadedApk.getSplitResDirs(); + ClassLoader classLoader = loadedApk.getClassLoader(); - if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) { + if (loadedApk.getApplicationInfo().requestsIsolatedSplitLoading()) { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies"); try { - classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName); - splitDirs = packageInfo.getSplitPaths(activityInfo.splitName); + classLoader = loadedApk.getSplitClassLoader(activityInfo.splitName); + splitDirs = loadedApk.getSplitPaths(activityInfo.splitName); } catch (NameNotFoundException e) { // Nothing above us can handle a NameNotFoundException, better crash. throw new RuntimeException(e); @@ -2292,14 +2264,14 @@ class ContextImpl extends Context { } } - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, + ContextImpl context = new ContextImpl(null, mainThread, loadedApk, activityInfo.splitName, activityToken, null, 0, classLoader); // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY; final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY) - ? packageInfo.getCompatibilityInfo() + ? loadedApk.getCompatibilityInfo() : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; final ResourcesManager resourcesManager = ResourcesManager.getInstance(); @@ -2307,10 +2279,10 @@ class ContextImpl extends Context { // Create the base resources for which all configuration contexts for this Activity // will be rebased upon. context.setResources(resourcesManager.createBaseActivityResources(activityToken, - packageInfo.getResDir(), + loadedApk.getResDir(), splitDirs, - packageInfo.getOverlayDirs(), - packageInfo.getApplicationInfo().sharedLibraryFiles, + loadedApk.getOverlayDirs(), + loadedApk.getApplicationInfo().sharedLibraryFiles, displayId, overrideConfiguration, compatInfo, @@ -2321,7 +2293,7 @@ class ContextImpl extends Context { } private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, - @NonNull LoadedApk packageInfo, @Nullable String splitName, + @NonNull LoadedApk loadedApk, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader) { mOuterContext = this; @@ -2330,10 +2302,10 @@ class ContextImpl extends Context { // location for application. if ((flags & (Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE | Context.CONTEXT_DEVICE_PROTECTED_STORAGE)) == 0) { - final File dataDir = packageInfo.getDataDirFile(); - if (Objects.equals(dataDir, packageInfo.getCredentialProtectedDataDirFile())) { + final File dataDir = loadedApk.getDataDirFile(); + if (Objects.equals(dataDir, loadedApk.getCredentialProtectedDataDirFile())) { flags |= Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; - } else if (Objects.equals(dataDir, packageInfo.getDeviceProtectedDataDirFile())) { + } else if (Objects.equals(dataDir, loadedApk.getDeviceProtectedDataDirFile())) { flags |= Context.CONTEXT_DEVICE_PROTECTED_STORAGE; } } @@ -2347,7 +2319,7 @@ class ContextImpl extends Context { } mUser = user; - mPackageInfo = packageInfo; + mLoadedApk = loadedApk; mSplitName = splitName; mClassLoader = classLoader; mResourcesManager = ResourcesManager.getInstance(); @@ -2358,8 +2330,8 @@ class ContextImpl extends Context { setResources(container.mResources); mDisplay = container.mDisplay; } else { - mBasePackageName = packageInfo.mPackageName; - ApplicationInfo ainfo = packageInfo.getApplicationInfo(); + mBasePackageName = loadedApk.mPackageName; + ApplicationInfo ainfo = loadedApk.getApplicationInfo(); if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) { // Special case: system components allow themselves to be loaded in to other // processes. For purposes of app ops, we must then consider the context as @@ -2382,7 +2354,7 @@ class ContextImpl extends Context { } void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { - mPackageInfo.installSystemApplicationInfo(info, classLoader); + mLoadedApk.installSystemApplicationInfo(info, classLoader); } final void scheduleFinalCleanup(String who, String what) { @@ -2391,7 +2363,7 @@ class ContextImpl extends Context { final void performFinalCleanup(String who, String what) { //Log.i(TAG, "Cleanup up context: " + this); - mPackageInfo.removeContextRegistrations(getOuterContext(), who, what); + mLoadedApk.removeContextRegistrations(getOuterContext(), who, what); } final Context getReceiverRestrictedContext() { diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index f6d9710dae69..236a42c583e8 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.split.SplitDependencyLoader; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; @@ -48,15 +49,13 @@ import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.Log; +import android.util.LogPrinter; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DisplayAdjustments; - import com.android.internal.util.ArrayUtils; - import dalvik.system.VMRuntime; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -948,14 +947,78 @@ public final class LoadedApk { throw new AssertionError("null split not found"); } - mResources = ResourcesManager.getInstance().getResources(null, mResDir, - splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles, - Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(), + mResources = ResourcesManager.getInstance().getResources( + null, + mResDir, + splitPaths, + mOverlayDirs, + mApplicationInfo.sharedLibraryFiles, + Display.DEFAULT_DISPLAY, + null, + getCompatibilityInfo(), getClassLoader()); } return mResources; } + public Resources getOrCreateResourcesForSplit(@NonNull String splitName, + @Nullable IBinder activityToken, int displayId) throws NameNotFoundException { + return ResourcesManager.getInstance().getResources( + activityToken, + mResDir, + getSplitPaths(splitName), + mOverlayDirs, + mApplicationInfo.sharedLibraryFiles, + displayId, + null, + getCompatibilityInfo(), + getSplitClassLoader(splitName)); + } + + /** + * Creates the top level resources for the given package. Will return an existing + * Resources if one has already been created. + */ + public Resources getOrCreateTopLevelResources(@NonNull ApplicationInfo appInfo) { + // Request for this app, short circuit + if (appInfo.uid == Process.myUid()) { + return getResources(); + } + + // Get resources for a different package + return ResourcesManager.getInstance().getResources( + null, + appInfo.publicSourceDir, + appInfo.splitPublicSourceDirs, + appInfo.resourceDirs, + appInfo.sharedLibraryFiles, + Display.DEFAULT_DISPLAY, + null, + getCompatibilityInfo(), + getClassLoader()); + } + + public Resources createResources(IBinder activityToken, String splitName, + int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) { + final String[] splitResDirs; + final ClassLoader classLoader; + try { + splitResDirs = getSplitPaths(splitName); + classLoader = getSplitClassLoader(splitName); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + return ResourcesManager.getInstance().getResources(activityToken, + mResDir, + splitResDirs, + mOverlayDirs, + mApplicationInfo.sharedLibraryFiles, + displayId, + overrideConfig, + compatInfo, + classLoader); + } + public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { if (mApplication != null) { diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index fad4798e3a3e..044b78003bd7 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -54,14 +54,24 @@ public class ProfilerInfo implements Parcelable { */ public final String agent; + /** + * Whether the {@link agent} should be attached early (before bind-application) or during + * bind-application. Agents attached prior to binding cannot be loaded from the app's APK + * directly and must be given as an absolute path (or available in the default LD_LIBRARY_PATH). + * Agents attached during bind-application will miss early setup (e.g., resource initialization + * and classloader generation), but are searched in the app's library search path. + */ + public final boolean attachAgentDuringBind; + public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop, - boolean streaming, String agent) { + boolean streaming, String agent, boolean attachAgentDuringBind) { profileFile = filename; profileFd = fd; samplingInterval = interval; autoStopProfiler = autoStop; streamingOutput = streaming; this.agent = agent; + this.attachAgentDuringBind = attachAgentDuringBind; } public ProfilerInfo(ProfilerInfo in) { @@ -71,6 +81,7 @@ public class ProfilerInfo implements Parcelable { autoStopProfiler = in.autoStopProfiler; streamingOutput = in.streamingOutput; agent = in.agent; + attachAgentDuringBind = in.attachAgentDuringBind; } /** @@ -109,6 +120,7 @@ public class ProfilerInfo implements Parcelable { out.writeInt(autoStopProfiler ? 1 : 0); out.writeInt(streamingOutput ? 1 : 0); out.writeString(agent); + out.writeBoolean(attachAgentDuringBind); } public static final Parcelable.Creator<ProfilerInfo> CREATOR = @@ -131,5 +143,6 @@ public class ProfilerInfo implements Parcelable { autoStopProfiler = in.readInt() != 0; streamingOutput = in.readInt() != 0; agent = in.readString(); + attachAgentDuringBind = in.readBoolean(); } } diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 8c47598fff34..6ac15a5f8c91 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -71,6 +71,8 @@ final class SharedPreferencesImpl implements SharedPreferences { @GuardedBy("mLock") private Map<String, Object> mMap; + @GuardedBy("mLock") + private Throwable mThrowable; @GuardedBy("mLock") private int mDiskWritesInFlight = 0; @@ -107,6 +109,7 @@ final class SharedPreferencesImpl implements SharedPreferences { mMode = mode; mLoaded = false; mMap = null; + mThrowable = null; startLoadFromDisk(); } @@ -139,13 +142,14 @@ final class SharedPreferencesImpl implements SharedPreferences { Map<String, Object> map = null; StructStat stat = null; + Throwable thrown = null; try { stat = Os.stat(mFile.getPath()); if (mFile.canRead()) { BufferedInputStream str = null; try { str = new BufferedInputStream( - new FileInputStream(mFile), 16*1024); + new FileInputStream(mFile), 16 * 1024); map = (Map<String, Object>) XmlUtils.readMapXml(str); } catch (Exception e) { Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e); @@ -154,19 +158,36 @@ final class SharedPreferencesImpl implements SharedPreferences { } } } catch (ErrnoException e) { - /* ignore */ + // An errno exception means the stat failed. Treat as empty/non-existing by + // ignoring. + } catch (Throwable t) { + thrown = t; } synchronized (mLock) { mLoaded = true; - if (map != null) { - mMap = map; - mStatTimestamp = stat.st_mtim; - mStatSize = stat.st_size; - } else { - mMap = new HashMap<>(); + mThrowable = thrown; + + // It's important that we always signal waiters, even if we'll make + // them fail with an exception. The try-finally is pretty wide, but + // better safe than sorry. + try { + if (thrown == null) { + if (map != null) { + mMap = map; + mStatTimestamp = stat.st_mtim; + mStatSize = stat.st_size; + } else { + mMap = new HashMap<>(); + } + } + // In case of a thrown exception, we retain the old map. That allows + // any open editors to commit and store updates. + } catch (Throwable t) { + mThrowable = t; + } finally { + mLock.notifyAll(); } - mLock.notifyAll(); } } @@ -226,6 +247,7 @@ final class SharedPreferencesImpl implements SharedPreferences { } } + @GuardedBy("mLock") private void awaitLoadedLocked() { if (!mLoaded) { // Raise an explicit StrictMode onReadFromDisk for this @@ -239,6 +261,9 @@ final class SharedPreferencesImpl implements SharedPreferences { } catch (InterruptedException unused) { } } + if (mThrowable != null) { + throw new IllegalStateException(mThrowable); + } } @Override diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index ab70f0e71216..97c668117ee0 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -81,10 +81,10 @@ import android.net.INetworkPolicyManager; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; -import android.net.nsd.INsdManager; -import android.net.nsd.NsdManager; import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; import android.net.wifi.IRttManager; import android.net.wifi.IWifiManager; import android.net.wifi.IWifiScanner; @@ -130,6 +130,7 @@ import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccManager; import android.util.Log; import android.view.ContextThemeWrapper; @@ -504,6 +505,13 @@ final class SystemServiceRegistry { return new EuiccManager(ctx.getOuterContext()); }}); + registerService(Context.EUICC_CARD_SERVICE, EuiccCardManager.class, + new CachedServiceFetcher<EuiccCardManager>() { + @Override + public EuiccCardManager createService(ContextImpl ctx) { + return new EuiccCardManager(ctx.getOuterContext()); + }}); + registerService(Context.UI_MODE_SERVICE, UiModeManager.class, new CachedServiceFetcher<UiModeManager>() { @Override diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index c7be0f36ecef..6c8fe2e399fa 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -79,8 +79,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link BluetoothDevice} objects representing all paired devices with * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to - * listen for incoming connection requests with - * {@link #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for + * listen for incoming RFComm connection requests with {@link + * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented + * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. * </p> * <p>This class is thread safe.</p> @@ -210,6 +211,14 @@ public final class BluetoothAdapter { public static final int STATE_BLE_TURNING_OFF = 16; /** + * UUID of the GATT Read Characteristics for LE_PSM value. + * + * @hide + */ + public static final UUID LE_PSM_CHARACTERISTIC_UUID = + UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a"); + + /** * Human-readable string helper for AdapterState * * @hide @@ -1671,6 +1680,27 @@ public final class BluetoothAdapter { } /** + * Get the maximum number of connected audio devices. + * + * @return the maximum number of connected audio devices + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getMaxConnectedAudioDevices() { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getMaxConnectedAudioDevices(); + } + } catch (RemoteException e) { + Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return 1; + } + + /** * Return true if hardware has entries available for matching beacons * * @return true if there are hw entries available for matching beacons @@ -2135,7 +2165,9 @@ public final class BluetoothAdapter { min16DigitPin); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); + int assignedChannel = socket.mSocket.getPort(); + if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel); + socket.setChannel(assignedChannel); } if (errno != 0) { //TODO(BT): Throw the same exception error code @@ -2176,12 +2208,18 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { + Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, - false); + false); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); + int assignedChannel = socket.mSocket.getPort(); + if (DBG) { + Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to " + + assignedChannel); + } + socket.setChannel(assignedChannel); } if (errno != 0) { //TODO(BT): Throw the same exception error code @@ -2740,4 +2778,103 @@ public final class BluetoothAdapter { scanner.stopScan(scanCallback); } } + + /** + * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and + * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen + * for incoming connections. + * <p>A remote device connecting to this socket will be authenticated and communication on this + * socket will be encrypted. + * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening + * {@link BluetoothServerSocket}. + * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {#link + * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is + * closed, Bluetooth is turned off, or the application exits unexpectedly. + * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is + * defined and performed by the application. + * <p>Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server + * socket from another Android device that is given the PSM value. + * + * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} + * @return an L2CAP CoC BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or unable to start this CoC + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingL2capCoc(int transport) + throws IOException { + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, + SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + throw new IOException("Error: " + errno); + } + + int assignedPsm = socket.mSocket.getPort(); + if (assignedPsm == 0) { + throw new IOException("Error: Unable to assign PSM value"); + } + if (DBG) { + Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to " + + assignedPsm); + } + socket.setChannel(assignedPsm); + + return socket; + } + + /** + * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and + * assign a dynamic PSM value. This socket can be used to listen for incoming connections. + * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable + * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and + * authenticated communication channel is desired. + * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening + * {@link BluetoothServerSocket}. + * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value + * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released + * when this server socket is closed, Bluetooth is turned off, or the application exits + * unexpectedly. + * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is + * defined and performed by the application. + * <p>Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this + * server socket from another Android device that is given the PSM value. + * + * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} + * @return an L2CAP CoC BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or unable to start this CoC + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) + throws IOException { + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, + SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + throw new IOException("Error: " + errno); + } + + int assignedPsm = socket.mSocket.getPort(); + if (assignedPsm == 0) { + throw new IOException("Error: Unable to assign PSM value"); + } + if (DBG) { + Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to " + + assignedPsm); + } + socket.setChannel(assignedPsm); + + return socket; + } } diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index ad7a93cd6bbd..ac21395c2fa7 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -618,6 +618,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_UNKNOWN = 0; /** @@ -626,6 +627,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_ALLOWED = 1; /** @@ -634,6 +636,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_REJECTED = 2; /** @@ -1918,4 +1921,75 @@ public final class BluetoothDevice implements Parcelable { } return null; } + + /** + * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can + * be used to start a secure outgoing connection to the remote device with the same dynamic + * protocol/service multiplexer (PSM) value. + * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capCoc(int)} for + * peer-peer Bluetooth applications. + * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. + * <p>Application using this API is responsible for obtaining PSM value from remote device. + * <p>The remote device will be authenticated and communication on this socket will be + * encrypted. + * <p> Use this socket if an authenticated socket link is possible. Authentication refers + * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a + * secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int, + * int)}. + * + * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE} + * @param psm dynamic PSM value from remote device + * @return a CoC #BluetoothSocket ready for an outgoing connection + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException { + if (!isBluetoothEnabled()) { + Log.e(TAG, "createL2capCocSocket: Bluetooth is not enabled"); + throw new IOException(); + } + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + if (DBG) Log.d(TAG, "createL2capCocSocket: transport=" + transport + ", psm=" + psm); + return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm, + null); + } + + /** + * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can + * be used to start a secure outgoing connection to the remote device with the same dynamic + * protocol/service multiplexer (PSM) value. + * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingInsecureL2capCoc(int)} + * for peer-peer Bluetooth applications. + * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. + * <p>Application using this API is responsible for obtaining PSM value from remote device. + * <p> The communication channel may not have an authenticated link key, i.e. it may be subject + * to man-in-the-middle attacks. Use {@link #createL2capCocSocket(int, int)} if an encrypted and + * authenticated communication channel is possible. + * + * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE} + * @param psm dynamic PSM value from remote device + * @return a CoC #BluetoothSocket ready for an outgoing connection + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException { + if (!isBluetoothEnabled()) { + Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled"); + throw new IOException(); + } + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + if (DBG) { + Log.d(TAG, "createInsecureL2capCocSocket: transport=" + transport + ", psm=" + psm); + } + return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm, + null); + } } diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 55a6b4c6b4d4..a68f485f4374 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -556,8 +556,8 @@ public final class BluetoothHeadset implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or - * {@link #PRIORITY_OFF}, + * Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or + * {@link BluetoothProfile#PRIORITY_OFF}, * * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission. @@ -1071,9 +1071,35 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** - * check if in-band ringing is supported for this platform. + * Check if in-band ringing is currently enabled. In-band ringing could be disabled during an + * active connection. * - * @return true if in-band ringing is supported false if in-band ringing is not supported + * @return true if in-band ringing is enabled, false if in-band ringing is disabled + * @hide + */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH) + public boolean isInbandRingingEnabled() { + if (DBG) { + log("isInbandRingingEnabled()"); + } + final IBluetoothHeadset service = mService; + if (service != null && isEnabled()) { + try { + return service.isInbandRingingEnabled(); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return false; + } + + /** + * Check if in-band ringing is supported for this platform. + * + * @return true if in-band ringing is supported, false if in-band ringing is not supported * @hide */ public static boolean isInbandRingingSupported(Context context) { diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java index dc00d63043fc..d46b2e37467b 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -73,17 +73,18 @@ public final class BluetoothHeadsetClientCall implements Parcelable { private final boolean mOutgoing; private final UUID mUUID; private final long mCreationElapsedMilli; + private final boolean mInBandRing; /** * Creates BluetoothHeadsetClientCall instance. */ public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number, - boolean multiParty, boolean outgoing) { - this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing); + boolean multiParty, boolean outgoing, boolean inBandRing) { + this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing, inBandRing); } public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state, - String number, boolean multiParty, boolean outgoing) { + String number, boolean multiParty, boolean outgoing, boolean inBandRing) { mDevice = device; mId = id; mUUID = uuid; @@ -91,6 +92,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable { mNumber = number != null ? number : ""; mMultiParty = multiParty; mOutgoing = outgoing; + mInBandRing = inBandRing; mCreationElapsedMilli = SystemClock.elapsedRealtime(); } @@ -200,6 +202,16 @@ public final class BluetoothHeadsetClientCall implements Parcelable { return mOutgoing; } + /** + * Checks if the ringtone will be generated by the connected phone + * + * @return <code>true</code> if in band ring is enabled, <code>false</code> otherwise. + */ + public boolean isInBandRing() { + return mInBandRing; + } + + @Override public String toString() { return toString(false); @@ -253,6 +265,8 @@ public final class BluetoothHeadsetClientCall implements Parcelable { builder.append(mMultiParty); builder.append(", mOutgoing: "); builder.append(mOutgoing); + builder.append(", mInBandRing: "); + builder.append(mInBandRing); builder.append("}"); return builder.toString(); } @@ -266,7 +280,8 @@ public final class BluetoothHeadsetClientCall implements Parcelable { public BluetoothHeadsetClientCall createFromParcel(Parcel in) { return new BluetoothHeadsetClientCall((BluetoothDevice) in.readParcelable(null), in.readInt(), UUID.fromString(in.readString()), in.readInt(), - in.readString(), in.readInt() == 1, in.readInt() == 1); + in.readString(), in.readInt() == 1, in.readInt() == 1, + in.readInt() == 1); } @Override @@ -284,6 +299,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable { out.writeString(mNumber); out.writeInt(mMultiParty ? 1 : 0); out.writeInt(mOutgoing ? 1 : 0); + out.writeInt(mInBandRing ? 1 : 0); } @Override diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index df2028a55351..0e2263f773b8 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -19,6 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import java.util.List; @@ -157,12 +158,19 @@ public interface BluetoothProfile { public static final int HID_DEVICE = 19; /** + * Object Push Profile (OPP) + * + * @hide + */ + public static final int OPP = 20; + + /** * Max profile ID. This value should be updated whenever a new profile is added to match * the largest value assigned to a profile. * * @hide */ - public static final int MAX_PROFILE_ID = 19; + public static final int MAX_PROFILE_ID = 20; /** * Default priority for devices that we try to auto-connect to and @@ -178,6 +186,7 @@ public interface BluetoothProfile { * * @hide **/ + @SystemApi public static final int PRIORITY_ON = 100; /** @@ -186,6 +195,7 @@ public interface BluetoothProfile { * * @hide **/ + @SystemApi public static final int PRIORITY_OFF = 0; /** diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java index 58d090dc287b..ebb7f187aea5 100644 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ b/core/java/android/bluetooth/BluetoothServerSocket.java @@ -68,6 +68,7 @@ import java.io.IOException; public final class BluetoothServerSocket implements Closeable { private static final String TAG = "BluetoothServerSocket"; + private static final boolean DBG = false; /*package*/ final BluetoothSocket mSocket; private Handler mHandler; private int mMessage; @@ -169,6 +170,7 @@ public final class BluetoothServerSocket implements Closeable { * close any {@link BluetoothSocket} received from {@link #accept()}. */ public void close() throws IOException { + if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel); synchronized (this) { if (mHandler != null) { mHandler.obtainMessage(mMessage).sendToTarget(); @@ -197,6 +199,20 @@ public final class BluetoothServerSocket implements Closeable { } /** + * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP + * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the + * {#link BluetoothAdapter.listenUsingL2capCoc(int)} or {#link + * BluetoothAdapter.listenUsingInsecureL2capCoc(int)}. The returned value is undefined if this + * method is called on non-L2CAP server sockets. + * + * @return the assigned PSM or LE_PSM value depending on transport + * @hide + */ + public int getPsm() { + return mChannel; + } + + /** * Sets the channel on which future sockets are bound. * Currently used only when a channel is auto generated. */ @@ -227,6 +243,10 @@ public final class BluetoothServerSocket implements Closeable { sb.append("TYPE_L2CAP"); break; } + case BluetoothSocket.TYPE_L2CAP_LE: { + sb.append("TYPE_L2CAP_LE"); + break; + } case BluetoothSocket.TYPE_SCO: { sb.append("TYPE_SCO"); break; diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 0569913435a8..09f96840f918 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -99,6 +99,16 @@ public final class BluetoothSocket implements Closeable { /** L2CAP socket */ public static final int TYPE_L2CAP = 3; + /** L2CAP socket on BR/EDR transport + * @hide + */ + public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP; + + /** L2CAP socket on LE transport + * @hide + */ + public static final int TYPE_L2CAP_LE = 4; + /*package*/ static final int EBADFD = 77; /*package*/ static final int EADDRINUSE = 98; @@ -417,6 +427,7 @@ public final class BluetoothSocket implements Closeable { return -1; } try { + if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType); mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName, mUuid, mPort, getSecurityFlags()); } catch (RemoteException e) { @@ -451,7 +462,7 @@ public final class BluetoothSocket implements Closeable { mSocketState = SocketState.LISTENING; } } - if (DBG) Log.d(TAG, "channel: " + channel); + if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort); if (mPort <= -1) { mPort = channel; } // else ASSERT(mPort == channel) @@ -515,7 +526,7 @@ public final class BluetoothSocket implements Closeable { /*package*/ int read(byte[] b, int offset, int length) throws IOException { int ret = 0; if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); - if (mType == TYPE_L2CAP) { + if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { int bytesToRead = length; if (VDBG) { Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length @@ -558,7 +569,7 @@ public final class BluetoothSocket implements Closeable { // Rfcomm uses dynamic allocation, and should not have any bindings // to the actual message length. if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); - if (mType == TYPE_L2CAP) { + if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { if (length <= mMaxTxPacketSize) { mSocketOS.write(b, offset, length); } else { @@ -702,7 +713,7 @@ public final class BluetoothSocket implements Closeable { } private void createL2capRxBuffer() { - if (mType == TYPE_L2CAP) { + if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) { // Allocate the buffer to use for reads. if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize); mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7e2ac6372841..70087daf5192 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3589,8 +3589,18 @@ public abstract class Context { public static final String EUICC_SERVICE = "euicc_service"; /** - * Use with {@link #getSystemService} to retrieve a - * {@link android.text.ClipboardManager} for accessing and modifying + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.telephony.euicc.EuiccCardManager} to access the device eUICC (embedded SIM). + * + * @see #getSystemService(String) + * @see android.telephony.euicc.EuiccCardManager + * TODO(b/35851809): Make this a SystemApi. + * @hide + */ + public static final String EUICC_CARD_SERVICE = "euicc_card_service"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.content.ClipboardManager} for accessing and modifying * the contents of the global clipboard. * diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 025d46d12567..4e8c45dc2c46 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -96,6 +96,11 @@ interface IUsbManager */ void setCurrentFunction(String function, boolean usbDataUnlocked); + /* Sets the screen unlocked USB function(s), which will be set automatically + * when the screen is unlocked. + */ + void setScreenUnlockedFunctions(String function); + /* Allow USB debugging from the attached host. If alwaysAllow is true, add the * the public key to list of host keys that the user has approved. */ diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index d73d3d8b04cf..48e8d342db65 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -590,6 +590,32 @@ public class UsbManager { } /** + * Sets the screen unlocked functions, which are persisted and set as the current functions + * whenever the screen is unlocked. + * <p> + * The allowed values are: {@link #USB_FUNCTION_NONE}, + * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP}, + * or {@link #USB_FUNCTION_RNDIS}. + * {@link #USB_FUNCTION_NONE} has the effect of switching off this feature, so functions + * no longer change on screen unlock. + * </p><p> + * Note: When the screen is on, this method will apply given functions as current functions, + * which is asynchronous and may fail silently without applying the requested changes. + * </p> + * + * @param function function to set as default + * + * {@hide} + */ + public void setScreenUnlockedFunctions(String function) { + try { + mService.setScreenUnlockedFunctions(function); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns a list of physical USB ports on the device. * <p> * This list is guaranteed to contain all dual-role USB Type C ports but it might diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 8071e8b83738..11d338d05c68 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1794,7 +1794,7 @@ public class ConnectivityManager { ITelephony it = ITelephony.Stub.asInterface(b); int subId = SubscriptionManager.getDefaultDataSubscriptionId(); Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId); - boolean retVal = it.getDataEnabled(subId); + boolean retVal = it.isUserDataEnabled(subId); Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId + " retVal=" + retVal); return retVal; diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index d9b57db18071..790c80b1d934 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -31,7 +31,7 @@ import android.os.ParcelFileDescriptor; interface IIpSecService { IpSecSpiResponse allocateSecurityParameterIndex( - int direction, in String remoteAddress, int requestedSpi, in IBinder binder); + in String destinationAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); @@ -43,7 +43,7 @@ interface IIpSecService void deleteTransportModeTransform(int transformId); - void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); - void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index f82627b942c3..c69a4d4c0bee 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -231,13 +231,44 @@ public final class IpSecAlgorithm implements Parcelable { } } + /** @hide */ + public boolean isAuthentication() { + switch (getName()) { + // Fallthrough + case AUTH_HMAC_MD5: + case AUTH_HMAC_SHA1: + case AUTH_HMAC_SHA256: + case AUTH_HMAC_SHA384: + case AUTH_HMAC_SHA512: + return true; + default: + return false; + } + } + + /** @hide */ + public boolean isEncryption() { + return getName().equals(CRYPT_AES_CBC); + } + + /** @hide */ + public boolean isAead() { + return getName().equals(AUTH_CRYPT_AES_GCM); + } + + // Because encryption keys are sensitive and userdebug builds are used by large user pools + // such as beta testers, we only allow sensitive info such as keys on eng builds. + private static boolean isUnsafeBuild() { + return Build.IS_DEBUGGABLE && Build.IS_ENG; + } + @Override public String toString() { return new StringBuilder() .append("{mName=") .append(mName) .append(", mKey=") - .append(Build.IS_DEBUGGABLE ? HexDump.toHexString(mKey) : "<hidden>") + .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>") .append(", mTruncLenBits=") .append(mTruncLenBits) .append("}") diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index f54ceb5c142a..80b0af33735b 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -32,59 +32,29 @@ public final class IpSecConfig implements Parcelable { // MODE_TRANSPORT or MODE_TUNNEL private int mMode = IpSecTransform.MODE_TRANSPORT; - // Needs to be valid only for tunnel mode // Preventing this from being null simplifies Java->Native binder - private String mLocalAddress = ""; + private String mSourceAddress = ""; // Preventing this from being null simplifies Java->Native binder - private String mRemoteAddress = ""; + private String mDestinationAddress = ""; // The underlying Network that represents the "gateway" Network // for outbound packets. It may also be used to select packets. private Network mNetwork; - /** - * This class captures the parameters that specifically apply to inbound or outbound traffic. - */ - public static class Flow { - // Minimum requirements for identifying a transform - // SPI identifying the IPsec flow in packet processing - // and a remote IP address - private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; - - // Encryption Algorithm - private IpSecAlgorithm mEncryption; - - // Authentication Algorithm - private IpSecAlgorithm mAuthentication; - - // Authenticated Encryption Algorithm - private IpSecAlgorithm mAuthenticatedEncryption; - - @Override - public String toString() { - return new StringBuilder() - .append("{mSpiResourceId=") - .append(mSpiResourceId) - .append(", mEncryption=") - .append(mEncryption) - .append(", mAuthentication=") - .append(mAuthentication) - .append(", mAuthenticatedEncryption=") - .append(mAuthenticatedEncryption) - .append("}") - .toString(); - } - - static boolean equals(IpSecConfig.Flow lhs, IpSecConfig.Flow rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return (lhs.mSpiResourceId == rhs.mSpiResourceId - && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); - } - } + // Minimum requirements for identifying a transform + // SPI identifying the IPsec SA in packet processing + // and a destination IP address + private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; + + // Encryption Algorithm + private IpSecAlgorithm mEncryption; + + // Authentication Algorithm + private IpSecAlgorithm mAuthentication; - private final Flow[] mFlow = new Flow[] {new Flow(), new Flow()}; + // Authenticated Encryption Algorithm + private IpSecAlgorithm mAuthenticatedEncryption; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE @@ -100,36 +70,37 @@ public final class IpSecConfig implements Parcelable { mMode = mode; } - /** Set the local IP address for Tunnel mode */ - public void setLocalAddress(String localAddress) { - mLocalAddress = localAddress; + /** Set the source IP addres for this IPsec transform */ + public void setSourceAddress(String sourceAddress) { + mSourceAddress = sourceAddress; } - /** Set the remote IP address for this IPsec transform */ - public void setRemoteAddress(String remoteAddress) { - mRemoteAddress = remoteAddress; + /** Set the destination IP address for this IPsec transform */ + public void setDestinationAddress(String destinationAddress) { + mDestinationAddress = destinationAddress; } - /** Set the SPI for a given direction by resource ID */ - public void setSpiResourceId(int direction, int resourceId) { - mFlow[direction].mSpiResourceId = resourceId; + /** Set the SPI by resource ID */ + public void setSpiResourceId(int resourceId) { + mSpiResourceId = resourceId; } - /** Set the encryption algorithm for a given direction */ - public void setEncryption(int direction, IpSecAlgorithm encryption) { - mFlow[direction].mEncryption = encryption; + /** Set the encryption algorithm */ + public void setEncryption(IpSecAlgorithm encryption) { + mEncryption = encryption; } - /** Set the authentication algorithm for a given direction */ - public void setAuthentication(int direction, IpSecAlgorithm authentication) { - mFlow[direction].mAuthentication = authentication; + /** Set the authentication algorithm */ + public void setAuthentication(IpSecAlgorithm authentication) { + mAuthentication = authentication; } - /** Set the authenticated encryption algorithm for a given direction */ - public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) { - mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption; + /** Set the authenticated encryption algorithm */ + public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) { + mAuthenticatedEncryption = authenticatedEncryption; } + /** Set the underlying network that will carry traffic for this transform */ public void setNetwork(Network network) { mNetwork = network; } @@ -155,28 +126,28 @@ public final class IpSecConfig implements Parcelable { return mMode; } - public String getLocalAddress() { - return mLocalAddress; + public String getSourceAddress() { + return mSourceAddress; } - public int getSpiResourceId(int direction) { - return mFlow[direction].mSpiResourceId; + public int getSpiResourceId() { + return mSpiResourceId; } - public String getRemoteAddress() { - return mRemoteAddress; + public String getDestinationAddress() { + return mDestinationAddress; } - public IpSecAlgorithm getEncryption(int direction) { - return mFlow[direction].mEncryption; + public IpSecAlgorithm getEncryption() { + return mEncryption; } - public IpSecAlgorithm getAuthentication(int direction) { - return mFlow[direction].mAuthentication; + public IpSecAlgorithm getAuthentication() { + return mAuthentication; } - public IpSecAlgorithm getAuthenticatedEncryption(int direction) { - return mFlow[direction].mAuthenticatedEncryption; + public IpSecAlgorithm getAuthenticatedEncryption() { + return mAuthenticatedEncryption; } public Network getNetwork() { @@ -209,17 +180,13 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mMode); - out.writeString(mLocalAddress); - out.writeString(mRemoteAddress); + out.writeString(mSourceAddress); + out.writeString(mDestinationAddress); out.writeParcelable(mNetwork, flags); - out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags); - out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags); + out.writeInt(mSpiResourceId); + out.writeParcelable(mEncryption, flags); + out.writeParcelable(mAuthentication, flags); + out.writeParcelable(mAuthenticatedEncryption, flags); out.writeInt(mEncapType); out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); @@ -231,22 +198,15 @@ public final class IpSecConfig implements Parcelable { private IpSecConfig(Parcel in) { mMode = in.readInt(); - mLocalAddress = in.readString(); - mRemoteAddress = in.readString(); + mSourceAddress = in.readString(); + mDestinationAddress = in.readString(); mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt(); - mFlow[IpSecTransform.DIRECTION_IN].mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt(); - mFlow[IpSecTransform.DIRECTION_OUT].mEncryption = + mSpiResourceId = in.readInt(); + mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication = + mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption = + mAuthenticatedEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); @@ -260,10 +220,10 @@ public final class IpSecConfig implements Parcelable { strBuilder .append("{mMode=") .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) + .append(", mSourceAddress=") + .append(mSourceAddress) + .append(", mDestinationAddress=") + .append(mDestinationAddress) .append(", mNetwork=") .append(mNetwork) .append(", mEncapType=") @@ -274,10 +234,14 @@ public final class IpSecConfig implements Parcelable { .append(mEncapRemotePort) .append(", mNattKeepaliveInterval=") .append(mNattKeepaliveInterval) - .append(", mFlow[OUT]=") - .append(mFlow[IpSecTransform.DIRECTION_OUT]) - .append(", mFlow[IN]=") - .append(mFlow[IpSecTransform.DIRECTION_IN]) + .append("{mSpiResourceId=") + .append(mSpiResourceId) + .append(", mEncryption=") + .append(mEncryption) + .append(", mAuthentication=") + .append(mAuthentication) + .append(", mAuthenticatedEncryption=") + .append(mAuthenticatedEncryption) .append("}"); return strBuilder.toString(); @@ -299,17 +263,18 @@ public final class IpSecConfig implements Parcelable { public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { if (lhs == null || rhs == null) return (lhs == rhs); return (lhs.mMode == rhs.mMode - && lhs.mLocalAddress.equals(rhs.mLocalAddress) - && lhs.mRemoteAddress.equals(rhs.mRemoteAddress) + && lhs.mSourceAddress.equals(rhs.mSourceAddress) + && lhs.mDestinationAddress.equals(rhs.mDestinationAddress) && ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork)) || (lhs.mNetwork == rhs.mNetwork)) && lhs.mEncapType == rhs.mEncapType && lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId && lhs.mEncapRemotePort == rhs.mEncapRemotePort && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval - && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_OUT], - rhs.mFlow[IpSecTransform.DIRECTION_OUT]) - && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_IN], - rhs.mFlow[IpSecTransform.DIRECTION_IN])); + && lhs.mSpiResourceId == rhs.mSpiResourceId + && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) + && IpSecAlgorithm.equals( + lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) + && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); } } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 34cfa9b2153d..2cda58c99a61 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -17,6 +17,7 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemService; import android.annotation.TestApi; @@ -33,6 +34,8 @@ import dalvik.system.CloseGuard; import java.io.FileDescriptor; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; @@ -53,6 +56,23 @@ public final class IpSecManager { private static final String TAG = "IpSecManager"; /** + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic towards the host. + */ + public static final int DIRECTION_IN = 0; + + /** + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic from the host. + */ + public static final int DIRECTION_OUT = 1; + + /** @hide */ + @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) + @Retention(RetentionPolicy.SOURCE) + public @interface PolicyDirection {} + + /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * * <p>No IPsec packet may contain an SPI of 0. @@ -125,7 +145,7 @@ public final class IpSecManager { */ public static final class SecurityParameterIndex implements AutoCloseable { private final IIpSecService mService; - private final InetAddress mRemoteAddress; + private final InetAddress mDestinationAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId = INVALID_RESOURCE_ID; @@ -164,14 +184,14 @@ public final class IpSecManager { } private SecurityParameterIndex( - @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) + @NonNull IIpSecService service, InetAddress destinationAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; - mRemoteAddress = remoteAddress; + mDestinationAddress = destinationAddress; try { IpSecSpiResponse result = mService.allocateSecurityParameterIndex( - direction, remoteAddress.getHostAddress(), spi, new Binder()); + destinationAddress.getHostAddress(), spi, new Binder()); if (result == null) { throw new NullPointerException("Received null response from IpSecService"); @@ -216,25 +236,23 @@ public final class IpSecManager { } /** - * Reserve a random SPI for traffic bound to or from the specified remote address. + * Reserve a random SPI for traffic bound to or from the specified destination address. * * <p>If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress + * @param destinationAddress the destination address for traffic bearing the requested SPI. + * For inbound traffic, the destination should be an address currently assigned on-device. * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated - * for this user - * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved + * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * currently allocated for this user */ - public SecurityParameterIndex allocateSecurityParameterIndex( - int direction, InetAddress remoteAddress) throws ResourceUnavailableException { + public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress) + throws ResourceUnavailableException { try { return new SecurityParameterIndex( mService, - direction, - remoteAddress, + destinationAddress, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); } catch (SpiUnavailableException unlikely) { throw new ResourceUnavailableException("No SPIs available"); @@ -242,26 +260,27 @@ public final class IpSecManager { } /** - * Reserve the requested SPI for traffic bound to or from the specified remote address. + * Reserve the requested SPI for traffic bound to or from the specified destination address. * * <p>If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress + * @param destinationAddress the destination address for traffic bearing the requested SPI. + * For inbound traffic, the destination should be an address currently assigned on-device. * @param requestedSpi the requested SPI, or '0' to allocate a random SPI * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated - * for this user - * @throws SpiUnavailableException indicating that the requested SPI could not be reserved + * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * currently allocated for this user + * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be + * reserved */ public SecurityParameterIndex allocateSecurityParameterIndex( - int direction, InetAddress remoteAddress, int requestedSpi) + InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); } - return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); } /** @@ -269,14 +288,14 @@ public final class IpSecManager { * * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * * <p>For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * * <h4>Rekey Procedure</h4> * @@ -287,15 +306,14 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a stream socket + * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied - * @hide */ - public void applyTransportModeTransform(Socket socket, IpSecTransform transform) + public void applyTransportModeTransform( + Socket socket, int direction, IpSecTransform transform) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - applyTransportModeTransform(pfd, transform); - } + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } /** @@ -303,14 +321,14 @@ public final class IpSecManager { * * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * * <p>For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * * <h4>Rekey Procedure</h4> * @@ -321,15 +339,13 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a datagram socket + * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied - * @hide */ - public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) - throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - applyTransportModeTransform(pfd, transform); - } + public void applyTransportModeTransform( + DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } /** @@ -337,14 +353,14 @@ public final class IpSecManager { * * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * * <p>For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * * <h4>Rekey Procedure</h4> * @@ -355,24 +371,17 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a socket file descriptor + * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + public void applyTransportModeTransform( + FileDescriptor socket, int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() - // constructor takes control and closes the user's FD when we exit the method - // This is behaviorally the same as the other versions, but the PFD constructor does not - // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup(). + // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - applyTransportModeTransform(pfd, transform); - } - } - - /* Call down to activate a transform */ - private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { - try { - mService.applyTransportModeTransform(pfd, transform.getResourceId()); + mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -396,75 +405,56 @@ public final class IpSecManager { /** * Remove an IPsec transform from a stream socket. * - * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket - * @hide */ - public void removeTransportModeTransform(Socket socket, IpSecTransform transform) + public void removeTransportModeTransforms(Socket socket) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - removeTransportModeTransform(pfd, transform); - } + removeTransportModeTransforms(socket.getFileDescriptor$()); } /** * Remove an IPsec transform from a datagram socket. * - * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket - * @hide */ - public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) + public void removeTransportModeTransforms(DatagramSocket socket) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - removeTransportModeTransform(pfd, transform); - } + removeTransportModeTransforms(socket.getFileDescriptor$()); } /** * Remove an IPsec transform from a socket. * - * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + public void removeTransportModeTransforms(FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - removeTransportModeTransform(pfd, transform); - } - } - - /* Call down to remove a transform */ - private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { - try { - mService.removeTransportModeTransform(pfd, transform.getResourceId()); + mService.removeTransportModeTransforms(pfd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 102ba6d94faa..7b9b4830929d 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -38,13 +38,11 @@ import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; /** - * This class represents an IPsec transform, which comprises security associations in one or both - * directions. + * This class represents a transform, which roughly corresponds to an IPsec Security Association. * * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} - * object encapsulates the properties and state of an inbound and outbound IPsec security - * association. That includes, but is not limited to, algorithm choice, key material, and allocated - * system resources. + * object encapsulates the properties and state of an IPsec security association. That includes, + * but is not limited to, algorithm choice, key material, and allocated system resources. * * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the * Internet Protocol</a> @@ -52,23 +50,6 @@ import java.net.InetAddress; public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; - /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic towards the host. - */ - public static final int DIRECTION_IN = 0; - - /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic from the host. - */ - public static final int DIRECTION_OUT = 1; - - /** @hide */ - @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface TransformDirection {} - /** @hide */ public static final int MODE_TRANSPORT = 0; @@ -170,7 +151,7 @@ public final class IpSecTransform implements AutoCloseable { * * <p>Deactivating a transform while it is still applied to a socket will result in errors on * that socket. Make sure to remove transforms by calling {@link - * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a + * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a * socket will not deactivate it (because one transform may be applied to multiple sockets). * * <p>It is safe to call this method on a transform that has already been deactivated. @@ -272,85 +253,49 @@ public final class IpSecTransform implements AutoCloseable { private IpSecConfig mConfig; /** - * Set the encryption algorithm for the given direction. - * - * <p>If encryption is set for a direction without also providing an SPI for that direction, - * creation of an {@code IpSecTransform} will fail when attempting to build the transform. + * Set the encryption algorithm. * * <p>Encryption is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ - public IpSecTransform.Builder setEncryption( - @TransformDirection int direction, IpSecAlgorithm algo) { + public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - mConfig.setEncryption(direction, algo); + Preconditions.checkNotNull(algo); + mConfig.setEncryption(algo); return this; } /** - * Set the authentication (integrity) algorithm for the given direction. - * - * <p>If authentication is set for a direction without also providing an SPI for that - * direction, creation of an {@code IpSecTransform} will fail when attempting to build the - * transform. + * Set the authentication (integrity) algorithm. * * <p>Authentication is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ - public IpSecTransform.Builder setAuthentication( - @TransformDirection int direction, IpSecAlgorithm algo) { + public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - mConfig.setAuthentication(direction, algo); + Preconditions.checkNotNull(algo); + mConfig.setAuthentication(algo); return this; } /** - * Set the authenticated encryption algorithm for the given direction. - * - * <p>If an authenticated encryption algorithm is set for a given direction without also - * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when - * attempting to build the transform. + * Set the authenticated encryption algorithm. * - * <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated - * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as - * referred to in <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>). + * <p>The Authenticated Encryption (AE) class of algorithms are also known as + * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode + * algorithms (as referred to in + * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>). * * <p>Authenticated encryption is mutually exclusive with encryption and authentication. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * be applied. */ - public IpSecTransform.Builder setAuthenticatedEncryption( - @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.setAuthenticatedEncryption(direction, algo); - return this; - } - - /** - * Set the SPI for the given direction. - * - * <p>Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies - * packets to a given destination address. To prevent SPI collisions, values should be - * reserved by calling {@link IpSecManager#allocateSecurityParameterIndex}. - * - * <p>If the SPI and algorithms are omitted for one direction, traffic in that direction - * will not be encrypted or authenticated. - * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - */ - public IpSecTransform.Builder setSpi( - @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setSpiResourceId(direction, spi.getResourceId()); + public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { + Preconditions.checkNotNull(algo); + mConfig.setAuthenticatedEncryption(algo); return this; } @@ -363,7 +308,8 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi - public IpSecTransform.Builder setUnderlyingNetwork(Network net) { + public IpSecTransform.Builder setUnderlyingNetwork(@NonNull Network net) { + Preconditions.checkNotNull(net); mConfig.setNetwork(net); return this; } @@ -382,7 +328,8 @@ public final class IpSecTransform implements AutoCloseable { * encapsulated traffic. In the case of IKEv2, this should be port 4500. */ public IpSecTransform.Builder setIpv4Encapsulation( - IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { + @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { + Preconditions.checkNotNull(localSocket); mConfig.setEncapType(ENCAP_ESPINUDP); if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); @@ -419,24 +366,33 @@ public final class IpSecTransform implements AutoCloseable { * will not affect any network traffic until it has been applied to one or more sockets. * * @see IpSecManager#applyTransportModeTransform - * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use - * this transform + * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use + * this transform; this address must belong to the Network used by all sockets that + * utilize this transform; if provided, then only traffic originating from the + * specified source address will be processed. + * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed + * traffic * @throws IllegalArgumentException indicating that a particular combination of transform * properties is invalid - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are - * active + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms + * are active * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI * collides with an existing transform * @throws IOException indicating other errors */ - public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) + public IpSecTransform buildTransportModeTransform( + @NonNull InetAddress sourceAddress, + @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - if (remoteAddress == null) { - throw new IllegalArgumentException("Remote address may not be null or empty!"); + Preconditions.checkNotNull(sourceAddress); + Preconditions.checkNotNull(spi); + if (spi.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } mConfig.setMode(MODE_TRANSPORT); - mConfig.setRemoteAddress(remoteAddress.getHostAddress()); + mConfig.setSourceAddress(sourceAddress.getHostAddress()); + mConfig.setSpiResourceId(spi.getResourceId()); // FIXME: modifying a builder after calling build can change the built transform. return new IpSecTransform(mContext, mConfig).activate(); } @@ -445,26 +401,33 @@ public final class IpSecTransform implements AutoCloseable { * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some * parameters have interdependencies that are checked at build time. * - * @param localAddress the {@link InetAddress} that provides the local endpoint for this + * @param sourceAddress the {@link InetAddress} that provides the source address for this * IPsec tunnel. This is almost certainly an address belonging to the {@link Network} * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. - * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this - * IPsec tunnel. + * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed + * traffic * @throws IllegalArgumentException indicating that a particular combination of transform * properties is invalid. + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms + * are active + * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI + * collides with an existing transform + * @throws IOException indicating other errors * @hide */ public IpSecTransform buildTunnelModeTransform( - InetAddress localAddress, InetAddress remoteAddress) { - if (localAddress == null) { - throw new IllegalArgumentException("Local address may not be null or empty!"); - } - if (remoteAddress == null) { - throw new IllegalArgumentException("Remote address may not be null or empty!"); + @NonNull InetAddress sourceAddress, + @NonNull IpSecManager.SecurityParameterIndex spi) + throws IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException, IOException { + Preconditions.checkNotNull(sourceAddress); + Preconditions.checkNotNull(spi); + if (spi.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } - mConfig.setLocalAddress(localAddress.getHostAddress()); - mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setMode(MODE_TUNNEL); + mConfig.setSourceAddress(sourceAddress.getHostAddress()); + mConfig.setSpiResourceId(spi.getResourceId()); return new IpSecTransform(mContext, mConfig); } diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 4e474c8e478c..f525b1f37518 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -50,6 +50,8 @@ public final class LinkProperties implements Parcelable { private String mIfaceName; private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>(); + private boolean mUsePrivateDns; + private String mPrivateDnsServerName; private String mDomains; private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); private ProxyInfo mHttpProxy; @@ -165,6 +167,8 @@ public final class LinkProperties implements Parcelable { mIfaceName = source.getInterfaceName(); for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); for (InetAddress i : source.getDnsServers()) mDnses.add(i); + mUsePrivateDns = source.mUsePrivateDns; + mPrivateDnsServerName = source.mPrivateDnsServerName; mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? @@ -391,6 +395,59 @@ public final class LinkProperties implements Parcelable { } /** + * Set whether private DNS is currently in use on this network. + * + * @param usePrivateDns The private DNS state. + * @hide + */ + public void setUsePrivateDns(boolean usePrivateDns) { + mUsePrivateDns = usePrivateDns; + } + + /** + * Returns whether private DNS is currently in use on this network. When + * private DNS is in use, applications must not send unencrypted DNS + * queries as doing so could reveal private user information. Furthermore, + * if private DNS is in use and {@link #getPrivateDnsServerName} is not + * {@code null}, DNS queries must be sent to the specified DNS server. + * + * @return {@code true} if private DNS is in use, {@code false} otherwise. + */ + public boolean isPrivateDnsActive() { + return mUsePrivateDns; + } + + /** + * Set the name of the private DNS server to which private DNS queries + * should be sent when in strict mode. This value should be {@code null} + * when private DNS is off or in opportunistic mode. + * + * @param privateDnsServerName The private DNS server name. + * @hide + */ + public void setPrivateDnsServerName(@Nullable String privateDnsServerName) { + mPrivateDnsServerName = privateDnsServerName; + } + + /** + * Returns the private DNS server name that is in use. If not {@code null}, + * private DNS is in strict mode. In this mode, applications should ensure + * that all DNS queries are encrypted and sent to this hostname and that + * queries are only sent if the hostname's certificate is valid. If + * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private + * DNS is in opportunistic mode, and applications should ensure that DNS + * queries are encrypted and sent to a DNS server returned by + * {@link #getDnsServers}. System DNS will handle each of these cases + * correctly, but applications implementing their own DNS lookups must make + * sure to follow these requirements. + * + * @return The private DNS server name. + */ + public @Nullable String getPrivateDnsServerName() { + return mPrivateDnsServerName; + } + + /** * Sets the DNS domain search path used on this link. * * @param domains A {@link String} listing in priority order the comma separated @@ -622,6 +679,8 @@ public final class LinkProperties implements Parcelable { mIfaceName = null; mLinkAddresses.clear(); mDnses.clear(); + mUsePrivateDns = false; + mPrivateDnsServerName = null; mDomains = null; mRoutes.clear(); mHttpProxy = null; @@ -649,6 +708,13 @@ public final class LinkProperties implements Parcelable { for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; dns += "] "; + String usePrivateDns = "UsePrivateDns: " + mUsePrivateDns + " "; + + String privateDnsServerName = ""; + if (privateDnsServerName != null) { + privateDnsServerName = "PrivateDnsServerName: " + mPrivateDnsServerName + " "; + } + String domainName = "Domains: " + mDomains; String mtu = " MTU: " + mMtu; @@ -671,8 +737,9 @@ public final class LinkProperties implements Parcelable { } stacked += "] "; } - return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu - + tcpBuffSizes + proxy + stacked + "}"; + return "{" + ifaceName + linkAddresses + routes + dns + usePrivateDns + + privateDnsServerName + domainName + mtu + tcpBuffSizes + proxy + + stacked + "}"; } /** @@ -896,6 +963,20 @@ public final class LinkProperties implements Parcelable { } /** + * Compares this {@code LinkProperties} private DNS settings against the + * target. + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalPrivateDns(LinkProperties target) { + return (isPrivateDnsActive() == target.isPrivateDnsActive() + && TextUtils.equals(getPrivateDnsServerName(), + target.getPrivateDnsServerName())); + } + + /** * Compares this {@code LinkProperties} Routes against the target * * @param target LinkProperties to compare. @@ -989,14 +1070,15 @@ public final class LinkProperties implements Parcelable { * stacked interfaces are not so much a property of the link as a * description of connections between links. */ - return isIdenticalInterfaceName(target) && - isIdenticalAddresses(target) && - isIdenticalDnses(target) && - isIdenticalRoutes(target) && - isIdenticalHttpProxy(target) && - isIdenticalStackedLinks(target) && - isIdenticalMtu(target) && - isIdenticalTcpBufferSizes(target); + return isIdenticalInterfaceName(target) + && isIdenticalAddresses(target) + && isIdenticalDnses(target) + && isIdenticalPrivateDns(target) + && isIdenticalRoutes(target) + && isIdenticalHttpProxy(target) + && isIdenticalStackedLinks(target) + && isIdenticalMtu(target) + && isIdenticalTcpBufferSizes(target); } /** @@ -1091,7 +1173,9 @@ public final class LinkProperties implements Parcelable { + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) + mStackedLinks.hashCode() * 47) + mMtu * 51 - + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()); + + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) + + (mUsePrivateDns ? 57 : 0) + + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()); } /** @@ -1108,6 +1192,8 @@ public final class LinkProperties implements Parcelable { for(InetAddress d : mDnses) { dest.writeByteArray(d.getAddress()); } + dest.writeBoolean(mUsePrivateDns); + dest.writeString(mPrivateDnsServerName); dest.writeString(mDomains); dest.writeInt(mMtu); dest.writeString(mTcpBufferSizes); @@ -1148,6 +1234,8 @@ public final class LinkProperties implements Parcelable { netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray())); } catch (UnknownHostException e) { } } + netProp.setUsePrivateDns(in.readBoolean()); + netProp.setPrivateDnsServerName(in.readString()); netProp.setDomains(in.readString()); netProp.setMtu(in.readInt()); netProp.setTcpBufferSizes(in.readString()); diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index d6992aaede5f..287bdc88dd3e 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.IntDef; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -60,7 +61,7 @@ public final class MacAddress implements Parcelable { }) public @interface MacAddressType { } - /** Indicates a MAC address of unknown type. */ + /** @hide Indicates a MAC address of unknown type. */ public static final int TYPE_UNKNOWN = 0; /** Indicates a MAC address is a unicast address. */ public static final int TYPE_UNICAST = 1; @@ -92,7 +93,7 @@ public final class MacAddress implements Parcelable { * * @return the int constant representing the MAC address type of this MacAddress. */ - public @MacAddressType int addressType() { + public @MacAddressType int getAddressType() { if (equals(BROADCAST_ADDRESS)) { return TYPE_BROADCAST; } @@ -120,12 +121,12 @@ public final class MacAddress implements Parcelable { /** * @return a byte array representation of this MacAddress. */ - public byte[] toByteArray() { + public @NonNull byte[] toByteArray() { return byteAddrFromLongAddr(mAddr); } @Override - public String toString() { + public @NonNull String toString() { return stringAddrFromLongAddr(mAddr); } @@ -133,7 +134,7 @@ public final class MacAddress implements Parcelable { * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal * numbers in [0,ff] joined by ':' characters. */ - public String toOuiString() { + public @NonNull String toOuiString() { return String.format( "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff); } @@ -197,7 +198,7 @@ public final class MacAddress implements Parcelable { if (!isMacAddress(addr)) { return TYPE_UNKNOWN; } - return MacAddress.fromBytes(addr).addressType(); + return MacAddress.fromBytes(addr).getAddressType(); } /** @@ -211,7 +212,7 @@ public final class MacAddress implements Parcelable { * * @hide */ - public static byte[] byteAddrFromStringAddr(String addr) { + public static @NonNull byte[] byteAddrFromStringAddr(String addr) { Preconditions.checkNotNull(addr); String[] parts = addr.split(":"); if (parts.length != ETHER_ADDR_LEN) { @@ -239,7 +240,7 @@ public final class MacAddress implements Parcelable { * * @hide */ - public static String stringAddrFromByteAddr(byte[] addr) { + public static @NonNull String stringAddrFromByteAddr(byte[] addr) { if (!isMacAddress(addr)) { return null; } @@ -291,7 +292,7 @@ public final class MacAddress implements Parcelable { // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr)) // that avoids the allocation of an intermediary byte[]. - private static String stringAddrFromLongAddr(long addr) { + private static @NonNull String stringAddrFromLongAddr(long addr) { return String.format("%02x:%02x:%02x:%02x:%02x:%02x", (addr >> 40) & 0xff, (addr >> 32) & 0xff, @@ -310,7 +311,7 @@ public final class MacAddress implements Parcelable { * @return the MacAddress corresponding to the given String representation. * @throws IllegalArgumentException if the given String is not a valid representation. */ - public static MacAddress fromString(String addr) { + public static @NonNull MacAddress fromString(@NonNull String addr) { return new MacAddress(longAddrFromStringAddr(addr)); } @@ -322,7 +323,7 @@ public final class MacAddress implements Parcelable { * @return the MacAddress corresponding to the given byte array representation. * @throws IllegalArgumentException if the given byte array is not a valid representation. */ - public static MacAddress fromBytes(byte[] addr) { + public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) { return new MacAddress(longAddrFromByteAddr(addr)); } @@ -336,7 +337,7 @@ public final class MacAddress implements Parcelable { * * @hide */ - public static MacAddress createRandomUnicastAddress() { + public static @NonNull MacAddress createRandomUnicastAddress() { return createRandomUnicastAddress(BASE_GOOGLE_MAC, new Random()); } @@ -352,7 +353,7 @@ public final class MacAddress implements Parcelable { * * @hide */ - public static MacAddress createRandomUnicastAddress(MacAddress base, Random r) { + public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) { long addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()); addr = addr | LOCALLY_ASSIGNED_MASK; addr = addr & ~MULTICAST_MASK; diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 903b602b42f8..3683d3450b41 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -356,13 +356,13 @@ public class Network implements Parcelable { // Multiple Provisioning Domains API recommendations, as made by the // IETF mif working group. // - // The HANDLE_MAGIC value MUST be kept in sync with the corresponding + // The handleMagic value MUST be kept in sync with the corresponding // value in the native/android/net.c NDK implementation. if (netId == 0) { return 0L; // make this zero condition obvious for debugging } - final long HANDLE_MAGIC = 0xfacade; - return (((long) netId) << 32) | HANDLE_MAGIC; + final long handleMagic = 0xcafed00dL; + return (((long) netId) << 32) | handleMagic; } // implement the Parcelable interface diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 7c897de9b5e9..be85583a823f 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -107,6 +107,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_CAPTIVE_PORTAL, NET_CAPABILITY_NOT_ROAMING, NET_CAPABILITY_FOREGROUND, + NET_CAPABILITY_NOT_CONGESTED, }) public @interface NetCapability { } @@ -234,8 +235,17 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_FOREGROUND = 19; + /** + * Indicates that this network is not congested. + * <p> + * When a network is congested, the device should defer network traffic that + * can be done at a later time without breaking developer contracts. + * @hide + */ + public static final int NET_CAPABILITY_NOT_CONGESTED = 20; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_CONGESTED; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -248,7 +258,8 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_VALIDATED) | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) | (1 << NET_CAPABILITY_NOT_ROAMING) | - (1 << NET_CAPABILITY_FOREGROUND); + (1 << NET_CAPABILITY_FOREGROUND) | + (1 << NET_CAPABILITY_NOT_CONGESTED); /** * Network capabilities that are not allowed in NetworkRequests. This exists because the @@ -386,12 +397,9 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public String describeFirstNonRequestableCapability() { - if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED"; - if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL"; - if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND"; - // This cannot happen unless the preceding checks are incomplete. - if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) { - return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities); + final long nonRequestable = (mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES); + if (nonRequestable != 0) { + return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]); } if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth"; if (hasSignalStrength()) return "signalStrength"; @@ -1056,6 +1064,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; + case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; default: return Integer.toString(capability); } } diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java index 7277ba34534b..bb36536fe2ce 100644 --- a/core/java/android/net/metrics/WakeupStats.java +++ b/core/java/android/net/metrics/WakeupStats.java @@ -80,7 +80,7 @@ public class WakeupStats { break; } - switch (ev.dstHwAddr.addressType()) { + switch (ev.dstHwAddr.getAddressType()) { case MacAddress.TYPE_UNICAST: l2UnicastCount++; break; diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 5c4a40e503db..336e1b48251e 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -792,7 +792,7 @@ final class BinderProxy implements IBinder { /** * Return the total number of pairs in the map. */ - int size() { + private int size() { int size = 0; for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { if (a != null) { @@ -803,6 +803,24 @@ final class BinderProxy implements IBinder { } /** + * Return the total number of pairs in the map containing values that have + * not been cleared. More expensive than the above size function. + */ + private int unclearedSize() { + int size = 0; + for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { + if (a != null) { + for (WeakReference<BinderProxy> ref : a) { + if (ref.get() != null) { + ++size; + } + } + } + } + return size; + } + + /** * Remove ith entry from the hash bucket indicated by hash. */ private void remove(int hash, int index) { @@ -895,17 +913,31 @@ final class BinderProxy implements IBinder { Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size + " total = " + totalSize); mWarnBucketSize += WARN_INCREMENT; - if (Build.IS_DEBUGGABLE && totalSize > CRASH_AT_SIZE) { - diagnosticCrash(); + if (Build.IS_DEBUGGABLE && totalSize >= CRASH_AT_SIZE) { + // Use the number of uncleared entries to determine whether we should + // really report a histogram and crash. We don't want to fundamentally + // change behavior for a debuggable process, so we GC only if we are + // about to crash. + final int totalUnclearedSize = unclearedSize(); + if (totalUnclearedSize >= CRASH_AT_SIZE) { + dumpProxyInterfaceCounts(); + Runtime.getRuntime().gc(); + throw new AssertionError("Binder ProxyMap has too many entries: " + + totalSize + " (total), " + totalUnclearedSize + " (uncleared), " + + unclearedSize() + " (uncleared after GC). BinderProxy leak?"); + } else if (totalSize > 3 * totalUnclearedSize / 2) { + Log.v(Binder.TAG, "BinderProxy map has many cleared entries: " + + (totalSize - totalUnclearedSize) + " of " + totalSize + + " are cleared"); + } } } } /** - * Dump a histogram to the logcat, then throw an assertion error. Used to diagnose - * abnormally large proxy maps. + * Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps. */ - private void diagnosticCrash() { + private void dumpProxyInterfaceCounts() { Map<String, Integer> counts = new HashMap<>(); for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { if (a != null) { @@ -940,11 +972,6 @@ final class BinderProxy implements IBinder { Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i].getKey() + " x" + sorted[i].getValue()); } - - // Now throw an assertion. - final int totalSize = size(); - throw new AssertionError("Binder ProxyMap has too many entries: " + totalSize - + ". BinderProxy leak?"); } // Corresponding ArrayLists in the following two arrays always have the same size. diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index a474b47c4297..a5e1934ad5d6 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -339,7 +339,8 @@ interface INetworkManagementService /** * Configure name servers, search paths, and resolver parameters for the given network. */ - void setDnsConfigurationForNetwork(int netId, in String[] servers, String domains); + void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains, + in int[] params, boolean useTls, String tlsHostname); void setFirewallEnabled(boolean enabled); boolean isFirewallEnabled(); diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index 340f3fb8cd25..12a495bf2821 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -76,8 +76,8 @@ public class VintfObject { /** * @return a list of VNDK snapshots supported by the framework, as * specified in framework manifest. For example, - * [("25.0.5", ["libjpeg.so", "libbase.so"]), - * ("25.1.3", ["libjpeg.so", "libbase.so"])] + * [("27", ["libjpeg.so", "libbase.so"]), + * ("28", ["libjpeg.so", "libbase.so"])] */ public static native Map<String, String[]> getVndkSnapshots(); } diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java index b47e872d47f8..09bba4b459f6 100644 --- a/core/java/android/service/carrier/CarrierIdentifier.java +++ b/core/java/android/service/carrier/CarrierIdentifier.java @@ -16,9 +16,14 @@ package android.service.carrier; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.uicc.IccUtils; + +import java.util.Objects; + /** * Used to pass info to CarrierConfigService implementations so they can decide what values to * return. @@ -40,13 +45,13 @@ public class CarrierIdentifier implements Parcelable { private String mMcc; private String mMnc; - private String mSpn; - private String mImsi; - private String mGid1; - private String mGid2; + private @Nullable String mSpn; + private @Nullable String mImsi; + private @Nullable String mGid1; + private @Nullable String mGid2; - public CarrierIdentifier(String mcc, String mnc, String spn, String imsi, String gid1, - String gid2) { + public CarrierIdentifier(String mcc, String mnc, @Nullable String spn, @Nullable String imsi, + @Nullable String gid1, @Nullable String gid2) { mMcc = mcc; mMnc = mnc; mSpn = spn; @@ -55,6 +60,32 @@ public class CarrierIdentifier implements Parcelable { mGid2 = gid2; } + /** + * Creates a carrier identifier instance. + * + * @param mccMnc A 3-byte array as defined by 3GPP TS 24.008. + * @param gid1 The group identifier level 1. + * @param gid2 The group identifier level 2. + * @throws IllegalArgumentException If the length of {@code mccMnc} is not 3. + */ + public CarrierIdentifier(byte[] mccMnc, @Nullable String gid1, @Nullable String gid2) { + if (mccMnc.length != 3) { + throw new IllegalArgumentException( + "MCC & MNC must be set by a 3-byte array: byte[" + mccMnc.length + "]"); + } + String hex = IccUtils.bytesToHexString(mccMnc); + mMcc = new String(new char[] {hex.charAt(1), hex.charAt(0), hex.charAt(3)}); + if (hex.charAt(2) == 'F') { + mMnc = new String(new char[] {hex.charAt(5), hex.charAt(4)}); + } else { + mMnc = new String(new char[] {hex.charAt(5), hex.charAt(4), hex.charAt(2)}); + } + mGid1 = gid1; + mGid2 = gid2; + mSpn = null; + mImsi = null; + } + /** @hide */ public CarrierIdentifier(Parcel parcel) { readFromParcel(parcel); @@ -71,26 +102,60 @@ public class CarrierIdentifier implements Parcelable { } /** Get the service provider name. */ + @Nullable public String getSpn() { return mSpn; } /** Get the international mobile subscriber identity. */ + @Nullable public String getImsi() { return mImsi; } /** Get the group identifier level 1. */ + @Nullable public String getGid1() { return mGid1; } /** Get the group identifier level 2. */ + @Nullable public String getGid2() { return mGid2; } @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + CarrierIdentifier that = (CarrierIdentifier) obj; + return Objects.equals(mMcc, that.mMcc) + && Objects.equals(mMnc, that.mMnc) + && Objects.equals(mSpn, that.mSpn) + && Objects.equals(mImsi, that.mImsi) + && Objects.equals(mGid1, that.mGid1) + && Objects.equals(mGid2, that.mGid2); + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + Objects.hashCode(mMcc); + result = 31 * result + Objects.hashCode(mMnc); + result = 31 * result + Objects.hashCode(mSpn); + result = 31 * result + Objects.hashCode(mImsi); + result = 31 * result + Objects.hashCode(mGid1); + result = 31 * result + Objects.hashCode(mGid2); + return result; + } + + @Override public int describeContents() { return 0; } diff --git a/core/java/android/service/euicc/EuiccProfileInfo.aidl b/core/java/android/service/euicc/EuiccProfileInfo.aidl new file mode 100644 index 000000000000..321021b5273c --- /dev/null +++ b/core/java/android/service/euicc/EuiccProfileInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 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.service.euicc; + +parcelable EuiccProfileInfo; diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java index ba6c9a2d1b57..8e752d1c6c1d 100644 --- a/core/java/android/service/euicc/EuiccProfileInfo.java +++ b/core/java/android/service/euicc/EuiccProfileInfo.java @@ -15,12 +15,19 @@ */ package android.service.euicc; +import android.annotation.IntDef; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.service.carrier.CarrierIdentifier; import android.telephony.UiccAccessRule; import android.text.TextUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; + /** * Information about an embedded profile (subscription) on an eUICC. * @@ -30,18 +37,90 @@ import android.text.TextUtils; */ public final class EuiccProfileInfo implements Parcelable { + /** Profile policy rules (bit mask) */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "POLICY_RULE_" }, value = { + POLICY_RULE_DO_NOT_DISABLE, + POLICY_RULE_DO_NOT_DELETE, + POLICY_RULE_DELETE_AFTER_DISABLING + }) + public @interface PolicyRule {} + /** Once this profile is enabled, it cannot be disabled. */ + public static final int POLICY_RULE_DO_NOT_DISABLE = 1; + /** This profile cannot be deleted. */ + public static final int POLICY_RULE_DO_NOT_DELETE = 1 << 1; + /** This profile should be deleted after being disabled. */ + public static final int POLICY_RULE_DELETE_AFTER_DISABLING = 1 << 2; + + /** Class of the profile */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "PROFILE_CLASS_" }, value = { + PROFILE_CLASS_TESTING, + PROFILE_CLASS_PROVISIONING, + PROFILE_CLASS_OPERATIONAL, + PROFILE_CLASS_UNSET + }) + public @interface ProfileClass {} + /** Testing profiles */ + public static final int PROFILE_CLASS_TESTING = 0; + /** Provisioning profiles which are pre-loaded on eUICC */ + public static final int PROFILE_CLASS_PROVISIONING = 1; + /** Operational profiles which can be pre-loaded or downloaded */ + public static final int PROFILE_CLASS_OPERATIONAL = 2; + /** + * Profile class not set. + * @hide + */ + public static final int PROFILE_CLASS_UNSET = -1; + + /** State of the profile */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "PROFILE_STATE_" }, value = { + PROFILE_STATE_DISABLED, + PROFILE_STATE_ENABLED, + PROFILE_STATE_UNSET + }) + public @interface ProfileState {} + /** Disabled profiles */ + public static final int PROFILE_STATE_DISABLED = 0; + /** Enabled profile */ + public static final int PROFILE_STATE_ENABLED = 1; + /** + * Profile state not set. + * @hide + */ + public static final int PROFILE_STATE_UNSET = -1; + /** The iccid of the subscription. */ public final String iccid; + /** An optional nickname for the subscription. */ + public final @Nullable String nickname; + + /** The service provider name for the subscription. */ + public final String serviceProviderName; + + /** The profile name for the subscription. */ + public final String profileName; + + /** Profile class for the subscription. */ + @ProfileClass public final int profileClass; + + /** The profile state of the subscription. */ + @ProfileState public final int state; + + /** The operator Id of the subscription. */ + public final CarrierIdentifier carrierIdentifier; + + /** The policy rules of the subscription. */ + @PolicyRule public final int policyRules; + /** * Optional access rules defining which apps can manage this subscription. If unset, only the * platform can manage it. */ public final @Nullable UiccAccessRule[] accessRules; - /** An optional nickname for the subscription. */ - public final @Nullable String nickname; - public static final Creator<EuiccProfileInfo> CREATOR = new Creator<EuiccProfileInfo>() { @Override public EuiccProfileInfo createFromParcel(Parcel in) { @@ -54,6 +133,12 @@ public final class EuiccProfileInfo implements Parcelable { } }; + // TODO(b/70292228): Remove this method when LPA can be updated. + /** + * @hide + * @deprecated - Do not use. + */ + @Deprecated public EuiccProfileInfo(String iccid, @Nullable UiccAccessRule[] accessRules, @Nullable String nickname) { if (!TextUtils.isDigitsOnly(iccid)) { @@ -62,23 +147,290 @@ public final class EuiccProfileInfo implements Parcelable { this.iccid = iccid; this.accessRules = accessRules; this.nickname = nickname; + + this.serviceProviderName = null; + this.profileName = null; + this.profileClass = PROFILE_CLASS_UNSET; + this.state = PROFILE_CLASS_UNSET; + this.carrierIdentifier = null; + this.policyRules = 0; } private EuiccProfileInfo(Parcel in) { iccid = in.readString(); - accessRules = in.createTypedArray(UiccAccessRule.CREATOR); nickname = in.readString(); + serviceProviderName = in.readString(); + profileName = in.readString(); + profileClass = in.readInt(); + state = in.readInt(); + byte exist = in.readByte(); + if (exist == (byte) 1) { + carrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in); + } else { + carrierIdentifier = null; + } + policyRules = in.readInt(); + accessRules = in.createTypedArray(UiccAccessRule.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(iccid); - dest.writeTypedArray(accessRules, flags); dest.writeString(nickname); + dest.writeString(serviceProviderName); + dest.writeString(profileName); + dest.writeInt(profileClass); + dest.writeInt(state); + if (carrierIdentifier != null) { + dest.writeByte((byte) 1); + carrierIdentifier.writeToParcel(dest, flags); + } else { + dest.writeByte((byte) 0); + } + dest.writeInt(policyRules); + dest.writeTypedArray(accessRules, flags); } @Override public int describeContents() { return 0; } + + /** The builder to build a new {@link EuiccProfileInfo} instance. */ + public static final class Builder { + public String iccid; + public UiccAccessRule[] accessRules; + public String nickname; + public String serviceProviderName; + public String profileName; + @ProfileClass public int profileClass; + @ProfileState public int state; + public CarrierIdentifier carrierIdentifier; + @PolicyRule public int policyRules; + + public Builder() {} + + public Builder(EuiccProfileInfo baseProfile) { + iccid = baseProfile.iccid; + nickname = baseProfile.nickname; + serviceProviderName = baseProfile.serviceProviderName; + profileName = baseProfile.profileName; + profileClass = baseProfile.profileClass; + state = baseProfile.state; + carrierIdentifier = baseProfile.carrierIdentifier; + policyRules = baseProfile.policyRules; + accessRules = baseProfile.accessRules; + } + + /** Builds the profile instance. */ + public EuiccProfileInfo build() { + if (iccid == null) { + throw new IllegalStateException("ICCID must be set for a profile."); + } + return new EuiccProfileInfo( + iccid, + nickname, + serviceProviderName, + profileName, + profileClass, + state, + carrierIdentifier, + policyRules, + accessRules); + } + + /** Sets the iccId of the subscription. */ + public Builder setIccid(String value) { + if (!TextUtils.isDigitsOnly(value)) { + throw new IllegalArgumentException("iccid contains invalid characters: " + value); + } + iccid = value; + return this; + } + + /** Sets the nickname of the subscription. */ + public Builder setNickname(String value) { + nickname = value; + return this; + } + + /** Sets the service provider name of the subscription. */ + public Builder setServiceProviderName(String value) { + serviceProviderName = value; + return this; + } + + /** Sets the profile name of the subscription. */ + public Builder setProfileName(String value) { + profileName = value; + return this; + } + + /** Sets the profile class of the subscription. */ + public Builder setProfileClass(@ProfileClass int value) { + profileClass = value; + return this; + } + + /** Sets the state of the subscription. */ + public Builder setState(@ProfileState int value) { + state = value; + return this; + } + + /** Sets the carrier identifier of the subscription. */ + public Builder setCarrierIdentifier(CarrierIdentifier value) { + carrierIdentifier = value; + return this; + } + + /** Sets the policy rules of the subscription. */ + public Builder setPolicyRules(@PolicyRule int value) { + policyRules = value; + return this; + } + + /** Sets the access rules of the subscription. */ + public Builder setUiccAccessRule(@Nullable UiccAccessRule[] value) { + accessRules = value; + return this; + } + } + + private EuiccProfileInfo( + String iccid, + @Nullable String nickname, + String serviceProviderName, + String profileName, + @ProfileClass int profileClass, + @ProfileState int state, + CarrierIdentifier carrierIdentifier, + @PolicyRule int policyRules, + @Nullable UiccAccessRule[] accessRules) { + this.iccid = iccid; + this.nickname = nickname; + this.serviceProviderName = serviceProviderName; + this.profileName = profileName; + this.profileClass = profileClass; + this.state = state; + this.carrierIdentifier = carrierIdentifier; + this.policyRules = policyRules; + this.accessRules = accessRules; + } + + /** Gets the ICCID string. */ + public String getIccid() { + return iccid; + } + + /** Gets the access rules. */ + @Nullable + public UiccAccessRule[] getUiccAccessRules() { + return accessRules; + } + + /** Gets the nickname. */ + public String getNickname() { + return nickname; + } + + /** Gets the service provider name. */ + public String getServiceProviderName() { + return serviceProviderName; + } + + /** Gets the profile name. */ + public String getProfileName() { + return profileName; + } + + /** Gets the profile class. */ + @ProfileClass + public int getProfileClass() { + return profileClass; + } + + /** Gets the state of the subscription. */ + @ProfileState + public int getState() { + return state; + } + + /** Gets the carrier identifier. */ + public CarrierIdentifier getCarrierIdentifier() { + return carrierIdentifier; + } + + /** Gets the policy rules. */ + @PolicyRule + public int getPolicyRules() { + return policyRules; + } + + /** Returns whether any policy rule exists. */ + public boolean hasPolicyRules() { + return policyRules != 0; + } + + /** Checks whether a certain policy rule exists. */ + public boolean hasPolicyRule(@PolicyRule int policy) { + return (policyRules & policy) != 0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EuiccProfileInfo that = (EuiccProfileInfo) obj; + return Objects.equals(iccid, that.iccid) + && Objects.equals(nickname, that.nickname) + && Objects.equals(serviceProviderName, that.serviceProviderName) + && Objects.equals(profileName, that.profileName) + && profileClass == that.profileClass + && state == that.state + && Objects.equals(carrierIdentifier, that.carrierIdentifier) + && policyRules == that.policyRules + && Arrays.equals(accessRules, that.accessRules); + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + Objects.hashCode(iccid); + result = 31 * result + Objects.hashCode(nickname); + result = 31 * result + Objects.hashCode(serviceProviderName); + result = 31 * result + Objects.hashCode(profileName); + result = 31 * result + profileClass; + result = 31 * result + state; + result = 31 * result + Objects.hashCode(carrierIdentifier); + result = 31 * result + policyRules; + result = 31 * result + Arrays.hashCode(accessRules); + return result; + } + + @Override + public String toString() { + return "EuiccProfileInfo (nickname=" + + nickname + + ", serviceProviderName=" + + serviceProviderName + + ", profileName=" + + profileName + + ", profileClass=" + + profileClass + + ", state=" + + state + + ", CarrierIdentifier=" + + carrierIdentifier.toString() + + ", policyRules=" + + policyRules + + ", accessRules=" + + Arrays.toString(accessRules) + + ")"; + } } diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index fb530074d5b0..be8580074f73 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -193,6 +193,18 @@ public abstract class EuiccService extends Service { } /** + * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} + * + * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} + * + * @see IEuiccService#startOtaIfNecessary + */ + public interface OtaStatusChangedCallback { + /** Called when OTA status is changed. */ + void onOtaStatusChanged(int status); + } + + /** * Return the EID of the eUICC. * * @param slotId ID of the SIM slot being queried. This is currently not populated but is here @@ -214,6 +226,16 @@ public abstract class EuiccService extends Service { public abstract @OtaStatus int onGetOtaStatus(int slotId); /** + * Perform OTA if current OS is not the latest one. + * + * @param slotId ID of the SIM slot to use for the operation. This is currently not populated + * but is here to future-proof the APIs. + * @param statusChangedCallback Function called when OTA status changed. + */ + public abstract void onStartOtaIfNecessary( + int slotId, OtaStatusChangedCallback statusChangedCallback); + + /** * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. * * @param slotId ID of the SIM slot to use for the operation. This is currently not populated @@ -396,6 +418,26 @@ public abstract class EuiccService extends Service { } @Override + public void startOtaIfNecessary( + int slotId, IOtaStatusChangedCallback statusChangedCallback) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { + @Override + public void onOtaStatusChanged(int status) { + try { + statusChangedCallback.onOtaStatusChanged(status); + } catch (RemoteException e) { + // Can't communicate with the phone process; ignore. + } + } + }); + } + }); + } + + @Override public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { mExecutor.execute(new Runnable() { @Override diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl index a24e5c35c1cb..45be52740f32 100644 --- a/core/java/android/service/euicc/IEuiccService.aidl +++ b/core/java/android/service/euicc/IEuiccService.aidl @@ -25,6 +25,7 @@ import android.service.euicc.IGetEidCallback; import android.service.euicc.IGetEuiccInfoCallback; import android.service.euicc.IGetEuiccProfileInfoListCallback; import android.service.euicc.IGetOtaStatusCallback; +import android.service.euicc.IOtaStatusChangedCallback; import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; import android.service.euicc.ISwitchToSubscriptionCallback; import android.service.euicc.IUpdateSubscriptionNicknameCallback; @@ -39,6 +40,7 @@ oneway interface IEuiccService { boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback); void getEid(int slotId, in IGetEidCallback callback); void getOtaStatus(int slotId, in IGetOtaStatusCallback callback); + void startOtaIfNecessary(int slotId, in IOtaStatusChangedCallback statusChangedCallback); void getEuiccProfileInfoList(int slotId, in IGetEuiccProfileInfoListCallback callback); void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, in IGetDefaultDownloadableSubscriptionListCallback callback); diff --git a/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl b/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl new file mode 100644 index 000000000000..caec75f13f61 --- /dev/null +++ b/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +/** @hide */ +oneway interface IOtaStatusChangedCallback { + void onOtaStatusChanged(int status); +}
\ No newline at end of file diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index bbd9c9c0bac0..562ae7ada90a 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -358,7 +358,7 @@ public class Time { } /** - * Return the current time in YYYYMMDDTHHMMSS<tz> format + * Return the current time in YYYYMMDDTHHMMSS<tz> format */ @Override public String toString() { @@ -738,6 +738,7 @@ public class Time { * <p> * You should also use <tt>toMillis(false)</tt> if you want * to read back the same milliseconds that you set with {@link #set(long)} + * or {@link #set(Time)} or after parsing a date string. * * <p> * This method can return {@code -1} when the date / time fields have been @@ -745,8 +746,6 @@ public class Time { * For example, when daylight savings transitions cause an hour to be * skipped: times within that hour will return {@code -1} if isDst = * {@code -1}. - * - * or {@link #set(Time)} or after parsing a date string. */ public long toMillis(boolean ignoreDst) { calculator.copyFieldsFromTime(this); diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 77cfc2fc5bd4..96d3baf7cf0b 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -411,6 +411,9 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { mContext.unbindService(mConnection); mConnection.destroy(); } + if (mAfterCompute != null) { + mAfterCompute.afterCompute(); + } if (DEBUG) { Log.d(TAG, "Unbinded Resolver Ranker."); } @@ -573,7 +576,6 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { if (DEBUG) { Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction"); } - return; } else { try { mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 3ee8b472869b..9167076474ff 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -69,6 +69,9 @@ public final class Zygote { private Zygote() {} + /** Called for some security initialization before any fork. */ + native static void nativeSecurityInit(); + /** * Forks a new VM instance. The current VM must have been started * with the -Xzygote flag. <b>NOTE: new instance keeps all diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 2be6212b9f1e..21f1fb652794 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -30,7 +30,6 @@ import android.os.IInstalld; import android.os.Environment; import android.os.Process; import android.os.RemoteException; -import android.os.Seccomp; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemClock; @@ -572,10 +571,12 @@ public class ZygoteInit { final String seInfo = null; final String classLoaderContext = getSystemServerClassLoaderContext(classPathForElement); + final int targetSdkVersion = 0; // SystemServer targets the system's SDK version try { installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName, instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, - uuid, classLoaderContext, seInfo, false /* downgrade */); + uuid, classLoaderContext, seInfo, false /* downgrade */, + targetSdkVersion); } catch (RemoteException | ServiceSpecificException e) { // Ignore (but log), we need this on the classpath for fallback mode. Log.w(TAG, "Failed compiling classpath element for system server: " @@ -779,12 +780,11 @@ public class ZygoteInit { // Zygote. Trace.setTracingEnabled(false, 0); + Zygote.nativeSecurityInit(); + // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); - // Set seccomp policy - Seccomp.setPolicy(); - ZygoteHooks.stopZygoteNoThreadCreation(); if (startSystemServer) { diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 551d54ab9053..bc98716ebc9c 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -86,7 +86,6 @@ cc_library_shared { "android_os_MessageQueue.cpp", "android_os_Parcel.cpp", "android_os_SELinux.cpp", - "android_os_seccomp.cpp", "android_os_SharedMemory.cpp", "android_os_SystemClock.cpp", "android_os_SystemProperties.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 047fa8489453..35ab56a1a456 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -163,7 +163,6 @@ extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); extern int register_android_os_VintfObject(JNIEnv *env); extern int register_android_os_VintfRuntimeInfo(JNIEnv *env); -extern int register_android_os_seccomp(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); @@ -1420,7 +1419,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_GraphicsEnvironment), REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_SELinux), - REG_JNI(register_android_os_seccomp), REG_JNI(register_android_os_Trace), REG_JNI(register_android_os_UEventObserver), REG_JNI(register_android_net_LocalSocketImpl), diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 1eeea517cd78..16591685848e 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -146,8 +146,8 @@ static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) { return nullptr; } jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit); - for (const Vndk &vndk : manifest->vndks()) { - std::string key = to_string(vndk.versionRange()); + for (const auto &vndk : manifest->vendorNdks()) { + std::string key = vndk.version(); env->CallObjectMethod(jMap, gHashMapPut, env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries())); } diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp deleted file mode 100644 index 06e2a167de0a..000000000000 --- a/core/jni/android_os_seccomp.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include "core_jni_helpers.h" -#include <nativehelper/JniConstants.h> -#include "utils/Log.h" -#include <selinux/selinux.h> - -#include "seccomp_policy.h" - -static void Seccomp_setPolicy(JNIEnv* /*env*/) { - if (security_getenforce() == 0) { - ALOGI("seccomp disabled by setenforce 0"); - return; - } - - if (!set_seccomp_filter()) { - ALOGE("Failed to set seccomp policy - killing"); - exit(1); - } -} - -static const JNINativeMethod method_table[] = { - NATIVE_METHOD(Seccomp, setPolicy, "()V"), -}; - -namespace android { - -int register_android_os_seccomp(JNIEnv* env) { - return android::RegisterMethodsOrDie(env, "android/os/Seccomp", - method_table, NELEM(method_table)); -} - -} diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 32ef3dc0aed4..63dba43a5eb3 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -53,6 +53,7 @@ #include <private/android_filesystem_config.h> #include <utils/String8.h> #include <selinux/android.h> +#include <seccomp_policy.h> #include <processgroup/processgroup.h> #include "core_jni_helpers.h" @@ -76,6 +77,8 @@ static const char kZygoteClassName[] = "com/android/internal/os/Zygote"; static jclass gZygoteClass; static jmethodID gCallPostForkChildHooks; +static bool g_is_security_enforced = true; + // Must match values in com.android.internal.os.Zygote. enum MountExternalKind { MOUNT_EXTERNAL_NONE = 0, @@ -229,6 +232,20 @@ static void PreApplicationInit() { mallopt(M_DECAY_TIME, 1); } +static void SetUpSeccompFilter(uid_t uid) { + if (!g_is_security_enforced) { + ALOGI("seccomp disabled by setenforce 0"); + return; + } + + // Apply system or app filter based on uid. + if (getuid() >= AID_APP_START) { + set_app_seccomp_filter(); + } else { + set_system_seccomp_filter(); + } +} + static void EnableKeepCapabilities(JNIEnv* env) { int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); if (rc == -1) { @@ -541,6 +558,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); } + // Must be called when the new process still has CAP_SYS_ADMIN. The other alternative is to + // call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see + // b/71859146). + SetUpSeccompFilter(uid); + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(env); @@ -698,6 +720,12 @@ static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { namespace android { +static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) { + // security_getenforce is not allowed on app process. Initialize and cache the value before + // zygote forks. + g_is_security_enforced = security_getenforce(); +} + static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) { PreApplicationInit(); } @@ -832,6 +860,8 @@ static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* en } static const JNINativeMethod gMethods[] = { + { "nativeSecurityInit", "()V", + (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4b2ae06eff2f..fdda55bfa01b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -563,6 +563,9 @@ <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" /> <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" /> + <!-- Added in P --> + <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 960ad1b38349..0c2824b7305b 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2557,6 +2557,13 @@ <bool name="config_sms_force_7bit_encoding">false</bool> + <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and + is not necessarily the same as the number of phones/logical modems supported by the device. + For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots, + or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM + and one pSIM) --> + <integer name="config_num_physical_slots">1</integer> + <!--Thresholds for LTE dbm in status bar--> <integer-array translatable="false" name="config_lteDbmThresholds"> <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN --> @@ -3097,4 +3104,6 @@ <!-- Decide whether to display 'No service' on status bar instead of 'Emergency calls only' when SIM is unready. --> <bool name="config_display_no_service_when_sim_unready">false</bool> + + <bool name="config_supportBluetoothPersistedState">true</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 438ed82353a0..ac93361ad9d2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -445,6 +445,7 @@ <java-symbol type="integer" name="config_keepPreloadsMinDays" /> <java-symbol type="bool" name="config_hasPermanentDpad" /> <java-symbol type="bool" name="config_useDefaultFocusHighlight" /> + <java-symbol type="integer" name="config_num_physical_slots" /> <java-symbol type="color" name="tab_indicator_text_v4" /> @@ -3081,4 +3082,6 @@ <java-symbol type="integer" name="config_stableDeviceDisplayWidth" /> <java-symbol type="integer" name="config_stableDeviceDisplayHeight" /> <java-symbol type="bool" name="config_display_no_service_when_sim_unready" /> + + <java-symbol type="bool" name="config_supportBluetoothPersistedState" /> </resources> diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java new file mode 100644 index 000000000000..1e3ddf3226af --- /dev/null +++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; +import android.service.carrier.CarrierIdentifier; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.telephony.UiccAccessRule; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EuiccProfileInfoTest { + @Test + public void testWriteToParcel() { + EuiccProfileInfo p = + new EuiccProfileInfo.Builder() + .setIccid("21430000000000006587") + .setNickname("profile nickname") + .setServiceProviderName("service provider") + .setProfileName("profile name") + .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) + .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setCarrierIdentifier( + new CarrierIdentifier( + new byte[] {0x23, 0x45, 0x67}, + "123", + "45")) + .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) + .setUiccAccessRule( + new UiccAccessRule[] { + new UiccAccessRule(new byte[] {}, "package", 12345L) + }) + .build(); + + Parcel parcel = Parcel.obtain(); + assertTrue(parcel != null); + p.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + EuiccProfileInfo fromParcel = EuiccProfileInfo.CREATOR.createFromParcel(parcel); + + assertEquals(p, fromParcel); + } + + @Test + public void testWriteToParcelNullCarrierId() { + EuiccProfileInfo p = + new EuiccProfileInfo.Builder() + .setIccid("21430000000000006587") + .setNickname("profile nickname") + .setServiceProviderName("service provider") + .setProfileName("profile name") + .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) + .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) + .setUiccAccessRule( + new UiccAccessRule[] { + new UiccAccessRule(new byte[] {}, "package", 12345L) + }) + .build(); + + Parcel parcel = Parcel.obtain(); + assertTrue(parcel != null); + p.writeToParcel(parcel, 0); + + parcel.setDataPosition(0); + EuiccProfileInfo fromParcel = EuiccProfileInfo.CREATOR.createFromParcel(parcel); + + assertEquals(p, fromParcel); + } + + @Test + public void testBuilderAndGetters() { + EuiccProfileInfo p = + new EuiccProfileInfo.Builder() + .setIccid("21430000000000006587") + .setNickname("profile nickname") + .setProfileName("profile name") + .setServiceProviderName("service provider") + .setCarrierIdentifier( + new CarrierIdentifier( + new byte[] {0x23, 0x45, 0x67}, + "123", + "45")) + .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) + .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) + .setUiccAccessRule( + new UiccAccessRule[] { + new UiccAccessRule(new byte[0], null, 0) + }) + .build(); + + assertEquals("21430000000000006587", p.getIccid()); + assertEquals("profile nickname", p.getNickname()); + assertEquals("profile name", p.getProfileName()); + assertEquals("service provider", p.getServiceProviderName()); + assertEquals("325", p.getCarrierIdentifier().getMcc()); + assertEquals("764", p.getCarrierIdentifier().getMnc()); + assertEquals("123", p.getCarrierIdentifier().getGid1()); + assertEquals("45", p.getCarrierIdentifier().getGid2()); + assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, p.getState()); + assertEquals(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, p.getProfileClass()); + assertEquals(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, p.getPolicyRules()); + assertTrue(p.hasPolicyRules()); + assertTrue(p.hasPolicyRule(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)); + assertFalse(p.hasPolicyRule(EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE)); + assertArrayEquals( + new UiccAccessRule[] {new UiccAccessRule(new byte[0], null, 0)}, + p.getUiccAccessRules()); + } + + @Test + public void testBuilder_BasedOnAnotherProfile() { + EuiccProfileInfo p = + new EuiccProfileInfo.Builder() + .setIccid("21430000000000006587") + .setNickname("profile nickname") + .setProfileName("profile name") + .setServiceProviderName("service provider") + .setCarrierIdentifier( + new CarrierIdentifier( + new byte[] {0x23, 0x45, 0x67}, + "123", + "45")) + .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL) + .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) + .setUiccAccessRule( + new UiccAccessRule[] { + new UiccAccessRule(new byte[0], null, 0) + }) + .build(); + + EuiccProfileInfo copied = new EuiccProfileInfo.Builder(p).build(); + + assertEquals(p, copied); + assertEquals(p.hashCode(), copied.hashCode()); + } + + @Test + public void testEqualsHashCode() { + EuiccProfileInfo p = + new EuiccProfileInfo.Builder() + .setIccid("21430000000000006587") + .setNickname("profile nickname") + .setProfileName("profile name") + .setServiceProviderName("service provider") + .setCarrierIdentifier( + new CarrierIdentifier( + new byte[] {0x23, 0x45, 0x67}, + "123", + "45")) + .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setProfileClass(EuiccProfileInfo.PROFILE_STATE_ENABLED) + .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE) + .setUiccAccessRule( + new UiccAccessRule[] { + new UiccAccessRule(new byte[0], null, 0) + }) + .build(); + + assertTrue(p.equals(p)); + assertFalse(p.equals(new Object())); + + EuiccProfileInfo t = null; + assertFalse(p.equals(t)); + + t = new EuiccProfileInfo.Builder(p).setIccid("21").build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setNickname(null).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setProfileName(null).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setServiceProviderName(null).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setCarrierIdentifier(null).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p) + .setState(EuiccProfileInfo.PROFILE_STATE_DISABLED).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p) + .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_TESTING).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setPolicyRules(0).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + + t = new EuiccProfileInfo.Builder(p).setUiccAccessRule(null).build(); + assertFalse(p.equals(t)); + assertNotEquals(p.hashCode(), t.hashCode()); + } + + @Test(expected = IllegalStateException.class) + public void testBuilderBuild_NoIccid() { + new EuiccProfileInfo.Builder().build(); + } + + @Test(expected = IllegalArgumentException.class) + public void testBuilderSetOperatorMccMnc_Illegal() { + new EuiccProfileInfo.Builder() + .setCarrierIdentifier(new CarrierIdentifier(new byte[] {1, 2, 3, 4}, null, null)); + } + + @Test + public void testCreatorNewArray() { + EuiccProfileInfo[] profiles = EuiccProfileInfo.CREATOR.newArray(123); + assertEquals(123, profiles.length); + } +} diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 7c6046789cdc..e3af65532f85 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -551,18 +551,20 @@ bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) { } // Animate spots that are fading out and being removed. - for (size_t i = 0; i < mLocked.spots.size(); i++) { + for (size_t i = 0; i < mLocked.spots.size();) { Spot* spot = mLocked.spots.itemAt(i); if (spot->id == Spot::INVALID_ID) { spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; if (spot->alpha <= 0) { - mLocked.spots.removeAt(i--); + mLocked.spots.removeAt(i); releaseSpotLocked(spot); + continue; } else { spot->sprite->setAlpha(spot->alpha); keepAnimating = true; } } + ++i; } return keepAnimating; } diff --git a/libs/services/Android.bp b/libs/services/Android.bp new file mode 100644 index 000000000000..53e620138079 --- /dev/null +++ b/libs/services/Android.bp @@ -0,0 +1,46 @@ +// Copyright (C) 2018 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. + +// Provides C++ wrappers for system services. + +cc_library_shared { + name: "libservices", + srcs: [ + ":IDropBoxManagerService.aidl", + "src/os/DropBoxManager.cpp", + ], + + shared_libs: [ + "libbinder", + "liblog", + "libcutils", + "libutils", + ], + header_libs: [ + "libbase_headers", + ], + aidl: { + include_dirs: ["frameworks/base/core/java/"], + }, + + export_include_dirs: ["include"], + export_header_lib_headers: ["libbase_headers"], + + cflags: [ + "-Wall", + "-Werror", + "-Wunused", + "-Wunreachable-code", + ], +} diff --git a/libs/services/Android.mk b/libs/services/Android.mk deleted file mode 100644 index cbfd4b3f9f10..000000000000 --- a/libs/services/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2010 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. - -LOCAL_PATH:= $(call my-dir) - -# Provides C++ wrappers for system services. - -include $(CLEAR_VARS) - -LOCAL_MODULE := libservices -LOCAL_SRC_FILES := \ - ../../core/java/com/android/internal/os/IDropBoxManagerService.aidl \ - src/os/DropBoxManager.cpp - -LOCAL_AIDL_INCLUDES := \ - $(LOCAL_PATH)/../../core/java -LOCAL_C_INCLUDES := \ - system/core/include -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - liblog \ - libcutils \ - libutils - -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_C_INCLUDES += $(LOCAL_PATH)/include - -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code - -include $(BUILD_SHARED_LIBRARY) - - diff --git a/native/android/net.c b/native/android/net.c index de4b90cc1956..60296a7bd00c 100644 --- a/native/android/net.c +++ b/native/android/net.c @@ -27,7 +27,7 @@ static int getnetidfromhandle(net_handle_t handle, unsigned *netid) { static const uint32_t k32BitMask = 0xffffffff; // This value MUST be kept in sync with the corresponding value in // the android.net.Network#getNetworkHandle() implementation. - static const uint32_t kHandleMagic = 0xfacade; + static const uint32_t kHandleMagic = 0xcafed00d; // Check for minimum acceptable version of the API in the low bits. if (handle != NETWORK_UNSPECIFIED && diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index d7695ef17a08..5785b0c42a2f 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -30,13 +30,6 @@ cc_library_shared { "libandroid_runtime", "libskia", ], - - arch: { - arm: { - // TODO: This is to work around b/24465209. Remove after root cause is fixed - ldflags: ["-Wl,--hash-style=both"], - }, - }, } // The headers module is in frameworks/native/Android.bp. diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index d9713a517a94..20777901a3aa 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -60,6 +60,7 @@ import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Slog; +import com.android.internal.R; import com.android.internal.util.DumpUtils; import com.android.server.pm.UserRestrictionsUtils; @@ -415,9 +416,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int systemUiUid = -1; try { - systemUiUid = mContext.getPackageManager() - .getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY, - UserHandle.USER_SYSTEM); + // Check if device is configured with no home screen, which implies no SystemUI. + boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen); + if (!noHome) { + systemUiUid = mContext.getPackageManager() + .getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY, + UserHandle.USER_SYSTEM); + } + Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid)); } catch (PackageManager.NameNotFoundException e) { // Some platforms, such as wearables do not have a system ui. Slog.w(TAG, "Unable to resolve SystemUI's UID.", e); @@ -433,10 +439,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Settings.Global.AIRPLANE_MODE_ON, 0) == 1; } + private boolean supportBluetoothPersistedState() { + return mContext.getResources().getBoolean(R.bool.config_supportBluetoothPersistedState); + } + /** * Returns true if the Bluetooth saved state is "on" */ private boolean isBluetoothPersistedStateOn() { + if (!supportBluetoothPersistedState()) { + return false; + } int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); if (DBG) { Slog.d(TAG, "Bluetooth persisted state: " + state); @@ -448,6 +461,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH */ private boolean isBluetoothPersistedStateOnBluetooth() { + if (!supportBluetoothPersistedState()) { + return false; + } return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5228498ba883..56d7e7b9304a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -130,6 +130,8 @@ import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; +import com.android.server.connectivity.DnsManager; +import com.android.server.connectivity.DnsManager.PrivateDnsConfig; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; @@ -224,7 +226,11 @@ public class ConnectivityService extends IConnectivityManager.Stub @GuardedBy("mVpns") private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>(); + // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by + // a direct call to LockdownVpnTracker.isEnabled(). + @GuardedBy("mVpns") private boolean mLockdownEnabled; + @GuardedBy("mVpns") private LockdownVpnTracker mLockdownTracker; final private Context mContext; @@ -232,8 +238,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // 0 is full bad, 100 is full good private int mDefaultInetConditionPublished = 0; - private int mNumDnsEntries; - private boolean mTestMode; private static ConnectivityService sServiceInstance; @@ -396,6 +400,9 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_REVALIDATE_NETWORK = 36; + // Handle changes in Private DNS settings. + private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37; + private static String eventName(int what) { return sMagicDecoderRing.get(what, Integer.toString(what)); } @@ -407,6 +414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ final private NetworkStateTrackerHandler mTrackerHandler; + private final DnsManager mDnsManager; private boolean mSystemReady; private Intent mInitialBroadcast; @@ -857,6 +865,9 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultinetworkPolicyTracker = createMultinetworkPolicyTracker( mContext, mHandler, () -> rematchForAvoidBadWifiUpdate()); mMultinetworkPolicyTracker.start(); + + mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties); + registerPrivateDnsSettingsCallbacks(); } private Tethering makeTethering() { @@ -917,6 +928,12 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON); } + private void registerPrivateDnsSettingsCallbacks() { + for (Uri u : DnsManager.getPrivateDnsSettingsUris()) { + mSettingsObserver.observe(u, EVENT_PRIVATE_DNS_SETTINGS_CHANGED); + } + } + private synchronized int nextNetworkRequestId() { return mNextNetworkRequestId++; } @@ -972,9 +989,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } private Network[] getVpnUnderlyingNetworks(int uid) { - if (!mLockdownEnabled) { - int user = UserHandle.getUserId(uid); - synchronized (mVpns) { + synchronized (mVpns) { + if (!mLockdownEnabled) { + int user = UserHandle.getUserId(uid); Vpn vpn = mVpns.get(user); if (vpn != null && vpn.appliesToUid(uid)) { return vpn.getUnderlyingNetworks(); @@ -1062,8 +1079,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) { state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); } - if (mLockdownTracker != null) { - mLockdownTracker.augmentNetworkInfo(state.networkInfo); + synchronized (mVpns) { + if (mLockdownTracker != null) { + mLockdownTracker.augmentNetworkInfo(state.networkInfo); + } } } @@ -1228,8 +1247,8 @@ public class ConnectivityService extends IConnectivityManager.Stub result.put(nai.network, nc); } - if (!mLockdownEnabled) { - synchronized (mVpns) { + synchronized (mVpns) { + if (!mLockdownEnabled) { Vpn vpn = mVpns.get(userId); if (vpn != null) { Network[] networks = vpn.getUnderlyingNetworks(); @@ -1555,9 +1574,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } private Intent makeGeneralIntent(NetworkInfo info, String bcastType) { - if (mLockdownTracker != null) { - info = new NetworkInfo(info); - mLockdownTracker.augmentNetworkInfo(info); + synchronized (mVpns) { + if (mLockdownTracker != null) { + info = new NetworkInfo(info); + mLockdownTracker.augmentNetworkInfo(info); + } } Intent intent = new Intent(bcastType); @@ -1803,24 +1824,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void flushVmDnsCache() { - /* - * Tell the VMs to toss their DNS caches - */ - Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - /* - * Connectivity events can happen before boot has completed ... - */ - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - @Override public int getRestoreDefaultNetworkDelay(int networkType) { String restoreDefaultNetworkDelayStr = mSystemProperties.get( @@ -2094,36 +2097,59 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { nai = mNetworkForNetId.get(msg.arg2); } - if (nai != null) { - final boolean valid = - (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); - final boolean wasValidated = nai.lastValidated; - final boolean wasDefault = isDefaultNetwork(nai); - if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") + - (msg.obj == null ? "" : " with redirect to " + (String)msg.obj)); - if (valid != nai.lastValidated) { - if (wasDefault) { - metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity( - SystemClock.elapsedRealtime(), valid); - } - final int oldScore = nai.getCurrentScore(); - nai.lastValidated = valid; - nai.everValidated |= valid; - updateCapabilities(oldScore, nai, nai.networkCapabilities); - // If score has changed, rebroadcast to NetworkFactories. b/17726566 - if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); + if (nai == null) break; + + final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); + final boolean wasValidated = nai.lastValidated; + final boolean wasDefault = isDefaultNetwork(nai); + + final PrivateDnsConfig privateDnsCfg = (msg.obj instanceof PrivateDnsConfig) + ? (PrivateDnsConfig) msg.obj : null; + final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : ""; + + final boolean reevaluationRequired; + final String logMsg; + if (valid) { + reevaluationRequired = updatePrivateDns(nai, privateDnsCfg); + logMsg = (DBG && (privateDnsCfg != null)) + ? " with " + privateDnsCfg.toString() : ""; + } else { + reevaluationRequired = false; + logMsg = (DBG && !TextUtils.isEmpty(redirectUrl)) + ? " with redirect to " + redirectUrl : ""; + } + if (DBG) { + log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg); + } + // If there is a change in Private DNS configuration, + // trigger reevaluation of the network to test it. + if (reevaluationRequired) { + nai.networkMonitor.sendMessage( + NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID); + break; + } + if (valid != nai.lastValidated) { + if (wasDefault) { + metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity( + SystemClock.elapsedRealtime(), valid); } - updateInetCondition(nai); - // Let the NetworkAgent know the state of its network - Bundle redirectUrlBundle = new Bundle(); - redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj); - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_REPORT_NETWORK_STATUS, - (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), - 0, redirectUrlBundle); - if (wasValidated && !nai.lastValidated) { - handleNetworkUnvalidated(nai); - } + final int oldScore = nai.getCurrentScore(); + nai.lastValidated = valid; + nai.everValidated |= valid; + updateCapabilities(oldScore, nai, nai.networkCapabilities); + // If score has changed, rebroadcast to NetworkFactories. b/17726566 + if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); + } + updateInetCondition(nai); + // Let the NetworkAgent know the state of its network + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl); + nai.asyncChannel.sendMessage( + NetworkAgent.CMD_REPORT_NETWORK_STATUS, + (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), + 0, redirectUrlBundle); + if (wasValidated && !nai.lastValidated) { + handleNetworkUnvalidated(nai); } break; } @@ -2163,6 +2189,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } break; } + case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: { + final NetworkAgentInfo nai; + synchronized (mNetworkForNetId) { + nai = mNetworkForNetId.get(msg.arg2); + } + if (nai == null) break; + + final PrivateDnsConfig cfg = (PrivateDnsConfig) msg.obj; + final boolean reevaluationRequired = updatePrivateDns(nai, cfg); + if (nai.lastValidated && reevaluationRequired) { + nai.networkMonitor.sendMessage( + NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID); + } + break; + } } return true; } @@ -2198,6 +2239,63 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void handlePrivateDnsSettingsChanged() { + final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig(); + + for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + // Private DNS only ever applies to networks that might provide + // Internet access and therefore also require validation. + if (!NetworkMonitor.isValidationRequired( + mDefaultRequest.networkCapabilities, nai.networkCapabilities)) { + continue; + } + + // Notify the NetworkMonitor thread in case it needs to cancel or + // schedule DNS resolutions. If a DNS resolution is required the + // result will be sent back to us. + nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg); + + if (!cfg.inStrictMode()) { + // No strict mode hostname DNS resolution needed, so just update + // DNS settings directly. In opportunistic and "off" modes this + // just reprograms netd with the network-supplied DNS servers + // (and of course the boolean of whether or not to attempt TLS). + // + // TODO: Consider code flow parity with strict mode, i.e. having + // NetworkMonitor relay the PrivateDnsConfig back to us and then + // performing this call at that time. + updatePrivateDns(nai, cfg); + } + } + } + + private boolean updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) { + final boolean reevaluationRequired = true; + final boolean dontReevaluate = false; + + final PrivateDnsConfig oldCfg = mDnsManager.updatePrivateDns(nai.network, newCfg); + updateDnses(nai.linkProperties, null, nai.network.netId); + + if (newCfg == null) { + if (oldCfg == null) return dontReevaluate; + return oldCfg.useTls ? reevaluationRequired : dontReevaluate; + } + + if (oldCfg == null) { + return newCfg.useTls ? reevaluationRequired : dontReevaluate; + } + + if (oldCfg.useTls != newCfg.useTls) { + return reevaluationRequired; + } + + if (newCfg.inStrictMode() && !Objects.equals(oldCfg.hostname, newCfg.hostname)) { + return reevaluationRequired; + } + + return dontReevaluate; + } + private void updateLingerState(NetworkAgentInfo nai, long now) { // 1. Update the linger timer. If it's changed, reschedule or cancel the alarm. // 2. If the network was lingering and there are now requests, unlinger it. @@ -2332,6 +2430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } catch (Exception e) { loge("Exception removing network: " + e); } + mDnsManager.removeNetwork(nai.network); } synchronized (mNetworkForNetId) { mNetIdInUse.delete(nai.network.netId); @@ -2488,6 +2587,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) { nri.unlinkDeathRecipient(); mNetworkRequests.remove(nri.request); + synchronized (mUidToNetworkRequestCount) { int requests = mUidToNetworkRequestCount.get(nri.mUid, 0); if (requests < 1) { @@ -2500,6 +2600,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mUidToNetworkRequestCount.put(nri.mUid, requests - 1); } } + mNetworkRequestInfoLogs.log("RELEASE " + nri); if (nri.request.isRequest()) { boolean wasKept = false; @@ -2876,6 +2977,9 @@ public class ConnectivityService extends IConnectivityManager.Stub handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2)); break; } + case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: + handlePrivateDnsSettingsChanged(); + break; } } } @@ -3422,9 +3526,9 @@ public class ConnectivityService extends IConnectivityManager.Stub public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage, int userId) { enforceCrossUserPermission(userId); - throwIfLockdownEnabled(); synchronized (mVpns) { + throwIfLockdownEnabled(); Vpn vpn = mVpns.get(userId); if (vpn != null) { return vpn.prepare(oldPackage, newPackage); @@ -3468,9 +3572,9 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @Override public ParcelFileDescriptor establishVpn(VpnConfig config) { - throwIfLockdownEnabled(); int user = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mVpns) { + throwIfLockdownEnabled(); return mVpns.get(user).establish(config); } } @@ -3481,13 +3585,13 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @Override public void startLegacyVpn(VpnProfile profile) { - throwIfLockdownEnabled(); + int user = UserHandle.getUserId(Binder.getCallingUid()); final LinkProperties egress = getActiveLinkProperties(); if (egress == null) { throw new IllegalStateException("Missing active network connection"); } - int user = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mVpns) { + throwIfLockdownEnabled(); mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress); } } @@ -3513,11 +3617,11 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public VpnInfo[] getAllVpnInfo() { enforceConnectivityInternalPermission(); - if (mLockdownEnabled) { - return new VpnInfo[0]; - } - synchronized (mVpns) { + if (mLockdownEnabled) { + return new VpnInfo[0]; + } + List<VpnInfo> infoList = new ArrayList<>(); for (int i = 0; i < mVpns.size(); i++) { VpnInfo info = createVpnInfo(mVpns.valueAt(i)); @@ -3582,33 +3686,33 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } - // Tear down existing lockdown if profile was removed - mLockdownEnabled = LockdownVpnTracker.isEnabled(); - if (mLockdownEnabled) { - byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN); - if (profileTag == null) { - Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore"); - return false; - } - String profileName = new String(profileTag); - final VpnProfile profile = VpnProfile.decode( - profileName, mKeyStore.get(Credentials.VPN + profileName)); - if (profile == null) { - Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName); - setLockdownTracker(null); - return true; - } - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized (mVpns) { + synchronized (mVpns) { + // Tear down existing lockdown if profile was removed + mLockdownEnabled = LockdownVpnTracker.isEnabled(); + if (mLockdownEnabled) { + byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN); + if (profileTag == null) { + Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore"); + return false; + } + String profileName = new String(profileTag); + final VpnProfile profile = VpnProfile.decode( + profileName, mKeyStore.get(Credentials.VPN + profileName)); + if (profile == null) { + Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName); + setLockdownTracker(null); + return true; + } + int user = UserHandle.getUserId(Binder.getCallingUid()); Vpn vpn = mVpns.get(user); if (vpn == null) { Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown"); return false; } setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile)); + } else { + setLockdownTracker(null); } - } else { - setLockdownTracker(null); } return true; @@ -3618,6 +3722,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Internally set new {@link LockdownVpnTracker}, shutting down any existing * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown. */ + @GuardedBy("mVpns") private void setLockdownTracker(LockdownVpnTracker tracker) { // Shutdown any existing tracker final LockdownVpnTracker existing = mLockdownTracker; @@ -3632,6 +3737,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @GuardedBy("mVpns") private void throwIfLockdownEnabled() { if (mLockdownEnabled) { throw new IllegalStateException("Unavailable in lockdown mode"); @@ -3679,12 +3785,12 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceConnectivityInternalPermission(); enforceCrossUserPermission(userId); - // Can't set always-on VPN if legacy VPN is already in lockdown mode. - if (LockdownVpnTracker.isEnabled()) { - return false; - } - synchronized (mVpns) { + // Can't set always-on VPN if legacy VPN is already in lockdown mode. + if (LockdownVpnTracker.isEnabled()) { + return false; + } + Vpn vpn = mVpns.get(userId); if (vpn == null) { Slog.w(TAG, "User " + userId + " has no Vpn configuration"); @@ -3860,9 +3966,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId); mVpns.put(userId, userVpn); - } - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { - updateLockdownVpn(); + if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { + updateLockdownVpn(); + } } } @@ -3899,11 +4005,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserUnlocked(int userId) { - // User present may be sent because of an unlock, which might mean an unlocked keystore. - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { - updateLockdownVpn(); - } else { - startAlwaysOnVpn(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()) { + updateLockdownVpn(); + } else { + startAlwaysOnVpn(userId); + } } } @@ -4558,40 +4666,17 @@ public class ConnectivityService extends IConnectivityManager.Stub return; // no updating necessary } - Collection<InetAddress> dnses = newLp.getDnsServers(); - if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses); - try { - mNetd.setDnsConfigurationForNetwork( - netId, NetworkUtils.makeStrings(dnses), newLp.getDomains()); - } catch (Exception e) { - loge("Exception in setDnsConfigurationForNetwork: " + e); - } final NetworkAgentInfo defaultNai = getDefaultNetwork(); - if (defaultNai != null && defaultNai.network.netId == netId) { - setDefaultDnsSystemProperties(dnses); - } - flushVmDnsCache(); - } + final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); - private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { - int last = 0; - for (InetAddress dns : dnses) { - ++last; - setNetDnsProperty(last, dns.getHostAddress()); - } - for (int i = last + 1; i <= mNumDnsEntries; ++i) { - setNetDnsProperty(i, ""); + if (DBG) { + final Collection<InetAddress> dnses = newLp.getDnsServers(); + log("Setting DNS servers for network " + netId + " to " + dnses); } - mNumDnsEntries = last; - } - - private void setNetDnsProperty(int which, String value) { - final String key = "net.dns" + which; - // Log and forget errors setting unsupported properties. try { - mSystemProperties.set(key, value); + mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork); } catch (Exception e) { - Log.e(TAG, "Error setting unsupported net.dns property: ", e); + loge("Exception in setDnsConfigurationForNetwork: " + e); } } @@ -4607,51 +4692,67 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities} - * augmented with any stateful capabilities implied from {@code networkAgent} - * (e.g., validated status and captive portal status). - * - * @param oldScore score of the network before any of the changes that prompted us - * to call this function. - * @param nai the network having its capabilities updated. - * @param networkCapabilities the new network capabilities. + * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are + * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal, + * and foreground status). */ - private void updateCapabilities( - int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) { + private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) { // Once a NetworkAgent is connected, complain if some immutable capabilities are removed. - if (nai.everConnected && !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities( - networkCapabilities)) { - // TODO: consider not complaining when a network agent degrade its capabilities if this + if (nai.everConnected && + !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(nc)) { + // TODO: consider not complaining when a network agent degrades its capabilities if this // does not cause any request (that is not a listen) currently matching that agent to // stop being matched by the updated agent. - String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities); + String diff = nai.networkCapabilities.describeImmutableDifferences(nc); if (!TextUtils.isEmpty(diff)) { Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff); } } // Don't modify caller's NetworkCapabilities. - networkCapabilities = new NetworkCapabilities(networkCapabilities); + NetworkCapabilities newNc = new NetworkCapabilities(nc); if (nai.lastValidated) { - networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED); + newNc.addCapability(NET_CAPABILITY_VALIDATED); } else { - networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED); + newNc.removeCapability(NET_CAPABILITY_VALIDATED); } if (nai.lastCaptivePortalDetected) { - networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + newNc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL); } else { - networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL); + newNc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL); } if (nai.isBackgroundNetwork()) { - networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND); + newNc.removeCapability(NET_CAPABILITY_FOREGROUND); } else { - networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); + newNc.addCapability(NET_CAPABILITY_FOREGROUND); } - if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return; + return newNc; + } + + /** + * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically: + * + * 1. Calls mixInCapabilities to merge the passed-in NetworkCapabilities {@code nc} with the + * capabilities we manage and store in {@code nai}, such as validated status and captive + * portal status) + * 2. Takes action on the result: changes network permissions, sends CAP_CHANGED callbacks, and + * potentially triggers rematches. + * 3. Directly informs other network stack components (NetworkStatsService, VPNs, etc. of the + * change.) + * + * @param oldScore score of the network before any of the changes that prompted us + * to call this function. + * @param nai the network having its capabilities updated. + * @param nc the new network capabilities. + */ + private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) { + NetworkCapabilities newNc = mixInCapabilities(nai, nc); + + if (Objects.equals(nai.networkCapabilities, newNc)) return; final String oldPermission = getNetworkPermission(nai.networkCapabilities); - final String newPermission = getNetworkPermission(networkCapabilities); + final String newPermission = getNetworkPermission(newNc); if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) { try { mNetd.setNetworkPermission(nai.network.netId, newPermission); @@ -4663,11 +4764,10 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities prevNc; synchronized (nai) { prevNc = nai.networkCapabilities; - nai.networkCapabilities = networkCapabilities; + nai.networkCapabilities = newNc; } - if (nai.getCurrentScore() == oldScore && - networkCapabilities.equalRequestableCapabilities(prevNc)) { + if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) { // If the requestable capabilities haven't changed, and the score hasn't changed, then // the change we're processing can't affect any requests, it can only affect the listens // on this network. We might have been called by rematchNetworkAndRequests when a @@ -4683,15 +4783,15 @@ public class ConnectivityService extends IConnectivityManager.Stub // Report changes that are interesting for network statistics tracking. if (prevNc != null) { final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) != - networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED); + newNc.hasCapability(NET_CAPABILITY_NOT_METERED); final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) != - networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING); + newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); if (meteredChanged || roamingChanged) { notifyIfacesChangedForNetworkStats(); } } - if (!networkCapabilities.hasTransport(TRANSPORT_VPN)) { + if (!newNc.hasTransport(TRANSPORT_VPN)) { // Tell VPNs about updated capabilities, since they may need to // bubble those changes through. synchronized (mVpns) { @@ -4865,7 +4965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyLockdownVpn(newNetwork); handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy()); updateTcpBufferSizes(newNetwork); - setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); + mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5215,11 +5315,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void notifyLockdownVpn(NetworkAgentInfo nai) { - if (mLockdownTracker != null) { - if (nai != null && nai.isVPN()) { - mLockdownTracker.onVpnStateChanged(nai.networkInfo); - } else { - mLockdownTracker.onNetworkInfoChanged(); + synchronized (mVpns) { + if (mLockdownTracker != null) { + if (nai != null && nai.isVPN()) { + mLockdownTracker.onVpnStateChanged(nai.networkInfo); + } else { + mLockdownTracker.onNetworkInfoChanged(); + } } } } @@ -5449,28 +5551,28 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public boolean addVpnAddress(String address, int prefixLength) { - throwIfLockdownEnabled(); int user = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mVpns) { + throwIfLockdownEnabled(); return mVpns.get(user).addAddress(address, prefixLength); } } @Override public boolean removeVpnAddress(String address, int prefixLength) { - throwIfLockdownEnabled(); int user = UserHandle.getUserId(Binder.getCallingUid()); synchronized (mVpns) { + throwIfLockdownEnabled(); return mVpns.get(user).removeAddress(address, prefixLength); } } @Override public boolean setUnderlyingNetworksForVpn(Network[] networks) { - throwIfLockdownEnabled(); int user = UserHandle.getUserId(Binder.getCallingUid()); - boolean success; + final boolean success; synchronized (mVpns) { + throwIfLockdownEnabled(); success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { @@ -5530,31 +5632,31 @@ public class ConnectivityService extends IConnectivityManager.Stub setAlwaysOnVpnPackage(userId, null, false); setVpnPackageAuthorization(alwaysOnPackage, userId, false); } - } - // Turn Always-on VPN off - if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) { - final long ident = Binder.clearCallingIdentity(); - try { - mKeyStore.delete(Credentials.LOCKDOWN_VPN); - mLockdownEnabled = false; - setLockdownTracker(null); - } finally { - Binder.restoreCallingIdentity(ident); + // Turn Always-on VPN off + if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) { + final long ident = Binder.clearCallingIdentity(); + try { + mKeyStore.delete(Credentials.LOCKDOWN_VPN); + mLockdownEnabled = false; + setLockdownTracker(null); + } finally { + Binder.restoreCallingIdentity(ident); + } } - } - // Turn VPN off - VpnConfig vpnConfig = getVpnConfig(userId); - if (vpnConfig != null) { - if (vpnConfig.legacy) { - prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId); - } else { - // Prevent this app (packagename = vpnConfig.user) from initiating VPN connections - // in the future without user intervention. - setVpnPackageAuthorization(vpnConfig.user, userId, false); + // Turn VPN off + VpnConfig vpnConfig = getVpnConfig(userId); + if (vpnConfig != null) { + if (vpnConfig.legacy) { + prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId); + } else { + // Prevent this app (packagename = vpnConfig.user) from initiating + // VPN connections in the future without user intervention. + setVpnPackageAuthorization(vpnConfig.user, userId, false); - prepareVpn(null, VpnConfig.LEGACY_VPN, userId); + prepareVpn(null, VpnConfig.LEGACY_VPN, userId); + } } } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 5c098e32045b..46a35ec800ba 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; import android.content.Context; +import android.net.ConnectivityManager; import android.net.IIpSecService; import android.net.INetd; import android.net.IpSecAlgorithm; @@ -52,6 +53,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.IOException; @@ -61,7 +63,6 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import libcore.io.IoUtils; @@ -82,7 +83,7 @@ public class IpSecService extends IIpSecService.Stub { private static final String NETD_SERVICE_NAME = "netd"; private static final int[] DIRECTIONS = - new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; + new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int MAX_PORT_BIND_ATTEMPTS = 10; @@ -103,10 +104,10 @@ public class IpSecService extends IIpSecService.Stub { private final Context mContext; /** - * The next non-repeating global ID for tracking resources between users, this service, - * and kernel data structures. Accessing this variable is not thread safe, so it is - * only read or modified within blocks synchronized on IpSecService.this. We want to - * avoid -1 (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). + * The next non-repeating global ID for tracking resources between users, this service, and + * kernel data structures. Accessing this variable is not thread safe, so it is only read or + * modified within blocks synchronized on IpSecService.this. We want to avoid -1 + * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). */ @GuardedBy("IpSecService.this") private int mNextResourceId = 1; @@ -535,14 +536,14 @@ public class IpSecService extends IIpSecService.Stub { private final class TransformRecord extends KernelResourceRecord { private final IpSecConfig mConfig; - private final SpiRecord[] mSpis; + private final SpiRecord mSpi; private final EncapSocketRecord mSocket; TransformRecord( - int resourceId, IpSecConfig config, SpiRecord[] spis, EncapSocketRecord socket) { + int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) { super(resourceId); mConfig = config; - mSpis = spis; + mSpi = spi; mSocket = socket; } @@ -550,29 +551,26 @@ public class IpSecService extends IIpSecService.Stub { return mConfig; } - public SpiRecord getSpiRecord(int direction) { - return mSpis[direction]; + public SpiRecord getSpiRecord() { + return mSpi; } /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { - for (int direction : DIRECTIONS) { - int spi = mSpis[direction].getSpi(); - try { - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityAssociation( - mResourceId, - direction, - mConfig.getLocalAddress(), - mConfig.getRemoteAddress(), - spi); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); - } + int spi = mSpi.getSpi(); + try { + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, + mConfig.getSourceAddress(), + mConfig.getDestinationAddress(), + spi); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); } getResourceTracker().give(); @@ -596,10 +594,8 @@ public class IpSecService extends IIpSecService.Stub { .append(super.toString()) .append(", mSocket=") .append(mSocket) - .append(", mSpis[OUT].mResourceId=") - .append(mSpis[IpSecTransform.DIRECTION_OUT].mResourceId) - .append(", mSpis[IN].mResourceId=") - .append(mSpis[IpSecTransform.DIRECTION_IN].mResourceId) + .append(", mSpi.mResourceId=") + .append(mSpi.mResourceId) .append(", mConfig=") .append(mConfig) .append("}"); @@ -608,23 +604,16 @@ public class IpSecService extends IIpSecService.Stub { } private final class SpiRecord extends KernelResourceRecord { - private final int mDirection; - private final String mLocalAddress; - private final String mRemoteAddress; + private final String mSourceAddress; + private final String mDestinationAddress; private int mSpi; private boolean mOwnedByTransform = false; - SpiRecord( - int resourceId, - int direction, - String localAddress, - String remoteAddress, - int spi) { + SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) { super(resourceId); - mDirection = direction; - mLocalAddress = localAddress; - mRemoteAddress = remoteAddress; + mSourceAddress = sourceAddress; + mDestinationAddress = destinationAddress; mSpi = spi; } @@ -645,7 +634,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); + mResourceId, mSourceAddress, mDestinationAddress, mSpi); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } catch (RemoteException e) { @@ -661,6 +650,10 @@ public class IpSecService extends IIpSecService.Stub { return mSpi; } + public String getDestinationAddress() { + return mDestinationAddress; + } + public void setOwnedByTransform() { if (mOwnedByTransform) { // Programming error @@ -688,12 +681,10 @@ public class IpSecService extends IIpSecService.Stub { .append(super.toString()) .append(", mSpi=") .append(mSpi) - .append(", mDirection=") - .append(mDirection) - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) + .append(", mSourceAddress=") + .append(mSourceAddress) + .append(", mDestinationAddress=") + .append(mDestinationAddress) .append(", mOwnedByTransform=") .append(mOwnedByTransform) .append("}"); @@ -771,14 +762,17 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { - this(context, config, (fd, uid) -> { - try{ - TrafficStats.setThreadStatsUid(uid); - TrafficStats.tagFileDescriptor(fd); - } finally { - TrafficStats.clearThreadStatsUid(); - } - }); + this( + context, + config, + (fd, uid) -> { + try { + TrafficStats.setThreadStatsUid(uid); + TrafficStats.tagFileDescriptor(fd); + } finally { + TrafficStats.clearThreadStatsUid(); + } + }); } /** @hide */ @@ -844,8 +838,8 @@ public class IpSecService extends IIpSecService.Stub { */ private static void checkDirection(int direction) { switch (direction) { - case IpSecTransform.DIRECTION_OUT: - case IpSecTransform.DIRECTION_IN: + case IpSecManager.DIRECTION_OUT: + case IpSecManager.DIRECTION_IN: return; } throw new IllegalArgumentException("Invalid Direction: " + direction); @@ -854,10 +848,8 @@ public class IpSecService extends IIpSecService.Stub { /** Get a new SPI and maintain the reservation in the system server */ @Override public synchronized IpSecSpiResponse allocateSecurityParameterIndex( - int direction, String remoteAddress, int requestedSpi, IBinder binder) - throws RemoteException { - checkDirection(direction); - checkInetAddress(remoteAddress); + String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { + checkInetAddress(destinationAddress); /* requestedSpi can be anything in the int range, so no check is needed. */ checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); @@ -865,28 +857,21 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - String localAddress = ""; - try { if (!userRecord.mSpiQuotaTracker.isAvailable()) { return new IpSecSpiResponse( IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } + spi = mSrvConfig .getNetdInstance() - .ipSecAllocateSpi( - resourceId, - direction, - localAddress, - remoteAddress, - requestedSpi); + .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, new RefcountedResource<SpiRecord>( - new SpiRecord(resourceId, direction, localAddress, remoteAddress, spi), - binder)); + new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { // TODO: Add appropriate checks when other ServiceSpecificException types are supported return new IpSecSpiResponse( @@ -1030,6 +1015,30 @@ public class IpSecService extends IIpSecService.Stub { releaseResource(userRecord.mEncapSocketRecords, resourceId); } + @VisibleForTesting + void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException { + IpSecAlgorithm auth = config.getAuthentication(); + IpSecAlgorithm crypt = config.getEncryption(); + IpSecAlgorithm aead = config.getAuthenticatedEncryption(); + + // Validate the algorithm set + Preconditions.checkArgument( + aead != null || crypt != null || auth != null, + "No Encryption or Authentication algorithms specified"); + Preconditions.checkArgument( + auth == null || auth.isAuthentication(), + "Unsupported algorithm for Authentication"); + Preconditions.checkArgument( + crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption"); + Preconditions.checkArgument( + aead == null || aead.isAead(), + "Unsupported algorithm for Authenticated Encryption"); + Preconditions.checkArgument( + aead == null || (auth == null && crypt == null), + "Authenticated Encryption is mutually exclusive with other Authentication " + + "or Encryption algorithms"); + } + /** * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an * IllegalArgumentException if they are not. @@ -1037,29 +1046,6 @@ public class IpSecService extends IIpSecService.Stub { private void checkIpSecConfig(IpSecConfig config) { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - if (config.getLocalAddress() == null) { - throw new IllegalArgumentException("Invalid null Local InetAddress"); - } - - if (config.getRemoteAddress() == null) { - throw new IllegalArgumentException("Invalid null Remote InetAddress"); - } - - switch (config.getMode()) { - case IpSecTransform.MODE_TRANSPORT: - if (!config.getLocalAddress().isEmpty()) { - throw new IllegalArgumentException("Non-empty Local Address"); - } - // Must be valid, and not a wildcard - checkInetAddress(config.getRemoteAddress()); - break; - case IpSecTransform.MODE_TUNNEL: - break; - default: - throw new IllegalArgumentException( - "Invalid IpSecTransform.mode: " + config.getMode()); - } - switch (config.getEncapType()) { case IpSecTransform.ENCAP_NONE: break; @@ -1078,21 +1064,36 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); } - for (int direction : DIRECTIONS) { - IpSecAlgorithm crypt = config.getEncryption(direction); - IpSecAlgorithm auth = config.getAuthentication(direction); - IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction); - if (authenticatedEncryption == null && crypt == null && auth == null) { - throw new IllegalArgumentException( - "No Encryption or Authentication algorithms specified"); - } else if (authenticatedEncryption != null && (auth != null || crypt != null)) { - throw new IllegalArgumentException( - "Authenticated Encryption is mutually" - + " exclusive with other Authentication or Encryption algorithms"); - } + validateAlgorithms(config); + + // Retrieve SPI record; will throw IllegalArgumentException if not found + SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); + + // If no remote address is supplied, then use one from the SPI. + if (TextUtils.isEmpty(config.getDestinationAddress())) { + config.setDestinationAddress(s.getDestinationAddress()); + } + + // All remote addresses must match + if (!config.getDestinationAddress().equals(s.getDestinationAddress())) { + throw new IllegalArgumentException("Mismatched remote addresseses."); + } - // Retrieve SPI record; will throw IllegalArgumentException if not found - userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction)); + // This check is technically redundant due to the chain of custody between the SPI and + // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in + // the transform, this will prevent us from messing up. + checkInetAddress(config.getDestinationAddress()); + + // Require a valid source address for all transforms. + checkInetAddress(config.getSourceAddress()); + + switch (config.getMode()) { + case IpSecTransform.MODE_TRANSPORT: + case IpSecTransform.MODE_TUNNEL: + break; + default: + throw new IllegalArgumentException( + "Invalid IpSecTransform.mode: " + config.getMode()); } } @@ -1112,13 +1113,12 @@ public class IpSecService extends IIpSecService.Stub { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - // Avoid resizing by creating a dependency array of min-size 3 (1 UDP encap + 2 SPIs) - List<RefcountedResource> dependencies = new ArrayList<>(3); + // Avoid resizing by creating a dependency array of min-size 2 (1 UDP encap + 1 SPI) + List<RefcountedResource> dependencies = new ArrayList<>(2); if (!userRecord.mTransformQuotaTracker.isAvailable()) { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } - SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; int encapType, encapLocalPort = 0, encapRemotePort = 0; EncapSocketRecord socketRecord = null; @@ -1134,51 +1134,46 @@ public class IpSecService extends IIpSecService.Stub { encapRemotePort = c.getEncapRemotePort(); } - for (int direction : DIRECTIONS) { - IpSecAlgorithm auth = c.getAuthentication(direction); - IpSecAlgorithm crypt = c.getEncryption(direction); - IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction); + IpSecAlgorithm auth = c.getAuthentication(); + IpSecAlgorithm crypt = c.getEncryption(); + IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); - RefcountedResource<SpiRecord> refcountedSpiRecord = - userRecord.mSpiRecords.getRefcountedResourceOrThrow( - c.getSpiResourceId(direction)); - dependencies.add(refcountedSpiRecord); + RefcountedResource<SpiRecord> refcountedSpiRecord = + userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId()); + dependencies.add(refcountedSpiRecord); + SpiRecord spiRecord = refcountedSpiRecord.getResource(); - spis[direction] = refcountedSpiRecord.getResource(); - int spi = spis[direction].getSpi(); - try { - mSrvConfig - .getNetdInstance() - .ipSecAddSecurityAssociation( - resourceId, - c.getMode(), - direction, - c.getLocalAddress(), - c.getRemoteAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, - spi, - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } + try { + mSrvConfig + .getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + c.getSourceAddress(), + c.getDestinationAddress(), + (c.getNetwork() != null) ? c.getNetwork().netId : 0, + spiRecord.getSpi(), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : new byte[] {}, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : new byte[] {}, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } // Both SAs were created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( resourceId, new RefcountedResource<TransformRecord>( - new TransformRecord(resourceId, c, spis, socketRecord), + new TransformRecord(resourceId, c, spiRecord, socketRecord), binder, dependencies.toArray(new RefcountedResource[dependencies.size()]))); return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); @@ -1202,9 +1197,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void applyTransportModeTransform( - ParcelFileDescriptor socket, int resourceId) throws RemoteException { + ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - + checkDirection(direction); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); @@ -1215,17 +1210,15 @@ public class IpSecService extends IIpSecService.Stub { IpSecConfig c = info.getConfig(); try { - for (int direction : DIRECTIONS) { - mSrvConfig - .getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - c.getLocalAddress(), - c.getRemoteAddress(), - info.getSpiRecord(direction).getSpi()); - } + mSrvConfig + .getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } catch (ServiceSpecificException e) { if (e.errorCode == EINVAL) { throw new IllegalArgumentException(e.toString()); @@ -1236,13 +1229,13 @@ public class IpSecService extends IIpSecService.Stub { } /** - * Remove a transport mode transform from a socket, applying the default (empty) policy. This - * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of - * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not - * used: reserved for future improved input validation. + * Remove transport mode transforms from a socket, applying the default (empty) policy. This + * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a + * policy that performs no IPsec). Today the resourceId parameter is passed but not used: + * reserved for future improved input validation. */ @Override - public synchronized void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { try { mSrvConfig diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 8a15ded2960f..88ae22477a9d 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -18,11 +18,9 @@ package com.android.server; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.SHUTDOWN; -import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; -import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE; @@ -209,12 +207,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int StrictCleartext = 617; } - /* Defaults for resolver parameters. */ - public static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; - public static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; - public static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; - public static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; - /** * String indicating a softap command. */ @@ -1768,6 +1760,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub @Override public boolean setDataSaverModeEnabled(boolean enable) { + mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG); + if (DBG) Log.d(TAG, "setDataSaverMode: " + enable); synchronized (mQuotaLock) { if (mDataSaverMode == enable) { @@ -1947,80 +1941,19 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override - public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) { + public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains, + int[] params, boolean useTls, String tlsHostname) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - final ContentResolver cr = mContext.getContentResolver(); - - int sampleValidity = Settings.Global.getInt(cr, - Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, - DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); - if (sampleValidity < 0 || sampleValidity > 65535) { - Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" + - DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); - sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS; - } - - int successThreshold = Settings.Global.getInt(cr, - Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, - DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); - if (successThreshold < 0 || successThreshold > 100) { - Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" + - DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); - successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT; - } - - int minSamples = Settings.Global.getInt(cr, - Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); - int maxSamples = Settings.Global.getInt(cr, - Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); - if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) { - Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples + - "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " + - DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")"); - minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES; - maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES; - } - - final String[] domainStrs = domains == null ? new String[0] : domains.split(" "); - final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples }; - final boolean useTls = shouldUseTls(cr); - // TODO: Populate tlsHostname once it's decided how the hostname's IP - // addresses will be resolved: - // - // [1] network-provided DNS servers are included here with the - // hostname and netd will use the network-provided servers to - // resolve the hostname and fix up its internal structures, or - // - // [2] network-provided DNS servers are included here without the - // hostname, the ConnectivityService layer resolves the given - // hostname, and then reconfigures netd with this information. - // - // In practice, there will always be a need for ConnectivityService or - // the captive portal app to use the network-provided services to make - // some queries. This argues in favor of [1], in concert with another - // mechanism, perhaps setting a high bit in the netid, to indicate - // via existing DNS APIs which set of servers (network-provided or - // non-network-provided private DNS) should be queried. - final String tlsHostname = ""; final String[] tlsFingerprints = new String[0]; try { - mNetdService.setResolverConfiguration(netId, servers, domainStrs, params, - useTls, tlsHostname, tlsFingerprints); + mNetdService.setResolverConfiguration( + netId, servers, domains, params, useTls, tlsHostname, tlsFingerprints); } catch (RemoteException e) { throw new RuntimeException(e); } } - private static boolean shouldUseTls(ContentResolver cr) { - String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE); - if (TextUtils.isEmpty(privateDns)) { - privateDns = PRIVATE_DNS_DEFAULT_MODE; - } - return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) || - privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); - } - @Override public void addVpnUidRanges(int netId, UidRange[] ranges) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); @@ -2563,12 +2496,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub @Override public void removeNetwork(int netId) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG); try { - mConnector.execute("network", "destroy", netId); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + mNetdService.networkDestroy(netId); + } catch (ServiceSpecificException e) { + Log.w(TAG, "removeNetwork(" + netId + "): ", e); + throw e; + } catch (RemoteException e) { + Log.w(TAG, "removeNetwork(" + netId + "): ", e); + throw e.rethrowAsRuntimeException(); } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 831c9cbc2ef5..6747be340d46 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -147,6 +147,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataActivationState; + private boolean[] mUserMobileDataState; + private SignalStrength[] mSignalStrength; private boolean[] mMessageWaiting; @@ -304,6 +306,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mServiceState = new ServiceState[numPhones]; mVoiceActivationState = new int[numPhones]; mDataActivationState = new int[numPhones]; + mUserMobileDataState = new boolean[numPhones]; mSignalStrength = new SignalStrength[numPhones]; mMessageWaiting = new boolean[numPhones]; mCallForwarding = new boolean[numPhones]; @@ -320,6 +323,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallIncomingNumber[i] = ""; mServiceState[i] = new ServiceState(); mSignalStrength[i] = new SignalStrength(); + mUserMobileDataState[i] = false; mMessageWaiting[i] = false; mCallForwarding[i] = false; mCellLocation[i] = new Bundle(); @@ -656,6 +660,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) { + try { + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + } catch (RemoteException ex) { + remove(r.binder); + } + } } } } else { @@ -1012,6 +1023,33 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + public void notifyUserMobileDataStateChangedForPhoneId(int phoneId, int subId, boolean state) { + if (!checkNotifyPermission("notifyUserMobileDataStateChanged()")) { + return; + } + if (VDBG) { + log("notifyUserMobileDataStateChangedForSubscriberPhoneID: subId=" + phoneId + + " state=" + state); + } + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mMessageWaiting[phoneId] = state; + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) && + idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onUserMobileDataStateChanged(state); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + public void notifyCallForwardingChanged(boolean cfi) { notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cfi); } @@ -1374,6 +1412,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mServiceState=" + mServiceState[i]); pw.println("mVoiceActivationState= " + mVoiceActivationState[i]); pw.println("mDataActivationState= " + mDataActivationState[i]); + pw.println("mUserMobileDataState= " + mUserMobileDataState[i]); pw.println("mSignalStrength=" + mSignalStrength[i]); pw.println("mMessageWaiting=" + mMessageWaiting[i]); pw.println("mCallForwarding=" + mCallForwarding[i]); @@ -1755,6 +1794,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) { + try { + if (VDBG) { + log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId=" + + phoneId + " umds=" + mUserMobileDataState[phoneId]); + } + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { try { if (VDBG) { diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 8d46d1e27235..7ce0f4352203 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -87,6 +87,7 @@ public class Watchdog extends Thread { "/system/bin/sdcard", "/system/bin/surfaceflinger", "media.extractor", // system/bin/mediaextractor + "media.metrics", // system/bin/mediametrics "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service "com.android.bluetooth", // Bluetooth service }; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dce0c3852238..002381a5a3f0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -200,6 +200,7 @@ import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -1548,6 +1549,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final List<ScreenObserver> mScreenObservers = new ArrayList<>(); + final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1689,6 +1692,8 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; + static final int DISPATCH_SCREEN_AWAKE_MSG = 71; + static final int DISPATCH_SCREEN_KEYGUARD_MSG = 72; static final int START_USER_SWITCH_FG_MSG = 712; static final int NOTIFY_VR_KEYGUARD_MSG = 74; @@ -2412,11 +2417,17 @@ public class ActivityManagerService extends IActivityManager.Stub } } } break; - case NOTIFY_VR_SLEEPING_MSG: { - notifyVrManagerOfSleepState(msg.arg1 != 0); + case DISPATCH_SCREEN_AWAKE_MSG: { + final boolean isAwake = msg.arg1 != 0; + for (int i = mScreenObservers.size() - 1; i >= 0; i--) { + mScreenObservers.get(i).onAwakeStateChanged(isAwake); + } } break; - case NOTIFY_VR_KEYGUARD_MSG: { - notifyVrManagerOfKeyguardState(msg.arg1 != 0); + case DISPATCH_SCREEN_KEYGUARD_MSG: { + final boolean isShowing = msg.arg1 != 0; + for (int i = mScreenObservers.size() - 1; i >= 0; i--) { + mScreenObservers.get(i).onKeyguardStateChanged(isShowing); + } } break; case HANDLE_TRUST_STORAGE_UPDATE_MSG: { synchronized (ActivityManagerService.this) { @@ -3260,32 +3271,6 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); } - private void sendNotifyVrManagerOfSleepState(boolean isSleeping) { - mHandler.sendMessage( - mHandler.obtainMessage(NOTIFY_VR_SLEEPING_MSG, isSleeping ? 1 : 0, 0)); - } - - private void notifyVrManagerOfSleepState(boolean isSleeping) { - final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); - if (vrService == null) { - return; - } - vrService.onSleepStateChanged(isSleeping); - } - - private void sendNotifyVrManagerOfKeyguardState(boolean isShowing) { - mHandler.sendMessage( - mHandler.obtainMessage(NOTIFY_VR_KEYGUARD_MSG, isShowing ? 1 : 0, 0)); - } - - private void notifyVrManagerOfKeyguardState(boolean isShowing) { - final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); - if (vrService == null) { - return; - } - vrService.onKeyguardStateChanged(isShowing); - } - final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; @@ -7027,15 +7012,22 @@ public class ActivityManagerService extends IActivityManager.Stub } ProfilerInfo profilerInfo = null; - String agent = null; + String preBindAgent = null; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; - profilerInfo = (mProfilerInfo != null && mProfilerInfo.profileFile != null) ? - new ProfilerInfo(mProfilerInfo) : null; - agent = mProfilerInfo != null ? mProfilerInfo.agent : null; + if (mProfilerInfo != null) { + // Send a profiler info object to the app if either a file is given, or + // an agent should be loaded at bind-time. + boolean needsInfo = mProfilerInfo.profileFile != null + || mProfilerInfo.attachAgentDuringBind; + profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null; + if (!mProfilerInfo.attachAgentDuringBind) { + preBindAgent = mProfilerInfo.agent; + } + } } else if (app.instr != null && app.instr.mProfileFile != null) { profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false, - null); + null, false); } boolean enableTrackAllocation = false; @@ -7102,8 +7094,8 @@ public class ActivityManagerService extends IActivityManager.Stub // If we were asked to attach an agent on startup, do so now, before we're binding // application code. - if (agent != null) { - thread.attachAgent(agent); + if (preBindAgent != null) { + thread.attachAgent(preBindAgent); } checkTime(startTime, "attachApplicationLocked: immediately before bindApplication"); @@ -12497,7 +12489,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (wasAwake != isAwake) { // Also update state in a special way for running foreground services UI. mServices.updateScreenStateLocked(isAwake); - sendNotifyVrManagerOfSleepState(!isAwake); + mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0) + .sendToTarget(); } } } @@ -12650,7 +12643,9 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(ident); } } - sendNotifyVrManagerOfKeyguardState(showing); + + mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, showing ? 1 : 0, 0) + .sendToTarget(); } @Override @@ -24258,6 +24253,11 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + + @Override + public void registerScreenObserver(ScreenObserver observer) { + mScreenObservers.add(observer); + } } /** diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8488e526eba9..a7ace21607b5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -114,6 +114,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private boolean mAutoStop; private boolean mStreaming; // Streaming the profiling output to a file. private String mAgent; // Agent to attach on startup. + private boolean mAttachAgentDuringBind; // Whether agent should be attached late. private int mDisplayId; private int mStackId; private int mTaskId; @@ -295,7 +296,21 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--streaming")) { mStreaming = true; } else if (opt.equals("--attach-agent")) { + if (mAgent != null) { + cmd.getErrPrintWriter().println( + "Multiple --attach-agent(-bind) not supported"); + return false; + } + mAgent = getNextArgRequired(); + mAttachAgentDuringBind = false; + } else if (opt.equals("--attach-agent-bind")) { + if (mAgent != null) { + cmd.getErrPrintWriter().println( + "Multiple --attach-agent(-bind) not supported"); + return false; + } mAgent = getNextArgRequired(); + mAttachAgentDuringBind = true; } else if (opt.equals("-R")) { mRepeat = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("-S")) { @@ -381,7 +396,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } } profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop, - mStreaming, mAgent); + mStreaming, mAgent, mAttachAgentDuringBind); } pw.println("Starting: " + intent); @@ -755,7 +770,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming, - null); + null, false); } try { @@ -2679,6 +2694,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" (use with --start-profiler)"); pw.println(" -P <FILE>: like above, but profiling stops when app goes idle"); pw.println(" --attach-agent <agent>: attach the given agent before binding"); + pw.println(" --attach-agent-bind <agent>: attach the given agent during binding"); pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,"); pw.println(" the top activity will be finished."); pw.println(" -S: force stop the target app before starting the activity"); diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java new file mode 100644 index 000000000000..a1c54bd4885b --- /dev/null +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; +import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES; +import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; +import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; +import static android.provider.Settings.Global.PRIVATE_DNS_MODE; +import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkUtils; +import android.net.Uri; +import android.os.Binder; +import android.os.INetworkManagementService; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.system.GaiException; +import android.system.OsConstants; +import android.system.StructAddrinfo; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.server.connectivity.MockableSystemProperties; + +import libcore.io.Libcore; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.StringJoiner; + + +/** + * Encapsulate the management of DNS settings for networks. + * + * This class it NOT designed for concurrent access. Furthermore, all non-static + * methods MUST be called from ConnectivityService's thread. + * + * @hide + */ +public class DnsManager { + private static final String TAG = DnsManager.class.getSimpleName(); + + /* Defaults for resolver parameters. */ + private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; + private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; + private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; + private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; + + public static class PrivateDnsConfig { + public final boolean useTls; + public final String hostname; + public final InetAddress[] ips; + + public PrivateDnsConfig() { + this(false); + } + + public PrivateDnsConfig(boolean useTls) { + this.useTls = useTls; + this.hostname = ""; + this.ips = new InetAddress[0]; + } + + public PrivateDnsConfig(String hostname, InetAddress[] ips) { + this.useTls = !TextUtils.isEmpty(hostname); + this.hostname = useTls ? hostname : ""; + this.ips = (ips != null) ? ips : new InetAddress[0]; + } + + public PrivateDnsConfig(PrivateDnsConfig cfg) { + useTls = cfg.useTls; + hostname = cfg.hostname; + ips = cfg.ips; + } + + public boolean inStrictMode() { + return useTls && !TextUtils.isEmpty(hostname); + } + + public String toString() { + return PrivateDnsConfig.class.getSimpleName() + + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}"; + } + } + + public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) { + final String mode = getPrivateDnsMode(cr); + + final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode); + + if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) { + final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER); + return new PrivateDnsConfig(specifier, null); + } + + return new PrivateDnsConfig(useTls); + } + + public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) { + final StructAddrinfo hints = new StructAddrinfo(); + // Unnecessary, but expressly no AI_ADDRCONFIG. + hints.ai_flags = 0; + // Fetch all IP addresses at once to minimize re-resolution. + hints.ai_family = OsConstants.AF_UNSPEC; + hints.ai_socktype = OsConstants.SOCK_DGRAM; + + try { + final InetAddress[] ips = Libcore.os.android_getaddrinfo(name, hints, network.netId); + if (ips != null && ips.length > 0) { + return new PrivateDnsConfig(name, ips); + } + } catch (GaiException ignored) {} + + return null; + } + + public static Uri[] getPrivateDnsSettingsUris() { + final Uri[] uris = new Uri[2]; + uris[0] = Settings.Global.getUriFor(PRIVATE_DNS_MODE); + uris[1] = Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER); + return uris; + } + + private final Context mContext; + private final ContentResolver mContentResolver; + private final INetworkManagementService mNMS; + private final MockableSystemProperties mSystemProperties; + private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; + + private int mNumDnsEntries; + private int mSampleValidity; + private int mSuccessThreshold; + private int mMinSamples; + private int mMaxSamples; + private String mPrivateDnsMode; + private String mPrivateDnsSpecifier; + + public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) { + mContext = ctx; + mContentResolver = mContext.getContentResolver(); + mNMS = nms; + mSystemProperties = sp; + mPrivateDnsMap = new HashMap<>(); + + // TODO: Create and register ContentObservers to track every setting + // used herein, posting messages to respond to changes. + } + + public PrivateDnsConfig getPrivateDnsConfig() { + return getPrivateDnsConfig(mContentResolver); + } + + public void removeNetwork(Network network) { + mPrivateDnsMap.remove(network.netId); + } + + public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { + Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")"); + return (cfg != null) + ? mPrivateDnsMap.put(network.netId, cfg) + : mPrivateDnsMap.remove(network); + } + + public void setDnsConfigurationForNetwork( + int netId, LinkProperties lp, boolean isDefaultNetwork) { + // We only use the PrivateDnsConfig data pushed to this class instance + // from ConnectivityService because it works in coordination with + // NetworkMonitor to decide which networks need validation and runs the + // blocking calls to resolve Private DNS strict mode hostnames. + // + // At this time we do attempt to enable Private DNS on non-Internet + // networks like IMS. + final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId); + + final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls; + final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode(); + final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; + + final String[] serverStrs = NetworkUtils.makeStrings( + strictMode ? Arrays.stream(privateDnsCfg.ips) + .filter((ip) -> lp.isReachable(ip)) + .collect(Collectors.toList()) + : lp.getDnsServers()); + final String[] domainStrs = getDomainStrings(lp.getDomains()); + + updateParametersSettings(); + final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; + + Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", + netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs), + Arrays.toString(params), useTls, tlsHostname)); + try { + mNMS.setDnsConfigurationForNetwork( + netId, serverStrs, domainStrs, params, useTls, tlsHostname); + } catch (Exception e) { + Slog.e(TAG, "Error setting DNS configuration: " + e); + return; + } + + // TODO: netd should listen on [::1]:53 and proxy queries to the current + // default network, and we should just set net.dns1 to ::1, not least + // because applications attempting to use net.dns resolvers will bypass + // the privacy protections of things like DNS-over-TLS. + if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers()); + flushVmDnsCache(); + } + + public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { + int last = 0; + for (InetAddress dns : dnses) { + ++last; + setNetDnsProperty(last, dns.getHostAddress()); + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + setNetDnsProperty(i, ""); + } + mNumDnsEntries = last; + } + + private void flushVmDnsCache() { + /* + * Tell the VMs to toss their DNS caches + */ + final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + /* + * Connectivity events can happen before boot has completed ... + */ + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void updateParametersSettings() { + mSampleValidity = getIntSetting( + DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); + if (mSampleValidity < 0 || mSampleValidity > 65535) { + Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" + + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); + mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS; + } + + mSuccessThreshold = getIntSetting( + DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); + if (mSuccessThreshold < 0 || mSuccessThreshold > 100) { + Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" + + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); + mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT; + } + + mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); + mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); + if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) { + Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples + + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " + + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")"); + mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES; + mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES; + } + } + + private int getIntSetting(String which, int dflt) { + return Settings.Global.getInt(mContentResolver, which, dflt); + } + + private void setNetDnsProperty(int which, String value) { + final String key = "net.dns" + which; + // Log and forget errors setting unsupported properties. + try { + mSystemProperties.set(key, value); + } catch (Exception e) { + Slog.e(TAG, "Error setting unsupported net.dns property: ", e); + } + } + + private static String getPrivateDnsMode(ContentResolver cr) { + final String mode = getStringSetting(cr, PRIVATE_DNS_MODE); + return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE; + } + + private static String getStringSetting(ContentResolver cr, String which) { + return Settings.Global.getString(cr, which); + } + + private static String[] getDomainStrings(String domains) { + return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" "); + } +} diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 768403024353..ed268581b50c 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -29,6 +29,7 @@ import android.net.CaptivePortal; import android.net.ConnectivityManager; import android.net.ICaptivePortal; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.ProxyInfo; import android.net.TrafficStats; @@ -215,6 +216,15 @@ public class NetworkMonitor extends StateMachine { */ private static final int CMD_CAPTIVE_PORTAL_RECHECK = BASE + 12; + /** + * ConnectivityService notifies NetworkMonitor of settings changes to + * Private DNS. If a DNS resolution is required, e.g. for DNS-over-TLS in + * strict mode, then an event is sent back to ConnectivityService with the + * result of the resolution attempt. + */ + private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = BASE + 13; + public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = BASE + 14; + // Start mReevaluateDelayMs at this value and double. private static final int INITIAL_REEVALUATE_DELAY_MS = 1000; private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000; @@ -230,6 +240,12 @@ public class NetworkMonitor extends StateMachine { private static final int NUM_VALIDATION_LOG_LINES = 20; + public static boolean isValidationRequired( + NetworkCapabilities dfltNetCap, NetworkCapabilities nc) { + // TODO: Consider requiring validation for DUN networks. + return dfltNetCap.satisfiedByNetworkCapabilities(nc); + } + private final Context mContext; private final Handler mConnectivityServiceHandler; private final NetworkAgentInfo mNetworkAgentInfo; @@ -261,6 +277,8 @@ public class NetworkMonitor extends StateMachine { public boolean systemReady = false; + private DnsManager.PrivateDnsConfig mPrivateDnsCfg = null; + private final State mDefaultState = new DefaultState(); private final State mValidatedState = new ValidatedState(); private final State mMaybeNotifyState = new MaybeNotifyState(); @@ -342,6 +360,11 @@ public class NetworkMonitor extends StateMachine { return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION; } + private boolean isValidationRequired() { + return isValidationRequired( + mDefaultRequest.networkCapabilities, mNetworkAgentInfo.networkCapabilities); + } + // DefaultState is the parent of all States. It exists only to handle CMD_* messages but // does not entail any real state (hence no enter() or exit() routines). private class DefaultState extends State { @@ -405,6 +428,18 @@ public class NetworkMonitor extends StateMachine { break; } return HANDLED; + case CMD_PRIVATE_DNS_SETTINGS_CHANGED: + if (isValidationRequired()) { + // This performs a blocking DNS resolution of the + // strict mode hostname, if required. + resolvePrivateDnsConfig((DnsManager.PrivateDnsConfig) message.obj); + if ((mPrivateDnsCfg != null) && mPrivateDnsCfg.inStrictMode()) { + mConnectivityServiceHandler.sendMessage(obtainMessage( + EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0, mNetId, + new DnsManager.PrivateDnsConfig(mPrivateDnsCfg))); + } + } + return HANDLED; default: return HANDLED; } @@ -421,7 +456,7 @@ public class NetworkMonitor extends StateMachine { maybeLogEvaluationResult( networkEventType(validationStage(), EvaluationResult.VALIDATED)); mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, - NETWORK_TEST_RESULT_VALID, mNetId, null)); + NETWORK_TEST_RESULT_VALID, mNetId, mPrivateDnsCfg)); mValidations++; } @@ -567,9 +602,9 @@ public class NetworkMonitor extends StateMachine { // the network so don't bother validating here. Furthermore sending HTTP // packets over the network may be undesirable, for example an extremely // expensive metered network, or unwanted leaking of the User Agent string. - if (!mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities( - mNetworkAgentInfo.networkCapabilities)) { + if (!isValidationRequired()) { validationLog("Network would not satisfy default request, not validating"); + mPrivateDnsCfg = null; transitionTo(mValidatedState); return HANDLED; } @@ -582,6 +617,7 @@ public class NetworkMonitor extends StateMachine { // if this is found to cause problems. CaptivePortalProbeResult probeResult = isCaptivePortal(); if (probeResult.isSuccessful()) { + resolvePrivateDnsConfig(); transitionTo(mValidatedState); } else if (probeResult.isPortal()) { mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, @@ -1045,6 +1081,44 @@ public class NetworkMonitor extends StateMachine { return null; } + public void notifyPrivateDnsSettingsChanged(DnsManager.PrivateDnsConfig newCfg) { + // Cancel any outstanding resolutions. + removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED); + // Send the update to the proper thread. + sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg); + } + + private void resolvePrivateDnsConfig() { + resolvePrivateDnsConfig(DnsManager.getPrivateDnsConfig(mContext.getContentResolver())); + } + + private void resolvePrivateDnsConfig(DnsManager.PrivateDnsConfig cfg) { + // Nothing to do. + if (cfg == null) { + mPrivateDnsCfg = null; + return; + } + + // No DNS resolution required. + if (!cfg.inStrictMode()) { + mPrivateDnsCfg = cfg; + return; + } + + if ((mPrivateDnsCfg != null) && mPrivateDnsCfg.inStrictMode() && + (mPrivateDnsCfg.ips.length > 0) && mPrivateDnsCfg.hostname.equals(cfg.hostname)) { + // We have already resolved this strict mode hostname. Assume that + // Private DNS services won't be changing serving IP addresses very + // frequently and save ourselves one re-resolve. + return; + } + + mPrivateDnsCfg = cfg; + final DnsManager.PrivateDnsConfig resolvedCfg = DnsManager.tryBlockingResolveOf( + mNetwork, mPrivateDnsCfg.hostname); + if (resolvedCfg != null) mPrivateDnsCfg = resolvedCfg; + } + /** * @param responseReceived - whether or not we received a valid HTTP response to our request. * If false, isCaptivePortal and responseTimestampMs are ignored diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index d1bab8920a80..7b171b30b356 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -19,7 +19,6 @@ package com.android.server.connectivity; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; -import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -43,7 +42,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; @@ -53,9 +51,7 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; -import android.net.NetworkCapabilities; import android.net.NetworkInfo; -import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; @@ -76,7 +72,6 @@ import android.os.ResultReceiver; import android.os.UserHandle; import android.provider.Settings; import android.telephony.CarrierConfigManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; @@ -85,8 +80,6 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; @@ -110,12 +103,8 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; /** @@ -193,8 +182,6 @@ public class Tethering extends BaseNetworkObserver { private int mLastNotificationId; private boolean mRndisEnabled; // track the RNDIS function enabled state - private boolean mUsbTetherRequested; // true if USB tethering should be started - // when RNDIS is enabled // True iff. WiFi tethering should be started when soft AP is ready. private boolean mWifiTetherRequested; @@ -867,33 +854,18 @@ public class Tethering extends BaseNetworkObserver { // // For more explanation, see b/62552150 . synchronized (Tethering.this.mPublicSync) { - // Always record the state of RNDIS. - // TODO: consider: - // final boolean disconnected = !usbConnected; - // if (disconnected) { - // mRndisEnabled = false; - // mUsbTetherRequested = false; - // return; - // } - // final boolean configured = usbConnected && usbConfigured; - // mRndisEnabled = configured ? rndisEnabled : false; - // if (!configured) return; - mRndisEnabled = rndisEnabled; - - if (usbConnected && !usbConfigured) { - // Nothing to do here (only CONNECTED, not yet CONFIGURED). - return; - } - - // start tethering if we have a request pending - if (usbConfigured && mRndisEnabled && mUsbTetherRequested) { + if (!usbConnected && mRndisEnabled) { + // Turn off tethering if it was enabled and there is a disconnect. + tetherMatchingInterfaces( + IControlsTethering.STATE_AVAILABLE, + ConnectivityManager.TETHERING_USB); + } else if (usbConfigured && rndisEnabled) { + // Tether if rndis is enabled and usb is configured. tetherMatchingInterfaces( IControlsTethering.STATE_TETHERED, ConnectivityManager.TETHERING_USB); } - - // TODO: Figure out how to remove the need for this variable. - mUsbTetherRequested = false; + mRndisEnabled = usbConfigured && rndisEnabled; } } @@ -1065,34 +1037,8 @@ public class Tethering extends BaseNetworkObserver { public int setUsbTethering(boolean enable) { if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")"); UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); - synchronized (mPublicSync) { - if (enable) { - if (mRndisEnabled) { - final long ident = Binder.clearCallingIdentity(); - try { - tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, - ConnectivityManager.TETHERING_USB); - } finally { - Binder.restoreCallingIdentity(ident); - } - } else { - mUsbTetherRequested = true; - usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false); - } - } else { - final long ident = Binder.clearCallingIdentity(); - try { - tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, - ConnectivityManager.TETHERING_USB); - } finally { - Binder.restoreCallingIdentity(ident); - } - if (mRndisEnabled) { - usbManager.setCurrentFunction(null, false); - } - mUsbTetherRequested = false; - } + usbManager.setCurrentFunction(enable ? UsbManager.USB_FUNCTION_RNDIS : null, false); } return ConnectivityManager.TETHER_ERROR_NO_ERROR; } @@ -1149,7 +1095,7 @@ public class Tethering extends BaseNetworkObserver { if (!mForwardedDownstreams.isEmpty()) return true; synchronized (mPublicSync) { - return mUsbTetherRequested || mWifiTetherRequested; + return mWifiTetherRequested; } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index c7a43153c0aa..aa174e3ad715 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -18,6 +18,7 @@ package com.android.server.connectivity; import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.net.ConnectivityManager.NETID_UNSET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.RouteInfo.RTN_THROW; @@ -128,7 +129,7 @@ public class Vpn { // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on // the device idle whitelist during service launch and VPN bootstrap. - private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION = 60 * 1000; + private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000; // TODO: create separate trackers for each unique VPN to support // automated reconnection @@ -183,10 +184,10 @@ public class Vpn { @GuardedBy("this") private Set<UidRange> mBlockedUsers = new ArraySet<>(); - // Handle of user initiating VPN. + // Handle of the user initiating VPN. private final int mUserHandle; - // Listen to package remove and change event in this user + // Listen to package removal and change events (update/uninstall) for this user private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -197,14 +198,14 @@ public class Vpn { } synchronized (Vpn.this) { - // Avoid race that always-on package has been unset + // Avoid race where always-on package has been unset if (!packageName.equals(getAlwaysOnPackage())) { return; } final String action = intent.getAction(); - Log.i(TAG, "Received broadcast " + action + " for always-on package " + packageName - + " in user " + mUserHandle); + Log.i(TAG, "Received broadcast " + action + " for always-on VPN package " + + packageName + " in user " + mUserHandle); switch(action) { case Intent.ACTION_PACKAGE_REPLACED: @@ -248,7 +249,8 @@ public class Vpn { Log.wtf(TAG, "Problem registering observer", e); } - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE, + "" /* subtypeName */); mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); @@ -258,7 +260,7 @@ public class Vpn { } /** - * Set if this object is responsible for watching for {@link NetworkInfo} + * Set whether this object is responsible for watching for {@link NetworkInfo} * teardown. When {@code false}, teardown is handled externally by someone * else. */ @@ -297,11 +299,13 @@ public class Vpn { int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; boolean metered = false; boolean roaming = false; + boolean congested = false; if (ArrayUtils.isEmpty(underlyingNetworks)) { // No idea what the underlying networks are; assume sane defaults metered = true; roaming = false; + congested = false; } else { for (Network underlying : underlyingNetworks) { final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); @@ -318,22 +322,16 @@ public class Vpn { underlyingCaps.getLinkUpstreamBandwidthKbps()); metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED); roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING); + congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED); } } caps.setTransportTypes(transportTypes); caps.setLinkDownstreamBandwidthKbps(downKbps); caps.setLinkUpstreamBandwidthKbps(upKbps); - if (metered) { - caps.removeCapability(NET_CAPABILITY_NOT_METERED); - } else { - caps.addCapability(NET_CAPABILITY_NOT_METERED); - } - if (roaming) { - caps.removeCapability(NET_CAPABILITY_NOT_ROAMING); - } else { - caps.addCapability(NET_CAPABILITY_NOT_ROAMING); - } + caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered); + caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming); + caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested); } /** @@ -481,7 +479,6 @@ public class Vpn { } private void unregisterPackageChangeReceiverLocked() { - // register previous intent filter if (mIsPackageIntentReceiverRegistered) { mContext.unregisterReceiver(mPackageIntentReceiver); mIsPackageIntentReceiverRegistered = false; @@ -582,7 +579,7 @@ public class Vpn { DeviceIdleController.LocalService idleController = LocalServices.getService(DeviceIdleController.LocalService.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, - VPN_LAUNCH_IDLE_WHITELIST_DURATION, mUserHandle, false, "vpn"); + VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn"); // Start the VPN service declared in the app's manifest. Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); @@ -612,9 +609,10 @@ public class Vpn { * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and * it can be revoked by itself. * - * Note: when we added VPN pre-consent in http://ag/522961 the names oldPackage - * and newPackage become misleading, because when an app is pre-consented, we - * actually prepare oldPackage, not newPackage. + * Note: when we added VPN pre-consent in + * https://android.googlesource.com/platform/frameworks/base/+/0554260 + * the names oldPackage and newPackage became misleading, because when + * an app is pre-consented, we actually prepare oldPackage, not newPackage. * * Their meanings actually are: * @@ -630,7 +628,7 @@ public class Vpn { * @param oldPackage The package name of the old VPN application * @param newPackage The package name of the new VPN application * - * @return true if the operation is succeeded. + * @return true if the operation succeeded. */ public synchronized boolean prepare(String oldPackage, String newPackage) { if (oldPackage != null) { @@ -639,7 +637,7 @@ public class Vpn { return false; } - // Package is not same or old package was reinstalled. + // Package is not the same or old package was reinstalled. if (!isCurrentPreparedPackage(oldPackage)) { // The package doesn't match. We return false (to obtain user consent) unless the // user has already consented to that VPN package. @@ -861,8 +859,8 @@ public class Vpn { long token = Binder.clearCallingIdentity(); try { - mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, - mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { + mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */, + mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) { @Override public void unwanted() { // We are user controlled, not driven by NetworkRequest. @@ -936,7 +934,7 @@ public class Vpn { } ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, - null, 0, mUserHandle); + null, 0, mUserHandle); if (info == null) { throw new SecurityException("Cannot find " + config.user); } @@ -944,7 +942,7 @@ public class Vpn { throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); } } catch (RemoteException e) { - throw new SecurityException("Cannot find " + config.user); + throw new SecurityException("Cannot find " + config.user); } finally { Binder.restoreCallingIdentity(token); } @@ -1337,7 +1335,7 @@ public class Vpn { } private void enforceControlPermissionOrInternalCaller() { - // Require caller to be either an application with CONTROL_VPN permission or a process + // Require the caller to be either an application with CONTROL_VPN permission or a process // in the system server. mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); @@ -1417,7 +1415,7 @@ public class Vpn { } /** - * This method should only be called by ConnectivityService. Because it doesn't + * This method should only be called by ConnectivityService because it doesn't * have enough data to fill VpnInfo.primaryUnderlyingIface field. */ public synchronized VpnInfo getVpnInfo() { @@ -1768,7 +1766,7 @@ public class Vpn { * Bringing up a VPN connection takes time, and that is all this thread * does. Here we have plenty of time. The only thing we need to take * care of is responding to interruptions as soon as possible. Otherwise - * requests will be piled up. This can be done in a Handler as a state + * requests will pile up. This could be done in a Handler as a state * machine, but it is much easier to read in the current form. */ private class LegacyVpnRunner extends Thread { @@ -1781,7 +1779,7 @@ public class Vpn { private final AtomicInteger mOuterConnection = new AtomicInteger(ConnectivityManager.TYPE_NONE); - private long mTimer = -1; + private long mBringupStartTime = -1; /** * Watch for the outer connection (passing in the constructor) going away. @@ -1861,8 +1859,8 @@ public class Vpn { synchronized (TAG) { Log.v(TAG, "Executing"); try { - execute(); - monitorDaemons(); + bringup(); + waitForDaemonsToStop(); interrupted(); // Clear interrupt flag if execute called exit. } catch (InterruptedException e) { } finally { @@ -1883,30 +1881,27 @@ public class Vpn { } } - private void checkpoint(boolean yield) throws InterruptedException { + private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException { long now = SystemClock.elapsedRealtime(); - if (mTimer == -1) { - mTimer = now; - Thread.sleep(1); - } else if (now - mTimer <= 60000) { - Thread.sleep(yield ? 200 : 1); + if (now - mBringupStartTime <= 60000) { + Thread.sleep(sleepLonger ? 200 : 1); } else { updateState(DetailedState.FAILED, "checkpoint"); - throw new IllegalStateException("Time is up"); + throw new IllegalStateException("VPN bringup took too long"); } } - private void execute() { - // Catch all exceptions so we can clean up few things. + private void bringup() { + // Catch all exceptions so we can clean up a few things. boolean initFinished = false; try { // Initialize the timer. - checkpoint(false); + mBringupStartTime = SystemClock.elapsedRealtime(); // Wait for the daemons to stop. for (String daemon : mDaemons) { while (!SystemService.isStopped(daemon)) { - checkpoint(true); + checkInterruptAndDelay(true); } } @@ -1943,7 +1938,7 @@ public class Vpn { // Wait for the daemon to start. while (!SystemService.isRunning(daemon)) { - checkpoint(true); + checkInterruptAndDelay(true); } // Create the control socket. @@ -1959,7 +1954,7 @@ public class Vpn { } catch (Exception e) { // ignore } - checkpoint(true); + checkInterruptAndDelay(true); } mSockets[i].setSoTimeout(500); @@ -1973,7 +1968,7 @@ public class Vpn { out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); - checkpoint(false); + checkInterruptAndDelay(false); } out.write(0xFF); out.write(0xFF); @@ -1989,7 +1984,7 @@ public class Vpn { } catch (Exception e) { // ignore } - checkpoint(true); + checkInterruptAndDelay(true); } } @@ -2002,7 +1997,7 @@ public class Vpn { throw new IllegalStateException(daemon + " is dead"); } } - checkpoint(true); + checkInterruptAndDelay(true); } // Now we are connected. Read and parse the new state. @@ -2058,8 +2053,8 @@ public class Vpn { // Set the start time mConfig.startTime = SystemClock.elapsedRealtime(); - // Check if the thread is interrupted while we are waiting. - checkpoint(false); + // Check if the thread was interrupted while we were waiting on the lock. + checkInterruptAndDelay(false); // Check if the interface is gone while we are waiting. if (jniCheck(mConfig.interfaze) == 0) { @@ -2082,10 +2077,11 @@ public class Vpn { } /** - * Monitor the daemons we started, moving to disconnected state if the - * underlying services fail. + * Check all daemons every two seconds. Return when one of them is stopped. + * The caller will move to the disconnected state when this function returns, + * which can happen if a daemon failed or if the VPN was torn down. */ - private void monitorDaemons() throws InterruptedException{ + private void waitForDaemonsToStop() throws InterruptedException { if (!mNetworkInfo.isConnected()) { return; } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 17adb1a74e30..2224913b2cf6 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -30,6 +30,7 @@ import android.net.RouteInfo; import android.net.ip.InterfaceController; import android.net.ip.RouterAdvertisementDaemon; import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.net.util.InterfaceParams; import android.net.util.NetdService; import android.net.util.SharedLog; import android.os.INetworkManagementService; @@ -48,7 +49,6 @@ import com.android.internal.util.StateMachine; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; @@ -120,8 +120,7 @@ public class TetherInterfaceStateMachine extends StateMachine { private int mLastError; private int mServingMode; private String mMyUpstreamIfaceName; // may change over time - private NetworkInterface mNetworkInterface; - private byte[] mHwAddr; + private InterfaceParams mInterfaceParams; // TODO: De-duplicate this with mLinkProperties above. Currently, these link // properties are those selected by the IPv6TetheringCoordinator and relayed // to us. By comparison, mLinkProperties contains the addresses and directly @@ -247,31 +246,16 @@ public class TetherInterfaceStateMachine extends StateMachine { } private boolean startIPv6() { - // TODO: Refactor for testability (perhaps passing an android.system.Os - // instance and calling getifaddrs() directly). - try { - mNetworkInterface = NetworkInterface.getByName(mIfaceName); - } catch (SocketException e) { - mLog.e("Error looking up NetworkInterfaces: " + e); - stopIPv6(); - return false; - } - if (mNetworkInterface == null) { - mLog.e("Failed to find NetworkInterface"); - stopIPv6(); - return false; - } - - try { - mHwAddr = mNetworkInterface.getHardwareAddress(); - } catch (SocketException e) { - mLog.e("Failed to find hardware address: " + e); + // TODO: Refactor for better testability. This is one of the things + // that prohibits unittesting IPv6 tethering setup. + mInterfaceParams = InterfaceParams.getByName(mIfaceName); + if (mInterfaceParams == null) { + mLog.e("Failed to find InterfaceParams"); stopIPv6(); return false; } - final int ifindex = mNetworkInterface.getIndex(); - mRaDaemon = new RouterAdvertisementDaemon(mIfaceName, ifindex, mHwAddr); + mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams); if (!mRaDaemon.start()) { stopIPv6(); return false; @@ -281,8 +265,7 @@ public class TetherInterfaceStateMachine extends StateMachine { } private void stopIPv6() { - mNetworkInterface = null; - mHwAddr = null; + mInterfaceParams = null; setRaParams(null); if (mRaDaemon != null) { diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 205e8283cc55..581e8c748e69 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -323,7 +323,7 @@ public class SyncManager { private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - EndPoint target = new EndPoint(null, null, context.getUserId()); + EndPoint target = new EndPoint(null, null, getSendingUserId()); updateRunningAccounts(target /* sync targets for user */); } }; diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index b7b91a76ebf3..625764cea550 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -39,8 +39,10 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Build; +import android.os.Handler; import android.os.IBinder; import android.os.IInterface; +import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -82,6 +84,7 @@ abstract public class ManagedServices { protected final String TAG = getClass().getSimpleName(); protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000; protected static final String ENABLED_SERVICES_SEPARATOR = ":"; /** @@ -101,12 +104,15 @@ abstract public class ManagedServices { private final IPackageManager mPm; private final UserManager mUm; private final Config mConfig; + private final Handler mHandler = new Handler(Looper.getMainLooper()); // contains connections to all connected services, including app services // and system services private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>(); // things that will be put into mServices as soon as they're ready private final ArrayList<String> mServicesBinding = new ArrayList<>(); + private final ArraySet<String> mServicesRebinding = new ArraySet<>(); + // lists the component names of all enabled (and therefore potentially connected) // app services for current profiles. private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles @@ -823,6 +829,7 @@ abstract public class ManagedServices { final String servicesBindingTag = name.toString() + "/" + userid; if (mServicesBinding.contains(servicesBindingTag)) { + Slog.v(TAG, "Not registering " + name + " as bind is already in progress"); // stop registering this thing already! we're working on it return; } @@ -871,6 +878,7 @@ abstract public class ManagedServices { boolean added = false; ManagedServiceInfo info = null; synchronized (mMutex) { + mServicesRebinding.remove(servicesBindingTag); mServicesBinding.remove(servicesBindingTag); try { mService = asInterface(binder); @@ -892,6 +900,27 @@ abstract public class ManagedServices { mServicesBinding.remove(servicesBindingTag); Slog.v(TAG, getCaption() + " connection lost: " + name); } + + @Override + public void onBindingDied(ComponentName name) { + Slog.w(TAG, getCaption() + " binding died: " + name); + synchronized (mMutex) { + mServicesBinding.remove(servicesBindingTag); + mContext.unbindService(this); + if (!mServicesRebinding.contains(servicesBindingTag)) { + mServicesRebinding.add(servicesBindingTag); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + registerService(name, userid); + } + }, ON_BINDING_DIED_REBIND_DELAY_MS); + } else { + Slog.v(TAG, getCaption() + " not rebinding as " + + "a previous rebind attempt was made: " + name); + } + } + } }; if (!mContext.bindServiceAsUser(intent, serviceConnection, diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 210eb1385035..41cfcbe1af88 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -281,13 +281,14 @@ public class Installer extends SystemService { public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, - @Nullable String seInfo, boolean downgrade) + @Nullable String seInfo, boolean downgrade, int targetSdkVersion) throws InstallerException { assertValidInstructionSet(instructionSet); if (!checkBeforeRemote()) return; try { mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, - dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade); + dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade, + targetSdkVersion); } catch (Exception e) { throw InstallerException.from(e); } diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 6253857d1aa4..5dbd3caa7b79 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -260,12 +260,13 @@ public class OtaDexoptService extends IOtaDexopt.Stub { public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, - @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade) + @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, + int targetSdkVersion) throws InstallerException { final StringBuilder builder = new StringBuilder(); - // The version. Right now it's 3. - builder.append("3 "); + // The version. Right now it's 4. + builder.append("4 "); builder.append("dexopt"); @@ -281,6 +282,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { encodeParameter(builder, sharedLibraries); encodeParameter(builder, seInfo); encodeParameter(builder, downgrade); + encodeParameter(builder, targetSdkVersion); commands.add(builder.toString()); } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 300f15fa0925..2cc51599ad16 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -274,7 +274,7 @@ public class PackageDexOptimizer { // primary dex files. mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, - false /* downgrade*/); + false /* downgrade*/, pkg.applicationInfo.targetSdkVersion); if (packageStats != null) { long endTime = System.currentTimeMillis(); @@ -395,7 +395,7 @@ public class PackageDexOptimizer { mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, /*oatDir*/ null, dexoptFlags, compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser, - options.isDowngrade()); + options.isDowngrade(), info.targetSdkVersion); } return DEX_OPT_PERFORMED; diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS index 6c8c9b20ecdb..ffc4731feadd 100644 --- a/services/core/java/com/android/server/pm/permission/OWNERS +++ b/services/core/java/com/android/server/pm/permission/OWNERS @@ -5,3 +5,4 @@ per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com per-file DefaultPermissionGrantPolicy.java = toddke@google.com per-file DefaultPermissionGrantPolicy.java = yamasani@google.com +per-file DefaultPermissionGrantPolicy.java = patb@google.com diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 853e1b269c92..3aca330ed3f2 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -24,8 +24,6 @@ import android.app.KeyguardManager; import android.app.ProgressDialog; import android.app.WallpaperColors; import android.app.WallpaperManager; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.IBluetoothManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -34,8 +32,6 @@ import android.content.IntentFilter; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.media.AudioAttributes; -import android.nfc.INfcAdapter; -import android.nfc.NfcAdapter; import android.os.FileUtils; import android.os.Handler; import android.os.PowerManager; @@ -122,9 +118,7 @@ public final class ShutdownThread extends Thread { private static String METRIC_AM = "shutdown_activity_manager"; private static String METRIC_PM = "shutdown_package_manager"; private static String METRIC_RADIOS = "shutdown_radios"; - private static String METRIC_BT = "shutdown_bt"; private static String METRIC_RADIO = "shutdown_radio"; - private static String METRIC_NFC = "shutdown_nfc"; private static String METRIC_SM = "shutdown_storage_manager"; private final Object mActionDoneSync = new Object(); @@ -418,7 +412,7 @@ public final class ShutdownThread extends Thread { /** * Makes sure we handle the shutdown gracefully. - * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. + * Shuts off power regardless of radio state if the allotted time has passed. */ public void run() { TimingsTraceLog shutdownTimingLog = newTimingsLog(); @@ -630,42 +624,10 @@ public final class ShutdownThread extends Thread { Thread t = new Thread() { public void run() { TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog(); - boolean nfcOff; - boolean bluetoothReadyForShutdown; boolean radioOff; - final INfcAdapter nfc = - INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc")); final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - final IBluetoothManager bluetooth = - IBluetoothManager.Stub.asInterface(ServiceManager.checkService( - BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE)); - try { - nfcOff = nfc == null || - nfc.getState() == NfcAdapter.STATE_OFF; - if (!nfcOff) { - Log.w(TAG, "Turning off NFC..."); - metricStarted(METRIC_NFC); - nfc.disable(false); // Don't persist new state - } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during NFC shutdown", ex); - nfcOff = true; - } - - try { - bluetoothReadyForShutdown = bluetooth == null || - bluetooth.getState() == BluetoothAdapter.STATE_OFF; - if (!bluetoothReadyForShutdown) { - Log.w(TAG, "Disabling Bluetooth..."); - metricStarted(METRIC_BT); - bluetooth.disable(mContext.getPackageName(), false); // disable but don't persist new state - } - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during bluetooth shutdown", ex); - bluetoothReadyForShutdown = true; - } try { radioOff = phone == null || !phone.needMobileRadioShutdown(); @@ -679,7 +641,7 @@ public final class ShutdownThread extends Thread { radioOff = true; } - Log.i(TAG, "Waiting for NFC, Bluetooth and Radio..."); + Log.i(TAG, "Waiting for Radio..."); long delay = endTime - SystemClock.elapsedRealtime(); while (delay > 0) { @@ -690,25 +652,6 @@ public final class ShutdownThread extends Thread { sInstance.setRebootProgress(status, null); } - if (!bluetoothReadyForShutdown) { - try { - // BLE only mode can happen when BT is turned off - // We will continue shutting down in such case - bluetoothReadyForShutdown = - bluetooth.getState() == BluetoothAdapter.STATE_OFF || - bluetooth.getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF || - bluetooth.getState() == BluetoothAdapter.STATE_BLE_ON; - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during bluetooth shutdown", ex); - bluetoothReadyForShutdown = true; - } - if (bluetoothReadyForShutdown) { - Log.i(TAG, "Bluetooth turned off."); - metricEnded(METRIC_BT); - shutdownTimingsTraceLog - .logDuration("ShutdownBt", TRON_METRICS.get(METRIC_BT)); - } - } if (!radioOff) { try { radioOff = !phone.needMobileRadioShutdown(); @@ -723,23 +666,9 @@ public final class ShutdownThread extends Thread { .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO)); } } - if (!nfcOff) { - try { - nfcOff = nfc.getState() == NfcAdapter.STATE_OFF; - } catch (RemoteException ex) { - Log.e(TAG, "RemoteException during NFC shutdown", ex); - nfcOff = true; - } - if (nfcOff) { - Log.i(TAG, "NFC turned off."); - metricEnded(METRIC_NFC); - shutdownTimingsTraceLog - .logDuration("ShutdownNfc", TRON_METRICS.get(METRIC_NFC)); - } - } - if (radioOff && bluetoothReadyForShutdown && nfcOff) { - Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete."); + if (radioOff) { + Log.i(TAG, "Radio shutdown complete."); done[0] = true; break; } @@ -756,7 +685,7 @@ public final class ShutdownThread extends Thread { } catch (InterruptedException ex) { } if (!done[0]) { - Log.w(TAG, "Timed out waiting for NFC, Radio and Bluetooth shutdown."); + Log.w(TAG, "Timed out waiting for Radio shutdown."); } } diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java index 7b1e12e24072..35b6ad3079a5 100644 --- a/services/core/java/com/android/server/vr/VrManagerInternal.java +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -59,13 +59,6 @@ public abstract class VrManagerInternal { int userId, int processId, @NonNull ComponentName calling); /** - * Set whether the system has acquired a sleep token. - * - * @param isAsleep is {@code true} if the device is asleep, or {@code false} otherwise. - */ - public abstract void onSleepStateChanged(boolean isAsleep); - - /** * Set whether the display used for VR output is on. * * @param isScreenOn is {@code true} if the display is on and can receive commands, @@ -74,13 +67,6 @@ public abstract class VrManagerInternal { public abstract void onScreenStateChanged(boolean isScreenOn); /** - * Set whether the keyguard is currently active/showing. - * - * @param isShowing is {@code true} if the keyguard is active/showing. - */ - public abstract void onKeyguardStateChanged(boolean isShowing); - - /** * Return NO_ERROR if the given package is installed on the device and enabled as a * VrListenerService for the given current user, or a negative error code indicating a failure. * diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index b0fd248b2b39..56cacf4e6aa1 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -19,6 +19,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.Manifest; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.INotificationManager; @@ -104,7 +105,8 @@ import java.util.Objects; * * @hide */ -public class VrManagerService extends SystemService implements EnabledComponentChangeListener{ +public class VrManagerService extends SystemService + implements EnabledComponentChangeListener, ScreenObserver { public static final String TAG = "VrManagerService"; static final boolean DBG = false; @@ -231,15 +233,17 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } - private void setSleepState(boolean isAsleep) { - setSystemState(FLAG_AWAKE, !isAsleep); - } - private void setScreenOn(boolean isScreenOn) { setSystemState(FLAG_SCREEN_ON, isScreenOn); } - private void setKeyguardShowing(boolean isShowing) { + @Override + public void onAwakeStateChanged(boolean isAwake) { + setSystemState(FLAG_AWAKE, isAwake); + } + + @Override + public void onKeyguardStateChanged(boolean isShowing) { setSystemState(FLAG_KEYGUARD_UNLOCKED, !isShowing); } @@ -675,21 +679,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @Override - public void onSleepStateChanged(boolean isAsleep) { - VrManagerService.this.setSleepState(isAsleep); - } - - @Override public void onScreenStateChanged(boolean isScreenOn) { VrManagerService.this.setScreenOn(isScreenOn); } @Override - public void onKeyguardStateChanged(boolean isShowing) { - VrManagerService.this.setKeyguardShowing(isShowing); - } - - @Override public boolean isCurrentVrListener(String packageName, int userId) { return VrManagerService.this.isCurrentVrListener(packageName, userId); } @@ -740,6 +734,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + LocalServices.getService(ActivityManagerInternal.class) + .registerScreenObserver(this); + mNotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); synchronized (mLock) { diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 31a1abb39461..7d9736ed3fe5 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -38,6 +38,7 @@ import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.PacketSocketAddress; @@ -56,7 +57,6 @@ import java.lang.Thread; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -247,7 +247,7 @@ public class ApfFilter { private final ApfCapabilities mApfCapabilities; private final IpClient.Callback mIpClientCallback; - private final NetworkInterface mNetworkInterface; + private final InterfaceParams mInterfaceParams; private final IpConnectivityLog mMetricsLog; @VisibleForTesting @@ -269,11 +269,11 @@ public class ApfFilter { private int mIPv4PrefixLength; @VisibleForTesting - ApfFilter(ApfConfiguration config, NetworkInterface networkInterface, + ApfFilter(ApfConfiguration config, InterfaceParams ifParams, IpClient.Callback ipClientCallback, IpConnectivityLog log) { mApfCapabilities = config.apfCapabilities; mIpClientCallback = ipClientCallback; - mNetworkInterface = networkInterface; + mInterfaceParams = ifParams; mMulticastFilter = config.multicastFilter; mDrop802_3Frames = config.ieee802_3Filter; @@ -287,7 +287,7 @@ public class ApfFilter { } private void log(String s) { - Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s); + Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); } @GuardedBy("this") @@ -332,14 +332,14 @@ public class ApfFilter { void maybeStartFilter() { FileDescriptor socket; try { - mHardwareAddress = mNetworkInterface.getHardwareAddress(); + mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); synchronized(this) { // Install basic filters installNewProgramLocked(); } socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, - mNetworkInterface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress( + (short) ETH_P_IPV6, mInterfaceParams.index); Os.bind(socket, addr); NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); } catch(SocketException|ErrnoException e) { @@ -1168,10 +1168,10 @@ public class ApfFilter { * filtering using APF programs. */ public static ApfFilter maybeCreate(ApfConfiguration config, - NetworkInterface networkInterface, IpClient.Callback ipClientCallback) { - if (config == null) return null; + InterfaceParams ifParams, IpClient.Callback ipClientCallback) { + if (config == null || ifParams == null) return null; ApfCapabilities apfCapabilities = config.apfCapabilities; - if (apfCapabilities == null || networkInterface == null) return null; + if (apfCapabilities == null) return null; if (apfCapabilities.apfVersionSupported == 0) return null; if (apfCapabilities.maximumApfProgramSize < 512) { Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); @@ -1186,7 +1186,7 @@ public class ApfFilter { Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); return null; } - return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog()); + return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog()); } public synchronized void shutdown() { diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index ed78175bd395..a956cefd1235 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -34,6 +34,7 @@ import android.net.TrafficStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpErrorEvent; +import android.net.util.InterfaceParams; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,7 +51,6 @@ import java.io.FileDescriptor; import java.io.IOException; import java.lang.Thread; import java.net.Inet4Address; -import java.net.NetworkInterface; import java.net.SocketException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -187,7 +187,8 @@ public class DhcpClient extends StateMachine { private final String mIfaceName; private boolean mRegisteredForPreDhcpNotification; - private NetworkInterface mIface; + private InterfaceParams mIface; + // TODO: MacAddress-ify more of this class hierarchy. private byte[] mHwAddr; private PacketSocketAddress mInterfaceBroadcastAddr; private int mTransactionId; @@ -221,8 +222,9 @@ public class DhcpClient extends StateMachine { return new WakeupMessage(mContext, getHandler(), cmdName, cmd); } + // TODO: Take an InterfaceParams instance instead of an interface name String. private DhcpClient(Context context, StateMachine controller, String iface) { - super(TAG); + super(TAG, controller.getHandler()); mContext = context; mController = controller; @@ -262,23 +264,23 @@ public class DhcpClient extends StateMachine { } public static DhcpClient makeDhcpClient( - Context context, StateMachine controller, String intf) { - DhcpClient client = new DhcpClient(context, controller, intf); + Context context, StateMachine controller, InterfaceParams ifParams) { + DhcpClient client = new DhcpClient(context, controller, ifParams.name); + client.mIface = ifParams; client.start(); return client; } private boolean initInterface() { - try { - mIface = NetworkInterface.getByName(mIfaceName); - mHwAddr = mIface.getHardwareAddress(); - mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(), - DhcpPacket.ETHER_BROADCAST); - return true; - } catch(SocketException | NullPointerException e) { - Log.e(TAG, "Can't determine ifindex or MAC address for " + mIfaceName, e); + if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName); + if (mIface == null) { + Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName); return false; } + + mHwAddr = mIface.macAddr.toByteArray(); + mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST); + return true; } private void startNewTransaction() { @@ -293,7 +295,7 @@ public class DhcpClient extends StateMachine { private boolean initPacketSocket() { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); - PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex()); + PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.index); Os.bind(mPacketSock, addr); NetworkUtils.attachDhcpFilter(mPacketSock); } catch(SocketException|ErrnoException e) { diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java index 6cf4fa9a3dfc..e6ddbbc95469 100644 --- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java +++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java @@ -21,6 +21,7 @@ import static android.system.OsConstants.*; import android.net.NetworkUtils; import android.net.util.PacketReader; import android.net.util.ConnectivityPacketSummary; +import android.net.util.InterfaceParams; import android.os.Handler; import android.system.ErrnoException; import android.system.Os; @@ -35,7 +36,6 @@ import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.io.IOException; -import java.net.NetworkInterface; import java.net.SocketException; @@ -69,24 +69,12 @@ public class ConnectivityPacketTracker { private boolean mRunning; private String mDisplayName; - public ConnectivityPacketTracker(Handler h, NetworkInterface netif, LocalLog log) { - final String ifname; - final int ifindex; - final byte[] hwaddr; - final int mtu; - - try { - ifname = netif.getName(); - ifindex = netif.getIndex(); - hwaddr = netif.getHardwareAddress(); - mtu = netif.getMTU(); - } catch (NullPointerException|SocketException e) { - throw new IllegalArgumentException("bad network interface", e); - } + public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) { + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); - mTag = TAG + "." + ifname; + mTag = TAG + "." + ifParams.name; mLog = log; - mPacketListener = new PacketListener(h, ifindex, hwaddr, mtu); + mPacketListener = new PacketListener(h, ifParams); } public void start(String displayName) { @@ -102,13 +90,11 @@ public class ConnectivityPacketTracker { } private final class PacketListener extends PacketReader { - private final int mIfIndex; - private final byte mHwAddr[]; + private final InterfaceParams mInterface; - PacketListener(Handler h, int ifindex, byte[] hwaddr, int mtu) { - super(h, mtu); - mIfIndex = ifindex; - mHwAddr = hwaddr; + PacketListener(Handler h, InterfaceParams ifParams) { + super(h, ifParams.defaultMtu); + mInterface = ifParams; } @Override @@ -117,7 +103,7 @@ public class ConnectivityPacketTracker { try { s = Os.socket(AF_PACKET, SOCK_RAW, 0); NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER); - Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mIfIndex)); + Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index)); } catch (ErrnoException | IOException e) { logError("Failed to create packet tracking socket: ", e); closeFd(s); @@ -129,7 +115,7 @@ public class ConnectivityPacketTracker { @Override protected void handlePacket(byte[] recvbuf, int length) { final String summary = ConnectivityPacketSummary.summarize( - mHwAddr, recvbuf, length); + mInterface.macAddr, recvbuf, length); if (summary == null) return; if (DBG) Log.d(mTag, summary); diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index fdb366c55a7b..d3a97b3851f4 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -35,6 +35,7 @@ import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.net.util.NetworkConstants; @@ -63,7 +64,6 @@ import java.io.PrintWriter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; @@ -556,7 +556,7 @@ public class IpClient extends StateMachine { private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final InterfaceController mInterfaceCtrl; - private NetworkInterface mNetworkInterface; + private InterfaceParams mInterfaceParams; /** * Non-final member variables accessed only from within our StateMachine. @@ -722,7 +722,12 @@ public class IpClient extends StateMachine { return; } - getNetworkInterface(); + mInterfaceParams = InterfaceParams.getByName(mInterfaceName); + if (mInterfaceParams == null) { + logError("Failed to find InterfaceParams for " + mInterfaceName); + // TODO: call doImmediateProvisioningFailure() with an error code + // indicating something like "interface not ready". + } mCallback.setNeighborDiscoveryOffload(true); sendMessage(CMD_START, new ProvisioningConfiguration(req)); @@ -858,7 +863,7 @@ public class IpClient extends StateMachine { protected String getLogRecString(Message msg) { final String logLine = String.format( "%s/%d %d %d %s [%s]", - mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(), + mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index, msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger); final String richerLogLine = getWhatToString(msg.what) + " " + logLine; @@ -889,15 +894,6 @@ public class IpClient extends StateMachine { mLog.log(msg); } - private void getNetworkInterface() { - try { - mNetworkInterface = NetworkInterface.getByName(mInterfaceName); - } catch (SocketException | NullPointerException e) { - // TODO: throw new IllegalStateException. - logError("Failed to get interface object: %s", e); - } - } - // This needs to be called with care to ensure that our LinkProperties // are in sync with the actual LinkProperties of the interface. For example, // we should only call this if we know for sure that there are no IP addresses @@ -1218,7 +1214,7 @@ public class IpClient extends StateMachine { } } else { // Start DHCPv4. - mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceName); + mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams); mDhcpClient.registerForPreDhcpNotification(); mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP); } @@ -1245,7 +1241,7 @@ public class IpClient extends StateMachine { try { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, - mInterfaceName, + mInterfaceParams, getHandler(), mLog, new IpReachabilityMonitor.Callback() { @@ -1447,7 +1443,7 @@ public class IpClient extends StateMachine { mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); apfConfig.ethTypeBlackList = mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList); - mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback); + mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. if (mApfFilter == null) { @@ -1515,7 +1511,7 @@ public class IpClient extends StateMachine { private ConnectivityPacketTracker createPacketTracker() { try { return new ConnectivityPacketTracker( - getHandler(), mNetworkInterface, mConnectivityPacketLog); + getHandler(), mInterfaceParams, mConnectivityPacketLog); } catch (IllegalArgumentException e) { return null; } diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java index 680733478657..fc07aa1ecd17 100644 --- a/services/net/java/android/net/ip/IpNeighborMonitor.java +++ b/services/net/java/android/net/ip/IpNeighborMonitor.java @@ -16,7 +16,11 @@ package android.net.ip; -import android.net.netlink.NetlinkConstants; +import static android.net.netlink.NetlinkConstants.hexify; +import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; +import static android.net.netlink.NetlinkConstants.stringForNlMsgType; + +import android.net.MacAddress; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; @@ -92,37 +96,35 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex; final InetAddress ip; final short nudState; - final byte[] linkLayerAddr; + final MacAddress macAddr; public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, - short nudState, byte[] linkLayerAddr) { + short nudState, MacAddress macAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; this.ip = ip; this.nudState = nudState; - this.linkLayerAddr = linkLayerAddr; + this.macAddr = macAddr; } boolean isConnected() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateConnected(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } boolean isValid() { - return (msgType != NetlinkConstants.RTM_DELNEIGH) && - StructNdMsg.isNudStateValid(nudState); + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } @Override public String toString() { final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); return j.add("@" + elapsedMs) - .add(NetlinkConstants.stringForNlMsgType(msgType)) + .add(stringForNlMsgType(msgType)) .add("if=" + ifindex) .add(ip.getHostAddress()) .add(StructNdMsg.stringForNudState(nudState)) - .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]") + .add("[" + macAddr + "]") .toString(); } } @@ -183,7 +185,7 @@ public class IpNeighborMonitor extends PacketReader { final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); if (nlMsg == null || nlMsg.getHeader() == null) { byteBuffer.position(position); - mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer)); + mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); break; } @@ -217,12 +219,13 @@ public class IpNeighborMonitor extends PacketReader { final int ifindex = ndMsg.ndm_ifindex; final InetAddress destination = neighMsg.getDestination(); final short nudState = - (msgType == NetlinkConstants.RTM_DELNEIGH) + (msgType == RTM_DELNEIGH) ? StructNdMsg.NUD_NONE : ndMsg.ndm_state; final NeighborEvent event = new NeighborEvent( - whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress()); + whenMs, msgType, ifindex, destination, nudState, + getMacAddress(neighMsg.getLinkLayerAddress())); if (VDBG) { Log.d(TAG, neighMsg.toString()); @@ -233,4 +236,16 @@ public class IpNeighborMonitor extends PacketReader { mConsumer.accept(event); } + + private static MacAddress getMacAddress(byte[] linkLayerAddress) { + if (linkLayerAddress != null) { + try { + return MacAddress.fromBytes(linkLayerAddress); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); + } + } + + return null; + } } diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index b31ffbba0279..7e02a2881da8 100644 --- a/services/net/java/android/net/ip/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -26,6 +26,7 @@ import android.net.ip.IpNeighborMonitor.NeighborEvent; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpReachabilityEvent; import android.net.netlink.StructNdMsg; +import android.net.util.InterfaceParams; import android.net.util.MultinetworkPolicyTracker; import android.net.util.SharedLog; import android.os.Handler; @@ -46,9 +47,7 @@ import java.io.PrintWriter; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.NetworkInterface; import java.net.SocketAddress; -import java.net.SocketException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -168,8 +167,7 @@ public class IpReachabilityMonitor { } } - private final String mInterfaceName; - private final int mInterfaceIndex; + private final InterfaceParams mInterfaceParams; private final IpNeighborMonitor mIpNeighborMonitor; private final SharedLog mLog; private final Callback mCallback; @@ -182,30 +180,25 @@ public class IpReachabilityMonitor { private volatile long mLastProbeTimeMs; public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback) { - this(context, ifName, h, log, callback, null); - } - - public IpReachabilityMonitor( - Context context, String ifName, Handler h, SharedLog log, Callback callback, + Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker) { - this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker, - Dependencies.makeDefault(context, ifName)); + this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name)); } @VisibleForTesting - IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback, + IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, MultinetworkPolicyTracker tracker, Dependencies dependencies) { - mInterfaceName = ifName; + if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); + + mInterfaceParams = ifParams; mLog = log.forSubComponent(TAG); mCallback = callback; mMultinetworkPolicyTracker = tracker; - mInterfaceIndex = ifIndex; mDependencies = dependencies; mIpNeighborMonitor = new IpNeighborMonitor(h, mLog, (NeighborEvent event) -> { - if (mInterfaceIndex != event.ifindex) return; + if (mInterfaceParams.index != event.ifindex) return; if (!mNeighborWatchList.containsKey(event.ip)) return; final NeighborEvent prev = mNeighborWatchList.put(event.ip, event); @@ -241,7 +234,7 @@ public class IpReachabilityMonitor { private String describeWatchList(String sep) { final StringBuilder sb = new StringBuilder(); - sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep); + sb.append("iface{" + mInterfaceParams + "}," + sep); sb.append("ntable=[" + sep); String delimiter = ""; for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) { @@ -262,10 +255,10 @@ public class IpReachabilityMonitor { } public void updateLinkProperties(LinkProperties lp) { - if (!mInterfaceName.equals(lp.getInterfaceName())) { + if (!mInterfaceParams.name.equals(lp.getInterfaceName())) { // TODO: figure out whether / how to cope with interface changes. Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() + - "' does not match: " + mInterfaceName); + "' does not match: " + mInterfaceParams.name); return; } @@ -353,10 +346,10 @@ public class IpReachabilityMonitor { mDependencies.acquireWakeLock(getProbeWakeLockDuration()); } - for (InetAddress target : ipProbeList) { - final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target); + for (InetAddress ip : ipProbeList) { + final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip); mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)", - target.getHostAddress(), rval)); + ip.getHostAddress(), rval)); logEvent(IpReachabilityEvent.PROBE, rval); } mLastProbeTimeMs = SystemClock.elapsedRealtime(); @@ -378,22 +371,9 @@ public class IpReachabilityMonitor { return (numUnicastProbes * retransTimeMs) + gracePeriodMs; } - private static int getInterfaceIndex(String ifname) { - final NetworkInterface iface; - try { - iface = NetworkInterface.getByName(ifname); - } catch (SocketException e) { - throw new IllegalArgumentException("invalid interface '" + ifname + "': ", e); - } - if (iface == null) { - throw new IllegalArgumentException("NetworkInterface was null for " + ifname); - } - return iface.getIndex(); - } - private void logEvent(int probeType, int errorCode) { int eventType = probeType | (errorCode & 0xff); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } private void logNudFailed(ProvisioningChange delta) { @@ -401,6 +381,6 @@ public class IpReachabilityMonitor { boolean isFromProbe = (duration < getProbeWakeLockDuration()); boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING); int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost); - mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType)); + mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType)); } } diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java index cb3123ce466a..49a1e79fd71e 100644 --- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java +++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java @@ -25,6 +25,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.TrafficStats; +import android.net.util.InterfaceParams; import android.system.ErrnoException; import android.system.Os; import android.system.StructGroupReq; @@ -96,9 +97,7 @@ public class RouterAdvertisementDaemon { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - private final String mIfName; - private final int mIfIndex; - private final byte[] mHwAddr; + private final InterfaceParams mInterface; private final InetSocketAddress mAllNodes; // This lock is to protect the RA from being updated while being @@ -223,11 +222,9 @@ public class RouterAdvertisementDaemon { } - public RouterAdvertisementDaemon(String ifname, int ifindex, byte[] hwaddr) { - mIfName = ifname; - mIfIndex = ifindex; - mHwAddr = hwaddr; - mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0); + public RouterAdvertisementDaemon(InterfaceParams ifParams) { + mInterface = ifParams; + mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0); mDeprecatedInfoTracker = new DeprecatedInfoTracker(); } @@ -279,7 +276,7 @@ public class RouterAdvertisementDaemon { try { putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute); - putSlla(ra, mHwAddr); + putSlla(ra, mInterface.macAddr.toByteArray()); mRaLength = ra.position(); // https://tools.ietf.org/html/rfc5175#section-4 says: @@ -579,9 +576,9 @@ public class RouterAdvertisementDaemon { // Setting SNDTIMEO is purely for defensive purposes. Os.setsockoptTimeval( mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS)); - Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName); + Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name); NetworkUtils.protectFromVpn(mSocket); - NetworkUtils.setupRaSocket(mSocket, mIfIndex); + NetworkUtils.setupRaSocket(mSocket, mInterface.index); } catch (ErrnoException | IOException e) { Log.e(TAG, "Failed to create RA daemon socket: " + e); return false; @@ -614,7 +611,7 @@ public class RouterAdvertisementDaemon { final InetAddress destip = dest.getAddress(); return (destip instanceof Inet6Address) && destip.isLinkLocalAddress() && - (((Inet6Address) destip).getScopeId() == mIfIndex); + (((Inet6Address) destip).getScopeId() == mInterface.index); } private void maybeSendRA(InetSocketAddress dest) { diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java index dae93afb6599..4951400eed84 100644 --- a/services/net/java/android/net/util/ConnectivityPacketSummary.java +++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java @@ -17,6 +17,7 @@ package android.net.util; import android.net.dhcp.DhcpPacket; +import android.net.MacAddress; import java.net.InetAddress; import java.net.UnknownHostException; @@ -45,21 +46,20 @@ public class ConnectivityPacketSummary { private final ByteBuffer mPacket; private final String mSummary; - public static String summarize(byte[] hwaddr, byte[] buffer) { + public static String summarize(MacAddress hwaddr, byte[] buffer) { return summarize(hwaddr, buffer, buffer.length); } // Methods called herein perform some but by no means all error checking. // They may throw runtime exceptions on malformed packets. - public static String summarize(byte[] hwaddr, byte[] buffer, int length) { - if ((hwaddr == null) || (hwaddr.length != ETHER_ADDR_LEN)) return null; - if (buffer == null) return null; + public static String summarize(MacAddress macAddr, byte[] buffer, int length) { + if ((macAddr == null) || (buffer == null)) return null; length = Math.min(length, buffer.length); - return (new ConnectivityPacketSummary(hwaddr, buffer, length)).toString(); + return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString(); } - private ConnectivityPacketSummary(byte[] hwaddr, byte[] buffer, int length) { - mHwAddr = hwaddr; + private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) { + mHwAddr = macAddr.toByteArray(); mBytes = buffer; mLength = Math.min(length, mBytes.length); mPacket = ByteBuffer.wrap(mBytes, 0, mLength); diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java new file mode 100644 index 000000000000..a4b2fbb6d963 --- /dev/null +++ b/services/net/java/android/net/util/InterfaceParams.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 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.util; + +import static android.net.MacAddress.ALL_ZEROS_ADDRESS; +import static android.net.util.NetworkConstants.ETHER_MTU; +import static android.net.util.NetworkConstants.IPV6_MIN_MTU; +import static com.android.internal.util.Preconditions.checkArgument; + +import android.net.MacAddress; +import android.text.TextUtils; + +import java.net.NetworkInterface; +import java.net.SocketException; + + +/** + * Encapsulate the interface parameters common to IpClient/IpServer components. + * + * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient + * and IpServer (sub)components need most or all of this information at some + * point during their lifecycles, so pass only this simplified object around + * which can be created once when IpClient/IpServer are told to start. + * + * @hide + */ +public class InterfaceParams { + public final String name; + public final int index; + public final MacAddress macAddr; + public final int defaultMtu; + + public static InterfaceParams getByName(String name) { + final NetworkInterface netif = getNetworkInterfaceByName(name); + if (netif == null) return null; + + // Not all interfaces have MAC addresses, e.g. rmnet_data0. + final MacAddress macAddr = getMacAddress(netif); + + try { + return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU()); + } catch (IllegalArgumentException|SocketException e) { + return null; + } + } + + public InterfaceParams(String name, int index, MacAddress macAddr) { + this(name, index, macAddr, ETHER_MTU); + } + + public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) { + checkArgument((!TextUtils.isEmpty(name)), "impossible interface name"); + checkArgument((index > 0), "invalid interface index"); + this.name = name; + this.index = index; + this.macAddr = (macAddr != null) ? macAddr : ALL_ZEROS_ADDRESS; + this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU; + } + + @Override + public String toString() { + return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu); + } + + private static NetworkInterface getNetworkInterfaceByName(String name) { + try { + return NetworkInterface.getByName(name); + } catch (NullPointerException|SocketException e) { + return null; + } + } + + private static MacAddress getMacAddress(NetworkInterface netif) { + try { + return MacAddress.fromBytes(netif.getHardwareAddress()); + } catch (IllegalArgumentException|NullPointerException|SocketException e) { + return null; + } + } +} diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index c66810097486..4a7072d03067 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -16,6 +16,9 @@ package com.android.server.usb; +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -26,6 +29,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; @@ -38,6 +42,7 @@ import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; import android.os.BatteryManager; +import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; @@ -60,6 +65,7 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.SomeArgs; import com.android.internal.util.IndentingPrintWriter; import com.android.server.FgThread; +import com.android.server.LocalServices; import java.io.File; import java.io.FileNotFoundException; @@ -75,7 +81,7 @@ import java.util.Set; /** * UsbDeviceManager manages USB state in device mode. */ -public class UsbDeviceManager { +public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver { private static final String TAG = "UsbDeviceManager"; private static final boolean DEBUG = false; @@ -97,6 +103,12 @@ public class UsbDeviceManager { private static final String USB_STATE_PROPERTY = "sys.usb.state"; /** + * The SharedPreference setting per user that stores the screen unlocked functions between + * sessions. + */ + private static final String UNLOCKED_CONFIG_PREF = "usb-screen-unlocked-config-%d"; + + /** * ro.bootmode value when phone boots into usual Android. */ private static final String NORMAL_BOOT = "normal"; @@ -128,6 +140,8 @@ public class UsbDeviceManager { private static final int MSG_UPDATE_CHARGING_STATE = 9; private static final int MSG_UPDATE_HOST_STATE = 10; private static final int MSG_LOCALE_CHANGED = 11; + private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12; + private static final int MSG_UPDATE_SCREEN_LOCK = 13; private static final int AUDIO_MODE_SOURCE = 1; @@ -169,6 +183,7 @@ public class UsbDeviceManager { private Intent mBroadcastedIntent; private boolean mPendingBootBroadcast; private static Set<Integer> sBlackListedInterfaces; + private SharedPreferences mSettings; static { sBlackListedInterfaces = new HashSet<>(); @@ -217,6 +232,31 @@ public class UsbDeviceManager { } }; + @Override + public void onKeyguardStateChanged(boolean isShowing) { + int userHandle = ActivityManager.getCurrentUser(); + boolean secure = mContext.getSystemService(KeyguardManager.class) + .isDeviceSecure(userHandle); + boolean unlocking = mContext.getSystemService(UserManager.class) + .isUserUnlockingOrUnlocked(userHandle); + if (DEBUG) { + Slog.v(TAG, "onKeyguardStateChanged: isShowing:" + isShowing + " secure:" + secure + + " unlocking:" + unlocking + " user:" + userHandle); + } + // We are unlocked when the keyguard is down or non-secure, and user storage is unlocked. + mHandler.sendMessage(MSG_UPDATE_SCREEN_LOCK, (isShowing && secure) || !unlocking); + } + + @Override + public void onAwakeStateChanged(boolean isAwake) { + // ignore + } + + /** Called when a user is unlocked. */ + public void onUnlockUser(int userHandle) { + onKeyguardStateChanged(false); + } + public UsbDeviceManager(Context context, UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) { mContext = context; @@ -303,6 +343,8 @@ public class UsbDeviceManager { public void systemReady() { if (DEBUG) Slog.d(TAG, "systemReady"); + LocalServices.getService(ActivityManagerInternal.class).registerScreenObserver(this); + mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -407,6 +449,14 @@ public class UsbDeviceManager { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } + private SharedPreferences getPinnedSharedPrefs(Context context) { + final File prefsFile = new File(new File( + Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL, + context.getUserId(), context.getPackageName()), "shared_prefs"), + UsbDeviceManager.class.getSimpleName() + ".xml"); + return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); + } + private final class UsbHandler extends Handler { // current USB state @@ -423,17 +473,21 @@ public class UsbDeviceManager { private UsbAccessory mCurrentAccessory; private int mUsbNotificationId; private boolean mAdbNotificationShown; - private int mCurrentUser = UserHandle.USER_NULL; + private int mCurrentUser; private boolean mUsbCharging; private String mCurrentOemFunctions; private boolean mHideUsbNotification; private boolean mSupportsAllCombinations; + private String mScreenUnlockedFunctions = UsbManager.USB_FUNCTION_NONE; + private boolean mScreenLocked; public UsbHandler(Looper looper) { super(looper); try { // Restore default functions. + mCurrentOemFunctions = SystemProperties.get(UsbDeviceManager.getPersistProp(false), + UsbManager.USB_FUNCTION_NONE); if (isNormalBoot()) { mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE); @@ -447,6 +501,9 @@ public class UsbDeviceManager { SystemProperties.get(USB_STATE_PROPERTY)); } + mCurrentUser = ActivityManager.getCurrentUser(); + mScreenLocked = true; + /* * Use the normal bootmode persistent prop to maintain state of adb across * all boot modes. @@ -651,7 +708,7 @@ public class UsbDeviceManager { private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { if (functions == null || applyAdbFunction(functions) .equals(UsbManager.USB_FUNCTION_NONE)) { - functions = getDefaultFunctions(); + functions = getChargingFunctions(); } functions = applyAdbFunction(functions); @@ -662,8 +719,7 @@ public class UsbDeviceManager { } if ((!functions.equals(oemFunctions) && - (mCurrentOemFunctions == null || - !mCurrentOemFunctions.equals(oemFunctions))) + !mCurrentOemFunctions.equals(oemFunctions)) || !mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied || forceRestart) { @@ -875,6 +931,14 @@ public class UsbDeviceManager { mMidiEnabled && mConfigured, mMidiCard, mMidiDevice); } + private void setScreenUnlockedFunctions() { + setEnabledFunctions(mScreenUnlockedFunctions, false, + UsbManager.containsFunction(mScreenUnlockedFunctions, + UsbManager.USB_FUNCTION_MTP) + || UsbManager.containsFunction(mScreenUnlockedFunctions, + UsbManager.USB_FUNCTION_PTP)); + } + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -894,7 +958,13 @@ public class UsbDeviceManager { if (mBootCompleted) { if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) { // restore defaults when USB is disconnected - setEnabledFunctions(null, !mAdbEnabled, false); + if (!mScreenLocked + && !UsbManager.USB_FUNCTION_NONE.equals( + mScreenUnlockedFunctions)) { + setScreenUnlockedFunctions(); + } else { + setEnabledFunctions(null, !mAdbEnabled, false); + } } updateUsbFunctions(); } else { @@ -977,6 +1047,47 @@ public class UsbDeviceManager { String functions = (String) msg.obj; setEnabledFunctions(functions, false, msg.arg1 == 1); break; + case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS: + mScreenUnlockedFunctions = (String) msg.obj; + SharedPreferences.Editor editor = mSettings.edit(); + editor.putString(String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, + mCurrentUser), mScreenUnlockedFunctions); + editor.commit(); + if (!mScreenLocked && !UsbManager.USB_FUNCTION_NONE.equals( + mScreenUnlockedFunctions)) { + // If the screen is unlocked, also set current functions. + setScreenUnlockedFunctions(); + } + break; + case MSG_UPDATE_SCREEN_LOCK: + if (msg.arg1 == 1 == mScreenLocked) { + break; + } + mScreenLocked = msg.arg1 == 1; + if (mSettings == null && !mScreenLocked) { + // Shared preferences aren't accessible until the user has been unlocked. + mSettings = getPinnedSharedPrefs(mContext); + mScreenUnlockedFunctions = mSettings.getString( + String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), + UsbManager.USB_FUNCTION_NONE); + } + if (!mBootCompleted) { + break; + } + if (mScreenLocked) { + if (!mConnected) { + setEnabledFunctions(null, false, false); + } + } else { + if (!UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions) + && (UsbManager.USB_FUNCTION_ADB.equals(mCurrentFunctions) + || (UsbManager.USB_FUNCTION_MTP.equals(mCurrentFunctions) + && !mUsbDataUnlocked))) { + // Set the screen unlocked functions if current function is charging. + setScreenUnlockedFunctions(); + } + } + break; case MSG_UPDATE_USER_RESTRICTIONS: // Restart the USB stack if USB transfer is enabled but no longer allowed. final boolean forceRestart = mUsbDataUnlocked @@ -1000,7 +1111,13 @@ public class UsbDeviceManager { updateUsbStateBroadcastIfNeeded(false); mPendingBootBroadcast = false; } - setEnabledFunctions(null, false, false); + + if (!mScreenLocked + && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) { + setScreenUnlockedFunctions(); + } else { + setEnabledFunctions(null, false, false); + } if (mCurrentAccessory != null) { getCurrentSettings().accessoryAttached(mCurrentAccessory); } @@ -1010,16 +1127,15 @@ public class UsbDeviceManager { break; case MSG_USER_SWITCHED: { if (mCurrentUser != msg.arg1) { - // Restart the USB stack and re-apply user restrictions for MTP or PTP. - if (mUsbDataUnlocked - && isUsbDataTransferActive() - && mCurrentUser != UserHandle.USER_NULL) { - Slog.v(TAG, "Current user switched to " + msg.arg1 - + "; resetting USB host stack for MTP or PTP"); - // avoid leaking sensitive data from previous user - setEnabledFunctions(null, true, false); + if (DEBUG) { + Slog.v(TAG, "Current user switched to " + msg.arg1); } mCurrentUser = msg.arg1; + mScreenLocked = true; + mScreenUnlockedFunctions = mSettings.getString( + String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), + UsbManager.USB_FUNCTION_NONE); + setEnabledFunctions(null, false, false); } break; } @@ -1071,20 +1187,12 @@ public class UsbDeviceManager { titleRes = com.android.internal.R.string.usb_unsupported_audio_accessory_title; id = SystemMessage.NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED; } else if (mConnected) { - if (!mUsbDataUnlocked) { - if (mSourcePower) { - titleRes = com.android.internal.R.string.usb_supplying_notification_title; - id = SystemMessage.NOTE_USB_SUPPLYING; - } else { - titleRes = com.android.internal.R.string.usb_charging_notification_title; - id = SystemMessage.NOTE_USB_CHARGING; - } - } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MTP)) { + if (UsbManager.containsFunction(mCurrentFunctions, + UsbManager.USB_FUNCTION_MTP) && mUsbDataUnlocked) { titleRes = com.android.internal.R.string.usb_mtp_notification_title; id = SystemMessage.NOTE_USB_MTP; } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_PTP)) { + UsbManager.USB_FUNCTION_PTP) && mUsbDataUnlocked) { titleRes = com.android.internal.R.string.usb_ptp_notification_title; id = SystemMessage.NOTE_USB_PTP; } else if (UsbManager.containsFunction(mCurrentFunctions, @@ -1235,7 +1343,7 @@ public class UsbDeviceManager { } } - private String getDefaultFunctions() { + private String getChargingFunctions() { String func = SystemProperties.get(getPersistProp(true), UsbManager.USB_FUNCTION_NONE); // if ADB is enabled, reset functions to ADB @@ -1252,6 +1360,8 @@ public class UsbDeviceManager { pw.println(" mCurrentFunctions: " + mCurrentFunctions); pw.println(" mCurrentOemFunctions: " + mCurrentOemFunctions); pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); + pw.println(" mScreenUnlockedFunctions: " + mScreenUnlockedFunctions); + pw.println(" mScreenLocked: " + mScreenLocked); pw.println(" mConnected: " + mConnected); pw.println(" mConfigured: " + mConfigured); pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); @@ -1308,6 +1418,17 @@ public class UsbDeviceManager { mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked); } + /** + * Sets the functions which are set when the screen is unlocked. + * @param functions Functions to set. + */ + public void setScreenUnlockedFunctions(String functions) { + if (DEBUG) { + Slog.d(TAG, "setScreenUnlockedFunctions(" + functions + ")"); + } + mHandler.sendMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, functions); + } + private void readOemUsbOverrideConfig() { String[] configList = mContext.getResources().getStringArray( com.android.internal.R.array.config_oemUsbModeOverride); diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index e4fcea77fa44..039597cf473a 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -87,6 +87,11 @@ public class UsbService extends IUsbManager.Stub { public void onStopUser(int userHandle) { mUsbService.onStopUser(UserHandle.of(userHandle)); } + + @Override + public void onUnlockUser(int userHandle) { + mUsbService.onUnlockUser(userHandle); + } } private static final String TAG = "UsbService"; @@ -205,6 +210,13 @@ public class UsbService extends IUsbManager.Stub { } } + /** Called when a user is unlocked. */ + public void onUnlockUser(int user) { + if (mDeviceManager != null) { + mDeviceManager.onUnlockUser(user); + } + } + /* Returns a list of all currently attached USB devices (host mdoe) */ @Override public void getDeviceList(Bundle devices) { @@ -389,6 +401,23 @@ public class UsbService extends IUsbManager.Stub { } } + @Override + public void setScreenUnlockedFunctions(String function) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + + if (!isSupportedCurrentFunction(function)) { + Slog.w(TAG, "Caller of setScreenUnlockedFunctions() requested unsupported USB function:" + + function); + function = UsbManager.USB_FUNCTION_NONE; + } + + if (mDeviceManager != null) { + mDeviceManager.setScreenUnlockedFunctions(function); + } else { + throw new IllegalStateException("USB device mode not supported"); + } + } + private static boolean isSupportedCurrentFunction(String function) { if (function == null) return true; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 20911012e6ba..8c7d6b30ecdc 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -1408,7 +1408,7 @@ public final class Call { * @param extras Bundle containing extra information associated with the event. */ public void sendCallEvent(String event, Bundle extras) { - mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras); + mInCallAdapter.sendCallEvent(mTelecomCallId, event, mTargetSdkVersion, extras); } /** diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 4fd602f7a856..e37aeb47f1a7 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -145,6 +145,8 @@ public abstract class ConnectionService extends Service { private static final String SESSION_STOP_RTT = "CS.-RTT"; private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR"; private static final String SESSION_HANDOVER_FAILED = "CS.haF"; + private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL"; + private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG"; private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1; private static final int MSG_CREATE_CONNECTION = 2; @@ -174,6 +176,8 @@ public abstract class ConnectionService extends Service { private static final int MSG_ON_STOP_RTT = 27; private static final int MSG_RTT_UPGRADE_RESPONSE = 28; private static final int MSG_CREATE_CONNECTION_COMPLETE = 29; + private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30; + private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31; private static final int MSG_HANDOVER_FAILED = 32; private static Connection sNullConnection; @@ -610,6 +614,26 @@ public abstract class ConnectionService extends Service { Log.endSession(); } } + + @Override + public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException { + Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_LOST); + try { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_LOST).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override + public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException { + Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_GAINED); + try { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_GAINED).sendToTarget(); + } finally { + Log.endSession(); + } + } }; private final Handler mHandler = new Handler(Looper.getMainLooper()) { @@ -1061,6 +1085,12 @@ public abstract class ConnectionService extends Service { } break; } + case MSG_CONNECTION_SERVICE_FOCUS_GAINED: + onConnectionServiceFocusGained(); + break; + case MSG_CONNECTION_SERVICE_FOCUS_LOST: + onConnectionServiceFocusLost(); + break; default: break; } @@ -1930,6 +1960,16 @@ public abstract class ConnectionService extends Service { } /** + * Call to inform Telecom that your {@link ConnectionService} has released call resources (e.g + * microphone, camera). + * + * @see ConnectionService#onConnectionServiceFocusLost() + */ + public final void connectionServiceFocusReleased() { + mAdapter.onConnectionServiceFocusReleased(); + } + + /** * Adds a connection created by the {@link ConnectionService} and informs telecom of the new * connection. * @@ -2179,6 +2219,20 @@ public abstract class ConnectionService extends Service { public void onRemoteExistingConnectionAdded(RemoteConnection connection) {} /** + * Called when the {@link ConnectionService} has lost the call focus. + * The {@link ConnectionService} should release the call resources and invokes + * {@link ConnectionService#connectionServiceFocusReleased()} to inform telecom that it has + * released the call resources. + */ + public void onConnectionServiceFocusLost() {} + + /** + * Called when the {@link ConnectionService} has gained the call focus. The + * {@link ConnectionService} can acquire the call resources at this time. + */ + public void onConnectionServiceFocusGained() {} + + /** * @hide */ public boolean containsConference(Conference conference) { diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java index 92a9dc2303c8..0d319bbc1d2a 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java @@ -628,4 +628,17 @@ final class ConnectionServiceAdapter implements DeathRecipient { } } } + + /** + * Notifies Telecom that the {@link ConnectionService} has released the call resource. + */ + void onConnectionServiceFocusReleased() { + for (IConnectionServiceAdapter adapter : mAdapters) { + try { + Log.d(this, "onConnectionServiceFocusReleased"); + adapter.onConnectionServiceFocusReleased(Log.getExternalSession()); + } catch (RemoteException ignored) { + } + } + } } diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java index 3fbdeb1effb0..3e1bf7790304 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java @@ -73,6 +73,7 @@ final class ConnectionServiceAdapterServant { private static final int MSG_ON_RTT_REMOTELY_TERMINATED = 32; private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33; private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34; + private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35; private final IConnectionServiceAdapter mDelegate; @@ -329,6 +330,9 @@ final class ConnectionServiceAdapterServant { } break; } + case MSG_CONNECTION_SERVICE_FOCUS_RELEASED: + mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/); + break; } } }; @@ -601,6 +605,11 @@ final class ConnectionServiceAdapterServant { args.arg2 = pHandle; mHandler.obtainMessage(MSG_SET_PHONE_ACCOUNT_CHANGED, args).sendToTarget(); } + + @Override + public void onConnectionServiceFocusReleased(Session.Info sessionInfo) { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_RELEASED).sendToTarget(); + } }; public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) { diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 4bc2a9b149f2..658685fe2907 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -286,11 +286,12 @@ public final class InCallAdapter { * * @param callId The callId to send the event for. * @param event The event. + * @param targetSdkVer Target sdk version of the app calling this api * @param extras Extras associated with the event. */ - public void sendCallEvent(String callId, String event, Bundle extras) { + public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) { try { - mAdapter.sendCallEvent(callId, event, extras); + mAdapter.sendCallEvent(callId, event, targetSdkVer, extras); } catch (RemoteException ignored) { } } diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 3361b5b6e777..83ca4702287d 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -340,24 +340,6 @@ public class Log { return sSessionManager; } - private static MessageDigest sMessageDigest; - - public static void initMd5Sum() { - new AsyncTask<Void, Void, Void>() { - @Override - public Void doInBackground(Void... args) { - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - md = null; - } - sMessageDigest = md; - return null; - } - }.execute(); - } - public static void setTag(String tag) { TAG = tag; DEBUG = isLoggable(android.util.Log.DEBUG); @@ -425,44 +407,13 @@ public class Log { /** * Redact personally identifiable information for production users. * If we are running in verbose mode, return the original string, - * and return "****" if we are running on the user build, otherwise - * return a SHA-1 hash of the input string. + * and return "***" otherwise. */ public static String pii(Object pii) { if (pii == null || VERBOSE) { return String.valueOf(pii); } - return "[" + secureHash(String.valueOf(pii).getBytes()) + "]"; - } - - private static String secureHash(byte[] input) { - // Refrain from logging user personal information in user build. - if (USER_BUILD) { - return "****"; - } - - if (sMessageDigest != null) { - sMessageDigest.reset(); - sMessageDigest.update(input); - byte[] result = sMessageDigest.digest(); - return encodeHex(result); - } else { - return "Uninitialized SHA1"; - } - } - - private static String encodeHex(byte[] bytes) { - StringBuffer hex = new StringBuffer(bytes.length * 2); - - for (int i = 0; i < bytes.length; i++) { - int byteIntValue = bytes[i] & 0xff; - if (byteIntValue < 0x10) { - hex.append("0"); - } - hex.append(Integer.toString(byteIntValue, 16)); - } - - return hex.toString(); + return "***"; } private static String getPrefixFromObject(Object obj) { diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 85906ad116be..59ce590858ee 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -213,6 +213,9 @@ final class RemoteConnectionService { } @Override + public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {} + + @Override public void addConferenceCall( final String callId, ParcelableConference parcel, Session.Info sessionInfo) { RemoteConference conference = new RemoteConference(callId, diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index e1247502fe86..96c6e0a5b743 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -236,6 +237,15 @@ public class TelecomManager { "android.telecom.extra.INCOMING_CALL_EXTRAS"; /** + * Optional extra for {@link #ACTION_INCOMING_CALL} containing a boolean to indicate that the + * call has an externally generated ringer. Used by the HfpClientConnectionService when In Band + * Ringtone is enabled to prevent two ringers from being generated. + * @hide + */ + public static final String EXTRA_CALL_EXTERNAL_RINGER = + "android.telecom.extra.CALL_EXTERNAL_RINGER"; + + /** * Optional extra for {@link android.content.Intent#ACTION_CALL} and * {@link android.content.Intent#ACTION_DIAL} {@code Intent} containing a {@link Bundle} * which contains metadata about the call. This {@link Bundle} will be saved into @@ -645,7 +655,6 @@ public class TelecomManager { mContext = context; } mTelecomServiceOverride = telecomServiceImpl; - android.telecom.Log.initMd5Sum(); } /** @@ -1424,6 +1433,13 @@ public class TelecomManager { public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { try { if (isServiceConnected()) { + if (extras != null && extras.getBoolean(EXTRA_IS_HANDOVER) && + mContext.getApplicationContext().getApplicationInfo().targetSdkVersion > + Build.VERSION_CODES.O_MR1) { + Log.e("TAG", "addNewIncomingCall failed. Use public api " + + "acceptHandover for API > O-MR1"); + // TODO add "return" after DUO team adds support for new handover API + } getTelecomService().addNewIncomingCall( phoneAccount, extras == null ? new Bundle() : extras); } diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl index 732d00d9eb85..02e1ff818066 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl @@ -103,4 +103,8 @@ oneway interface IConnectionService { void handoverFailed(String callId, in ConnectionRequest request, int error, in Session.Info sessionInfo); + + void connectionServiceFocusLost(in Session.Info sessionInfo); + + void connectionServiceFocusGained(in Session.Info sessionInfo); } diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl index da2015f6b99b..be474bd467ca 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl @@ -119,4 +119,6 @@ oneway interface IConnectionServiceAdapter { void onPhoneAccountChanged(String callId, in PhoneAccountHandle pHandle, in Session.Info sessionInfo); + + void onConnectionServiceFocusReleased(in Session.Info sessionInfo); } diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 23ac940edfa8..87ccd3ed4369 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -64,7 +64,7 @@ oneway interface IInCallAdapter { void pullExternalCall(String callId); - void sendCallEvent(String callId, String event, in Bundle extras); + void sendCallEvent(String callId, String event, int targetSdkVer, in Bundle extras); void putExtras(String callId, in Bundle extras); diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index 5f5dd82eed61..fc814be1b464 100644 --- a/telephony/java/android/telephony/RadioNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -17,23 +17,23 @@ package android.telephony; /** - * Contains radio access network related constants. + * Contains access network related constants. */ -public final class RadioNetworkConstants { +public final class AccessNetworkConstants { - public static final class RadioAccessNetworks { + public static final class AccessNetworkType { public static final int GERAN = 1; public static final int UTRAN = 2; public static final int EUTRAN = 3; - /** @hide */ public static final int CDMA2000 = 4; + public static final int IWLAN = 5; } /** * Frenquency bands for GERAN. * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf */ - public static final class GeranBands { + public static final class GeranBand { public static final int BAND_T380 = 1; public static final int BAND_T410 = 2; public static final int BAND_450 = 3; @@ -54,7 +54,7 @@ public final class RadioNetworkConstants { * Frenquency bands for UTRAN. * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf */ - public static final class UtranBands { + public static final class UtranBand { public static final int BAND_1 = 1; public static final int BAND_2 = 2; public static final int BAND_3 = 3; @@ -83,7 +83,7 @@ public final class RadioNetworkConstants { * Frenquency bands for EUTRAN. * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf */ - public static final class EutranBands { + public static final class EutranBand { public static final int BAND_1 = 1; public static final int BAND_2 = 2; public static final int BAND_3 = 3; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0a8d9cb4197a..0c05a025dd45 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -950,8 +950,9 @@ public class CarrierConfigManager { public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool"; /** - * String to identify carrier name in CarrierConfig app. This string is used only if - * #KEY_CARRIER_NAME_OVERRIDE_BOOL is true + * String to identify carrier name in CarrierConfig app. This string overrides SPN if + * #KEY_CARRIER_NAME_OVERRIDE_BOOL is true; otherwise, it will be used if its value is provided + * and SPN is unavailable * @hide */ public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string"; @@ -1006,6 +1007,13 @@ public class CarrierConfigManager { public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool"; + /** + * Boolean to decide whether to show precise call failed cause to user + * @hide + */ + public static final String KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL = + "show_precise_failed_cause_bool"; + // These variables are used by the MMS service and exposed through another API, {@link // SmsManager}. The variable names and string values are copied from there. public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled"; @@ -2012,6 +2020,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false); sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null); sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false); + sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false); sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false); diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/android/telephony/CellIdentity.aidl index d750363b9cd2..aeee769edab2 100644 --- a/telephony/java/android/telephony/data/InterfaceAddress.aidl +++ b/telephony/java/android/telephony/CellIdentity.aidl @@ -15,6 +15,6 @@ */ /** @hide */ -package android.telephony.data; +package android.telephony; -parcelable InterfaceAddress; +parcelable CellIdentity; diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java new file mode 100644 index 000000000000..e092d52d91bc --- /dev/null +++ b/telephony/java/android/telephony/CellIdentity.java @@ -0,0 +1,173 @@ +/* + * Copyright 2017 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.CallSuper; +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * CellIdentity represents the identity of a unique cell. This is the base class for + * CellIdentityXxx which represents cell identity for specific network access technology. + */ +public abstract class CellIdentity implements Parcelable { + /** + * Cell identity type + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "TYPE_", value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA}) + public @interface Type {} + + /** + * Unknown cell identity type + * @hide + */ + public static final int TYPE_UNKNOWN = 0; + /** + * GSM cell identity type + * @hide + */ + public static final int TYPE_GSM = 1; + /** + * CDMA cell identity type + * @hide + */ + public static final int TYPE_CDMA = 2; + /** + * LTE cell identity type + * @hide + */ + public static final int TYPE_LTE = 3; + /** + * WCDMA cell identity type + * @hide + */ + public static final int TYPE_WCDMA = 4; + /** + * TDS-CDMA cell identity type + * @hide + */ + public static final int TYPE_TDSCDMA = 5; + + // Log tag + /** @hide */ + protected final String mTag; + // Cell identity type + /** @hide */ + protected final int mType; + // 3-digit Mobile Country Code in string format. Null for CDMA cell identity. + /** @hide */ + protected final String mMccStr; + // 2 or 3-digit Mobile Network Code in string format. Null for CDMA cell identity. + /** @hide */ + protected final String mMncStr; + + /** @hide */ + protected CellIdentity(String tag, int type, String mcc, String mnc) { + mTag = tag; + mType = type; + + // Only allow INT_MAX if unknown string mcc/mnc + if (mcc == null || mcc.matches("^[0-9]{3}$")) { + mMccStr = mcc; + } else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) { + // If the mccStr is empty or unknown, set it as null. + mMccStr = null; + } else { + // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format + // after the bug got fixed. + mMccStr = null; + log("invalid MCC format: " + mcc); + } + + if (mnc == null || mnc.matches("^[0-9]{2,3}$")) { + mMncStr = mnc; + } else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) { + // If the mncStr is empty or unknown, set it as null. + mMncStr = null; + } else { + // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format + // after the bug got fixed. + mMncStr = null; + log("invalid MNC format: " + mnc); + } + } + + /** Implement the Parcelable interface */ + @Override + public int describeContents() { + return 0; + } + + /** + * @hide + * @return The type of the cell identity + */ + public @Type int getType() { return mType; } + + /** + * Used by child classes for parceling. + * + * @hide + */ + @CallSuper + public void writeToParcel(Parcel dest, int type) { + dest.writeInt(type); + dest.writeString(mMccStr); + dest.writeString(mMncStr); + } + + /** + * Construct from Parcel + * @hide + */ + protected CellIdentity(String tag, int type, Parcel source) { + this(tag, type, source.readString(), source.readString()); + } + + /** Implement the Parcelable interface */ + public static final Creator<CellIdentity> CREATOR = + new Creator<CellIdentity>() { + @Override + public CellIdentity createFromParcel(Parcel in) { + int type = in.readInt(); + switch (type) { + case TYPE_GSM: return CellIdentityGsm.createFromParcelBody(in); + case TYPE_WCDMA: return CellIdentityWcdma.createFromParcelBody(in); + case TYPE_CDMA: return CellIdentityCdma.createFromParcelBody(in); + case TYPE_LTE: return CellIdentityLte.createFromParcelBody(in); + case TYPE_TDSCDMA: return CellIdentityTdscdma.createFromParcelBody(in); + default: throw new IllegalArgumentException("Bad Cell identity Parcel"); + } + } + + @Override + public CellIdentity[] newArray(int size) { + return new CellIdentity[size]; + } + }; + + /** @hide */ + protected void log(String s) { + Rlog.w(mTag, s); + } +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index ddc938e64841..2e1d1dc343cd 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -17,8 +17,6 @@ package android.telephony; import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.Rlog; import android.text.TextUtils; import java.util.Objects; @@ -26,9 +24,8 @@ import java.util.Objects; /** * CellIdentity is to represent a unique CDMA cell */ -public final class CellIdentityCdma implements Parcelable { - - private static final String LOG_TAG = "CellSignalStrengthCdma"; +public final class CellIdentityCdma extends CellIdentity { + private static final String TAG = CellIdentityCdma.class.getSimpleName(); private static final boolean DBG = false; // Network Id 0..65535 @@ -60,6 +57,7 @@ public final class CellIdentityCdma implements Parcelable { * @hide */ public CellIdentityCdma() { + super(TAG, TYPE_CDMA, null, null); mNetworkId = Integer.MAX_VALUE; mSystemId = Integer.MAX_VALUE; mBasestationId = Integer.MAX_VALUE; @@ -81,7 +79,7 @@ public final class CellIdentityCdma implements Parcelable { * * @hide */ - public CellIdentityCdma (int nid, int sid, int bid, int lon, int lat) { + public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat) { this(nid, sid, bid, lon, lat, null, null); } @@ -99,8 +97,9 @@ public final class CellIdentityCdma implements Parcelable { * * @hide */ - public CellIdentityCdma (int nid, int sid, int bid, int lon, int lat, String alphal, + public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) { + super(TAG, TYPE_CDMA, null, null); mNetworkId = nid; mSystemId = sid; mBasestationId = bid; @@ -196,40 +195,33 @@ public final class CellIdentityCdma implements Parcelable { CellIdentityCdma o = (CellIdentityCdma) other; - return mNetworkId == o.mNetworkId && - mSystemId == o.mSystemId && - mBasestationId == o.mBasestationId && - mLatitude == o.mLatitude && - mLongitude == o.mLongitude && - TextUtils.equals(mAlphaLong, o.mAlphaLong) && - TextUtils.equals(mAlphaShort, o.mAlphaShort); + return mNetworkId == o.mNetworkId + && mSystemId == o.mSystemId + && mBasestationId == o.mBasestationId + && mLatitude == o.mLatitude + && mLongitude == o.mLongitude + && TextUtils.equals(mAlphaLong, o.mAlphaLong) + && TextUtils.equals(mAlphaShort, o.mAlphaShort); } @Override public String toString() { - StringBuilder sb = new StringBuilder("CellIdentityCdma:{"); - sb.append(" mNetworkId="); sb.append(mNetworkId); - sb.append(" mSystemId="); sb.append(mSystemId); - sb.append(" mBasestationId="); sb.append(mBasestationId); - sb.append(" mLongitude="); sb.append(mLongitude); - sb.append(" mLatitude="); sb.append(mLatitude); - sb.append(" mAlphaLong="); sb.append(mAlphaLong); - sb.append(" mAlphaShort="); sb.append(mAlphaShort); - sb.append("}"); - - return sb.toString(); - } - - /** Implement the Parcelable interface */ - @Override - public int describeContents() { - return 0; + return new StringBuilder(TAG) + .append(":{ mNetworkId=").append(mNetworkId) + .append(" mSystemId=").append(mSystemId) + .append(" mBasestationId=").append(mBasestationId) + .append(" mLongitude=").append(mLongitude) + .append(" mLatitude=").append(mLatitude) + .append(" mAlphaLong=").append(mAlphaLong) + .append(" mAlphaShort=").append(mAlphaShort) + .append("}").toString(); } /** Implement the Parcelable interface */ @Override public void writeToParcel(Parcel dest, int flags) { if (DBG) log("writeToParcel(Parcel, int): " + toString()); + super.writeToParcel(dest, TYPE_CDMA); dest.writeInt(mNetworkId); dest.writeInt(mSystemId); dest.writeInt(mBasestationId); @@ -241,10 +233,16 @@ public final class CellIdentityCdma implements Parcelable { /** Construct from Parcel, type has already been processed */ private CellIdentityCdma(Parcel in) { - this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readInt(), - in.readString(), in.readString()); - - if (DBG) log("CellIdentityCdma(Parcel): " + toString()); + super(TAG, TYPE_CDMA, in); + mNetworkId = in.readInt(); + mSystemId = in.readInt(); + mBasestationId = in.readInt(); + mLongitude = in.readInt(); + mLatitude = in.readInt(); + mAlphaLong = in.readString(); + mAlphaShort = in.readString(); + + if (DBG) log(toString()); } /** Implement the Parcelable interface */ @@ -253,7 +251,8 @@ public final class CellIdentityCdma implements Parcelable { new Creator<CellIdentityCdma>() { @Override public CellIdentityCdma createFromParcel(Parcel in) { - return new CellIdentityCdma(in); + in.readInt(); // skip + return createFromParcelBody(in); } @Override @@ -262,10 +261,8 @@ public final class CellIdentityCdma implements Parcelable { } }; - /** - * log - */ - private static void log(String s) { - Rlog.w(LOG_TAG, s); + /** @hide */ + protected static CellIdentityCdma createFromParcelBody(Parcel in) { + return new CellIdentityCdma(in); } } diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 376e6aa77155..f948f812676f 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -17,8 +17,6 @@ package android.telephony; import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.Rlog; import android.text.TextUtils; import java.util.Objects; @@ -26,9 +24,8 @@ import java.util.Objects; /** * CellIdentity to represent a unique GSM cell */ -public final class CellIdentityGsm implements Parcelable { - - private static final String LOG_TAG = "CellIdentityGsm"; +public final class CellIdentityGsm extends CellIdentity { + private static final String TAG = CellIdentityGsm.class.getSimpleName(); private static final boolean DBG = false; // 16-bit Location Area Code, 0..65535 @@ -39,10 +36,6 @@ public final class CellIdentityGsm implements Parcelable { private final int mArfcn; // 6-bit Base Station Identity Code private final int mBsic; - // 3-digit Mobile Country Code in string format - private final String mMccStr; - // 2 or 3-digit Mobile Network Code in string format - private final String mMncStr; // long alpha Operator Name String or Enhanced Operator Name String private final String mAlphaLong; // short alpha Operator Name String or Enhanced Operator Name String @@ -52,12 +45,11 @@ public final class CellIdentityGsm implements Parcelable { * @hide */ public CellIdentityGsm() { + super(TAG, TYPE_GSM, null, null); mLac = Integer.MAX_VALUE; mCid = Integer.MAX_VALUE; mArfcn = Integer.MAX_VALUE; mBsic = Integer.MAX_VALUE; - mMccStr = null; - mMncStr = null; mAlphaLong = null; mAlphaShort = null; } @@ -70,7 +62,7 @@ public final class CellIdentityGsm implements Parcelable { * * @hide */ - public CellIdentityGsm (int mcc, int mnc, int lac, int cid) { + public CellIdentityGsm(int mcc, int mnc, int lac, int cid) { this(lac, cid, Integer.MAX_VALUE, Integer.MAX_VALUE, String.valueOf(mcc), String.valueOf(mnc), null, null); } @@ -86,7 +78,7 @@ public final class CellIdentityGsm implements Parcelable { * * @hide */ - public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int arfcn, int bsic) { + public CellIdentityGsm(int mcc, int mnc, int lac, int cid, int arfcn, int bsic) { this(lac, cid, arfcn, bsic, String.valueOf(mcc), String.valueOf(mnc), null, null); } @@ -103,8 +95,9 @@ public final class CellIdentityGsm implements Parcelable { * * @hide */ - public CellIdentityGsm (int lac, int cid, int arfcn, int bsic, String mccStr, + public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr, String mncStr, String alphal, String alphas) { + super(TAG, TYPE_GSM, mccStr, mncStr); mLac = lac; mCid = cid; mArfcn = arfcn; @@ -112,31 +105,6 @@ public final class CellIdentityGsm implements Parcelable { // for inbound parcels mBsic = (bsic == 0xFF) ? Integer.MAX_VALUE : bsic; - // Only allow INT_MAX if unknown string mcc/mnc - if (mccStr == null || mccStr.matches("^[0-9]{3}$")) { - mMccStr = mccStr; - } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mccStr is empty or unknown, set it as null. - mMccStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format - // after the bug got fixed. - mMccStr = null; - log("invalid MCC format: " + mccStr); - } - - if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) { - mMncStr = mncStr; - } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mncStr is empty or unknown, set it as null. - mMncStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format - // after the bug got fixed. - mMncStr = null; - log("invalid MNC format: " + mncStr); - } - mAlphaLong = alphal; mAlphaShort = alphas; } @@ -237,6 +205,7 @@ public final class CellIdentityGsm implements Parcelable { /** + * @deprecated Primary Scrambling Code is not applicable to GSM. * @return Integer.MAX_VALUE, undefined for GSM */ @Deprecated @@ -260,58 +229,54 @@ public final class CellIdentityGsm implements Parcelable { } CellIdentityGsm o = (CellIdentityGsm) other; - return mLac == o.mLac && - mCid == o.mCid && - mArfcn == o.mArfcn && - mBsic == o.mBsic && - TextUtils.equals(mMccStr, o.mMccStr) && - TextUtils.equals(mMncStr, o.mMncStr) && - TextUtils.equals(mAlphaLong, o.mAlphaLong) && - TextUtils.equals(mAlphaShort, o.mAlphaShort); + return mLac == o.mLac + && mCid == o.mCid + && mArfcn == o.mArfcn + && mBsic == o.mBsic + && TextUtils.equals(mMccStr, o.mMccStr) + && TextUtils.equals(mMncStr, o.mMncStr) + && TextUtils.equals(mAlphaLong, o.mAlphaLong) + && TextUtils.equals(mAlphaShort, o.mAlphaShort); } @Override public String toString() { - StringBuilder sb = new StringBuilder("CellIdentityGsm:{"); - sb.append(" mLac=").append(mLac); - sb.append(" mCid=").append(mCid); - sb.append(" mArfcn=").append(mArfcn); - sb.append(" mBsic=").append("0x").append(Integer.toHexString(mBsic)); - sb.append(" mMcc=").append(mMccStr); - sb.append(" mMnc=").append(mMncStr); - sb.append(" mAlphaLong=").append(mAlphaLong); - sb.append(" mAlphaShort=").append(mAlphaShort); - sb.append("}"); - - return sb.toString(); - } - - /** Implement the Parcelable interface */ - @Override - public int describeContents() { - return 0; + return new StringBuilder(TAG) + .append(":{ mLac=").append(mLac) + .append(" mCid=").append(mCid) + .append(" mArfcn=").append(mArfcn) + .append(" mBsic=").append("0x").append(Integer.toHexString(mBsic)) + .append(" mMcc=").append(mMccStr) + .append(" mMnc=").append(mMncStr) + .append(" mAlphaLong=").append(mAlphaLong) + .append(" mAlphaShort=").append(mAlphaShort) + .append("}").toString(); } /** Implement the Parcelable interface */ @Override public void writeToParcel(Parcel dest, int flags) { if (DBG) log("writeToParcel(Parcel, int): " + toString()); + super.writeToParcel(dest, TYPE_GSM); dest.writeInt(mLac); dest.writeInt(mCid); dest.writeInt(mArfcn); dest.writeInt(mBsic); - dest.writeString(mMccStr); - dest.writeString(mMncStr); dest.writeString(mAlphaLong); dest.writeString(mAlphaShort); } /** Construct from Parcel, type has already been processed */ private CellIdentityGsm(Parcel in) { - this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(), - in.readString(), in.readString(), in.readString()); - - if (DBG) log("CellIdentityGsm(Parcel): " + toString()); + super(TAG, TYPE_GSM, in); + mLac = in.readInt(); + mCid = in.readInt(); + mArfcn = in.readInt(); + mBsic = in.readInt(); + mAlphaLong = in.readString(); + mAlphaShort = in.readString(); + + if (DBG) log(toString()); } /** Implement the Parcelable interface */ @@ -320,7 +285,8 @@ public final class CellIdentityGsm implements Parcelable { new Creator<CellIdentityGsm>() { @Override public CellIdentityGsm createFromParcel(Parcel in) { - return new CellIdentityGsm(in); + in.readInt(); // skip + return createFromParcelBody(in); } @Override @@ -329,10 +295,8 @@ public final class CellIdentityGsm implements Parcelable { } }; - /** - * log - */ - private static void log(String s) { - Rlog.w(LOG_TAG, s); + /** @hide */ + protected static CellIdentityGsm createFromParcelBody(Parcel in) { + return new CellIdentityGsm(in); } -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 6ca5daf63375..7f20c8ae5f45 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -17,8 +17,6 @@ package android.telephony; import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.Rlog; import android.text.TextUtils; import java.util.Objects; @@ -26,9 +24,8 @@ import java.util.Objects; /** * CellIdentity is to represent a unique LTE cell */ -public final class CellIdentityLte implements Parcelable { - - private static final String LOG_TAG = "CellIdentityLte"; +public final class CellIdentityLte extends CellIdentity { + private static final String TAG = CellIdentityLte.class.getSimpleName(); private static final boolean DBG = false; // 28-bit cell identity @@ -39,10 +36,6 @@ public final class CellIdentityLte implements Parcelable { private final int mTac; // 18-bit Absolute RF Channel Number private final int mEarfcn; - // 3-digit Mobile Country Code in string format - private final String mMccStr; - // 2 or 3-digit Mobile Network Code in string format - private final String mMncStr; // long alpha Operator Name String or Enhanced Operator Name String private final String mAlphaLong; // short alpha Operator Name String or Enhanced Operator Name String @@ -52,12 +45,11 @@ public final class CellIdentityLte implements Parcelable { * @hide */ public CellIdentityLte() { + super(TAG, TYPE_LTE, null, null); mCi = Integer.MAX_VALUE; mPci = Integer.MAX_VALUE; mTac = Integer.MAX_VALUE; mEarfcn = Integer.MAX_VALUE; - mMccStr = null; - mMncStr = null; mAlphaLong = null; mAlphaShort = null; } @@ -72,7 +64,7 @@ public final class CellIdentityLte implements Parcelable { * * @hide */ - public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac) { + public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) { this(ci, pci, tac, Integer.MAX_VALUE, String.valueOf(mcc), String.valueOf(mnc), null, null); } @@ -87,7 +79,7 @@ public final class CellIdentityLte implements Parcelable { * * @hide */ - public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac, int earfcn) { + public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac, int earfcn) { this(ci, pci, tac, earfcn, String.valueOf(mcc), String.valueOf(mnc), null, null); } @@ -104,38 +96,13 @@ public final class CellIdentityLte implements Parcelable { * * @hide */ - public CellIdentityLte (int ci, int pci, int tac, int earfcn, String mccStr, + public CellIdentityLte(int ci, int pci, int tac, int earfcn, String mccStr, String mncStr, String alphal, String alphas) { + super(TAG, TYPE_LTE, mccStr, mncStr); mCi = ci; mPci = pci; mTac = tac; mEarfcn = earfcn; - - // Only allow INT_MAX if unknown string mcc/mnc - if (mccStr == null || mccStr.matches("^[0-9]{3}$")) { - mMccStr = mccStr; - } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mccStr is empty or unknown, set it as null. - mMccStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format - // after the bug got fixed. - mMccStr = null; - log("invalid MCC format: " + mccStr); - } - - if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) { - mMncStr = mncStr; - } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mncStr is empty or unknown, set it as null. - mMncStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format - // after the bug got fixed. - mMncStr = null; - log("invalid MNC format: " + mncStr); - } - mAlphaLong = alphal; mAlphaShort = alphas; } @@ -248,58 +215,54 @@ public final class CellIdentityLte implements Parcelable { } CellIdentityLte o = (CellIdentityLte) other; - return mCi == o.mCi && - mPci == o.mPci && - mTac == o.mTac && - mEarfcn == o.mEarfcn && - TextUtils.equals(mMccStr, o.mMccStr) && - TextUtils.equals(mMncStr, o.mMncStr) && - TextUtils.equals(mAlphaLong, o.mAlphaLong) && - TextUtils.equals(mAlphaShort, o.mAlphaShort); + return mCi == o.mCi + && mPci == o.mPci + && mTac == o.mTac + && mEarfcn == o.mEarfcn + && TextUtils.equals(mMccStr, o.mMccStr) + && TextUtils.equals(mMncStr, o.mMncStr) + && TextUtils.equals(mAlphaLong, o.mAlphaLong) + && TextUtils.equals(mAlphaShort, o.mAlphaShort); } @Override public String toString() { - StringBuilder sb = new StringBuilder("CellIdentityLte:{"); - sb.append(" mCi="); sb.append(mCi); - sb.append(" mPci="); sb.append(mPci); - sb.append(" mTac="); sb.append(mTac); - sb.append(" mEarfcn="); sb.append(mEarfcn); - sb.append(" mMcc="); sb.append(mMccStr); - sb.append(" mMnc="); sb.append(mMncStr); - sb.append(" mAlphaLong="); sb.append(mAlphaLong); - sb.append(" mAlphaShort="); sb.append(mAlphaShort); - sb.append("}"); - - return sb.toString(); - } - - /** Implement the Parcelable interface */ - @Override - public int describeContents() { - return 0; + return new StringBuilder(TAG) + .append(":{ mCi=").append(mCi) + .append(" mPci=").append(mPci) + .append(" mTac=").append(mTac) + .append(" mEarfcn=").append(mEarfcn) + .append(" mMcc=").append(mMccStr) + .append(" mMnc=").append(mMncStr) + .append(" mAlphaLong=").append(mAlphaLong) + .append(" mAlphaShort=").append(mAlphaShort) + .append("}").toString(); } /** Implement the Parcelable interface */ @Override public void writeToParcel(Parcel dest, int flags) { if (DBG) log("writeToParcel(Parcel, int): " + toString()); + super.writeToParcel(dest, TYPE_LTE); dest.writeInt(mCi); dest.writeInt(mPci); dest.writeInt(mTac); dest.writeInt(mEarfcn); - dest.writeString(mMccStr); - dest.writeString(mMncStr); dest.writeString(mAlphaLong); dest.writeString(mAlphaShort); } /** Construct from Parcel, type has already been processed */ private CellIdentityLte(Parcel in) { - this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(), - in.readString(), in.readString(), in.readString()); - - if (DBG) log("CellIdentityLte(Parcel): " + toString()); + super(TAG, TYPE_LTE, in); + mCi = in.readInt(); + mPci = in.readInt(); + mTac = in.readInt(); + mEarfcn = in.readInt(); + mAlphaLong = in.readString(); + mAlphaShort = in.readString(); + + if (DBG) log(toString()); } /** Implement the Parcelable interface */ @@ -308,7 +271,8 @@ public final class CellIdentityLte implements Parcelable { new Creator<CellIdentityLte>() { @Override public CellIdentityLte createFromParcel(Parcel in) { - return new CellIdentityLte(in); + in.readInt(); // skip; + return createFromParcelBody(in); } @Override @@ -317,10 +281,8 @@ public final class CellIdentityLte implements Parcelable { } }; - /** - * log - */ - private static void log(String s) { - Rlog.w(LOG_TAG, s); + /** @hide */ + protected static CellIdentityLte createFromParcelBody(Parcel in) { + return new CellIdentityLte(in); } -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.aidl b/telephony/java/android/telephony/CellIdentityTdscdma.aidl new file mode 100644 index 000000000000..2a182cdfe176 --- /dev/null +++ b/telephony/java/android/telephony/CellIdentityTdscdma.aidl @@ -0,0 +1,20 @@ +/* + * Copyright 2017 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. + */ + +/** @hide */ +package android.telephony; + +parcelable CellIdentityTdscdma; diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java new file mode 100644 index 000000000000..001d19f777fd --- /dev/null +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -0,0 +1,196 @@ +/* + * Copyright 2017 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.os.Parcel; +import android.text.TextUtils; + +import java.util.Objects; + +/** + * CellIdentity is to represent a unique TD-SCDMA cell + */ +public final class CellIdentityTdscdma extends CellIdentity { + private static final String TAG = CellIdentityTdscdma.class.getSimpleName(); + private static final boolean DBG = false; + + // 16-bit Location Area Code, 0..65535, INT_MAX if unknown. + private final int mLac; + // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown. + private final int mCid; + // 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown. + private final int mCpid; + + /** + * @hide + */ + public CellIdentityTdscdma() { + super(TAG, TYPE_TDSCDMA, null, null); + mLac = Integer.MAX_VALUE; + mCid = Integer.MAX_VALUE; + mCpid = Integer.MAX_VALUE; + } + + /** + * @param mcc 3-digit Mobile Country Code, 0..999 + * @param mnc 2 or 3-digit Mobile Network Code, 0..999 + * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown + * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown + * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown + * + * @hide + */ + public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) { + this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid); + } + + /** + * @param mcc 3-digit Mobile Country Code in string format + * @param mnc 2 or 3-digit Mobile Network Code in string format + * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown + * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown + * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown + * + * @hide + */ + public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) { + super(TAG, TYPE_TDSCDMA, mcc, mnc); + mLac = lac; + mCid = cid; + mCpid = cpid; + } + + private CellIdentityTdscdma(CellIdentityTdscdma cid) { + this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid); + } + + CellIdentityTdscdma copy() { + return new CellIdentityTdscdma(this); + } + + /** + * Get Mobile Country Code in string format + * @return Mobile Country Code in string format, null if unknown + */ + public String getMccStr() { + return mMccStr; + } + + /** + * Get Mobile Network Code in string format + * @return Mobile Network Code in string format, null if unknown + */ + public String getMncStr() { + return mMncStr; + } + + /** + * @return 16-bit Location Area Code, 0..65535, INT_MAX if unknown + */ + public int getLac() { + return mLac; + } + + /** + * @return 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown + */ + public int getCid() { + return mCid; + } + + /** + * @return 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown + */ + public int getCpid() { + return mCpid; + } + + @Override + public int hashCode() { + return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof CellIdentityTdscdma)) { + return false; + } + + CellIdentityTdscdma o = (CellIdentityTdscdma) other; + return TextUtils.equals(mMccStr, o.mMccStr) + && TextUtils.equals(mMncStr, o.mMncStr) + && mLac == o.mLac + && mCid == o.mCid + && mCpid == o.mCpid; + } + + @Override + public String toString() { + return new StringBuilder(TAG) + .append(":{ mMcc=").append(mMccStr) + .append(" mMnc=").append(mMncStr) + .append(" mLac=").append(mLac) + .append(" mCid=").append(mCid) + .append(" mCpid=").append(mCpid) + .append("}").toString(); + } + + /** Implement the Parcelable interface */ + @Override + public void writeToParcel(Parcel dest, int flags) { + if (DBG) log("writeToParcel(Parcel, int): " + toString()); + super.writeToParcel(dest, TYPE_TDSCDMA); + dest.writeInt(mLac); + dest.writeInt(mCid); + dest.writeInt(mCpid); + } + + /** Construct from Parcel, type has already been processed */ + private CellIdentityTdscdma(Parcel in) { + super(TAG, TYPE_TDSCDMA, in); + mLac = in.readInt(); + mCid = in.readInt(); + mCpid = in.readInt(); + + if (DBG) log(toString()); + } + + /** Implement the Parcelable interface */ + @SuppressWarnings("hiding") + public static final Creator<CellIdentityTdscdma> CREATOR = + new Creator<CellIdentityTdscdma>() { + @Override + public CellIdentityTdscdma createFromParcel(Parcel in) { + in.readInt(); // skip + return createFromParcelBody(in); + } + + @Override + public CellIdentityTdscdma[] newArray(int size) { + return new CellIdentityTdscdma[size]; + } + }; + + /** @hide */ + protected static CellIdentityTdscdma createFromParcelBody(Parcel in) { + return new CellIdentityTdscdma(in); + } +} diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index e4bb4f297a3f..1aa1715ee3e8 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -17,8 +17,6 @@ package android.telephony; import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.Rlog; import android.text.TextUtils; import java.util.Objects; @@ -26,9 +24,8 @@ import java.util.Objects; /** * CellIdentity to represent a unique UMTS cell */ -public final class CellIdentityWcdma implements Parcelable { - - private static final String LOG_TAG = "CellIdentityWcdma"; +public final class CellIdentityWcdma extends CellIdentity { + private static final String TAG = CellIdentityWcdma.class.getSimpleName(); private static final boolean DBG = false; // 16-bit Location Area Code, 0..65535 @@ -39,10 +36,6 @@ public final class CellIdentityWcdma implements Parcelable { private final int mPsc; // 16-bit UMTS Absolute RF Channel Number private final int mUarfcn; - // 3-digit Mobile Country Code in string format - private final String mMccStr; - // 2 or 3-digit Mobile Network Code in string format - private final String mMncStr; // long alpha Operator Name String or Enhanced Operator Name String private final String mAlphaLong; // short alpha Operator Name String or Enhanced Operator Name String @@ -52,12 +45,11 @@ public final class CellIdentityWcdma implements Parcelable { * @hide */ public CellIdentityWcdma() { + super(TAG, TYPE_TDSCDMA, null, null); mLac = Integer.MAX_VALUE; mCid = Integer.MAX_VALUE; mPsc = Integer.MAX_VALUE; mUarfcn = Integer.MAX_VALUE; - mMccStr = null; - mMncStr = null; mAlphaLong = null; mAlphaShort = null; } @@ -106,36 +98,11 @@ public final class CellIdentityWcdma implements Parcelable { */ public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn, String mccStr, String mncStr, String alphal, String alphas) { + super(TAG, TYPE_WCDMA, mccStr, mncStr); mLac = lac; mCid = cid; mPsc = psc; mUarfcn = uarfcn; - - // Only allow INT_MAX if unknown string mcc/mnc - if (mccStr == null || mccStr.matches("^[0-9]{3}$")) { - mMccStr = mccStr; - } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mccStr is empty or unknown, set it as null. - mMccStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format - // after the bug got fixed. - mMccStr = null; - log("invalid MCC format: " + mccStr); - } - - if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) { - mMncStr = mncStr; - } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) { - // If the mncStr is empty or unknown, set it as null. - mMncStr = null; - } else { - // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format - // after the bug got fixed. - mMncStr = null; - log("invalid MNC format: " + mncStr); - } - mAlphaLong = alphal; mAlphaShort = alphas; } @@ -250,58 +217,53 @@ public final class CellIdentityWcdma implements Parcelable { } CellIdentityWcdma o = (CellIdentityWcdma) other; - return mLac == o.mLac && - mCid == o.mCid && - mPsc == o.mPsc && - mUarfcn == o.mUarfcn && - TextUtils.equals(mMccStr, o.mMccStr) && - TextUtils.equals(mMncStr, o.mMncStr) && - TextUtils.equals(mAlphaLong, o.mAlphaLong) && - TextUtils.equals(mAlphaShort, o.mAlphaShort); + return mLac == o.mLac + && mCid == o.mCid + && mPsc == o.mPsc + && mUarfcn == o.mUarfcn + && TextUtils.equals(mMccStr, o.mMccStr) + && TextUtils.equals(mMncStr, o.mMncStr) + && TextUtils.equals(mAlphaLong, o.mAlphaLong) + && TextUtils.equals(mAlphaShort, o.mAlphaShort); } @Override public String toString() { - StringBuilder sb = new StringBuilder("CellIdentityWcdma:{"); - sb.append(" mLac=").append(mLac); - sb.append(" mCid=").append(mCid); - sb.append(" mPsc=").append(mPsc); - sb.append(" mUarfcn=").append(mUarfcn); - sb.append(" mMcc=").append(mMccStr); - sb.append(" mMnc=").append(mMncStr); - sb.append(" mAlphaLong=").append(mAlphaLong); - sb.append(" mAlphaShort=").append(mAlphaShort); - sb.append("}"); - - return sb.toString(); - } - - /** Implement the Parcelable interface */ - @Override - public int describeContents() { - return 0; + return new StringBuilder(TAG) + .append(":{ mLac=").append(mLac) + .append(" mCid=").append(mCid) + .append(" mPsc=").append(mPsc) + .append(" mUarfcn=").append(mUarfcn) + .append(" mMcc=").append(mMccStr) + .append(" mMnc=").append(mMncStr) + .append(" mAlphaLong=").append(mAlphaLong) + .append(" mAlphaShort=").append(mAlphaShort) + .append("}").toString(); } /** Implement the Parcelable interface */ @Override public void writeToParcel(Parcel dest, int flags) { if (DBG) log("writeToParcel(Parcel, int): " + toString()); + super.writeToParcel(dest, TYPE_WCDMA); dest.writeInt(mLac); dest.writeInt(mCid); dest.writeInt(mPsc); dest.writeInt(mUarfcn); - dest.writeString(mMccStr); - dest.writeString(mMncStr); dest.writeString(mAlphaLong); dest.writeString(mAlphaShort); } /** Construct from Parcel, type has already been processed */ private CellIdentityWcdma(Parcel in) { - this(in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(), - in.readString(), in.readString(), in.readString()); - - if (DBG) log("CellIdentityWcdma(Parcel): " + toString()); + super(TAG, TYPE_WCDMA, in); + mLac = in.readInt(); + mCid = in.readInt(); + mPsc = in.readInt(); + mUarfcn = in.readInt(); + mAlphaLong = in.readString(); + mAlphaShort = in.readString(); + if (DBG) log(toString()); } /** Implement the Parcelable interface */ @@ -310,7 +272,8 @@ public final class CellIdentityWcdma implements Parcelable { new Creator<CellIdentityWcdma>() { @Override public CellIdentityWcdma createFromParcel(Parcel in) { - return new CellIdentityWcdma(in); + in.readInt(); // skip + return createFromParcelBody(in); } @Override @@ -319,10 +282,8 @@ public final class CellIdentityWcdma implements Parcelable { } }; - /** - * log - */ - private static void log(String s) { - Rlog.w(LOG_TAG, s); + /** @hide */ + protected static CellIdentityWcdma createFromParcelBody(Parcel in) { + return new CellIdentityWcdma(in); } }
\ No newline at end of file diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java index ea503c3e4bd8..9726569a60a2 100644 --- a/telephony/java/android/telephony/NetworkScanRequest.java +++ b/telephony/java/android/telephony/NetworkScanRequest.java @@ -143,7 +143,11 @@ public final class NetworkScanRequest implements Parcelable { int incrementalResultsPeriodicity, ArrayList<String> mccMncs) { this.mScanType = scanType; - this.mSpecifiers = specifiers.clone(); + if (specifiers != null) { + this.mSpecifiers = specifiers.clone(); + } else { + this.mSpecifiers = null; + } this.mSearchPeriodicity = searchPeriodicity; this.mMaxSearchTime = maxSearchTime; this.mIncrementalResults = incrementalResults; @@ -187,7 +191,7 @@ public final class NetworkScanRequest implements Parcelable { /** Returns the radio access technologies with bands or channels that need to be scanned. */ public RadioAccessSpecifier[] getSpecifiers() { - return mSpecifiers.clone(); + return mSpecifiers == null ? null : mSpecifiers.clone(); } /** diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index c7e51310e106..98ea45158ba1 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -244,6 +244,13 @@ public class PhoneStateListener { */ public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000; + /** + * Listen for changes to the user mobile data state + * + * @see #onUserMobileDataStateChanged + */ + public static final int LISTEN_USER_MOBILE_DATA_STATE = 0x00080000; + /* * Subscription used to listen to the phone state changes * @hide @@ -349,6 +356,9 @@ public class PhoneStateListener { case LISTEN_DATA_ACTIVATION_STATE: PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj); break; + case LISTEN_USER_MOBILE_DATA_STATE: + PhoneStateListener.this.onUserMobileDataStateChanged((boolean)msg.obj); + break; case LISTEN_CARRIER_NETWORK_CHANGE: PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj); break; @@ -543,6 +553,14 @@ public class PhoneStateListener { } /** + * Callback invoked when the user mobile data state has changed + * @param enabled indicates whether the current user mobile data state is enabled or disabled. + */ + public void onUserMobileDataStateChanged(boolean enabled) { + // default implementation empty + } + + /** * 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 @@ -654,6 +672,10 @@ public class PhoneStateListener { send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState); } + public void onUserMobileDataStateChanged(boolean enabled) { + send(LISTEN_USER_MOBILE_DATA_STATE, 0, 0, enabled); + } + public void onCarrierNetworkChange(boolean active) { send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active); } diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java index 5412c6172ba3..81e7ed0111f4 100644 --- a/telephony/java/android/telephony/RadioAccessSpecifier.java +++ b/telephony/java/android/telephony/RadioAccessSpecifier.java @@ -33,7 +33,7 @@ public final class RadioAccessSpecifier implements Parcelable { * * This parameter must be provided or else the scan will be rejected. * - * See {@link RadioNetworkConstants.RadioAccessNetworks} for details. + * See {@link AccessNetworkConstants.AccessNetworkType} for details. */ private int mRadioAccessNetwork; @@ -43,7 +43,7 @@ public final class RadioAccessSpecifier implements Parcelable { * When no specific bands are specified (empty array or null), all the frequency bands * supported by the modem will be scanned. * - * See {@link RadioNetworkConstants} for details. + * See {@link AccessNetworkConstants} for details. */ private int[] mBands; @@ -56,7 +56,7 @@ public final class RadioAccessSpecifier implements Parcelable { * When no specific channels are specified (empty array or null), all the frequency channels * supported by the modem will be scanned. * - * See {@link RadioNetworkConstants} for details. + * See {@link AccessNetworkConstants} for details. */ private int[] mChannels; @@ -72,14 +72,22 @@ public final class RadioAccessSpecifier implements Parcelable { */ public RadioAccessSpecifier(int ran, int[] bands, int[] channels) { this.mRadioAccessNetwork = ran; - this.mBands = bands.clone(); - this.mChannels = channels.clone(); + if (bands != null) { + this.mBands = bands.clone(); + } else { + this.mBands = null; + } + if (channels != null) { + this.mChannels = channels.clone(); + } else { + this.mChannels = null; + } } /** * Returns the radio access network that needs to be scanned. * - * The returned value is define in {@link RadioNetworkConstants.RadioAccessNetworks}; + * The returned value is define in {@link AccessNetworkConstants.AccessNetworkType}; */ public int getRadioAccessNetwork() { return mRadioAccessNetwork; @@ -88,17 +96,17 @@ public final class RadioAccessSpecifier implements Parcelable { /** * Returns the frequency bands that need to be scanned. * - * The returned value is defined in either of {@link RadioNetworkConstants.GeranBands}, - * {@link RadioNetworkConstants.UtranBands} and {@link RadioNetworkConstants.EutranBands}, and + * The returned value is defined in either of {@link AccessNetworkConstants.GeranBand}, + * {@link AccessNetworkConstants.UtranBand} and {@link AccessNetworkConstants.EutranBand}, and * it depends on the returned value of {@link #getRadioAccessNetwork()}. */ public int[] getBands() { - return mBands.clone(); + return mBands == null ? null : mBands.clone(); } /** Returns the frequency channels that need to be scanned. */ public int[] getChannels() { - return mChannels.clone(); + return mChannels == null ? null : mChannels.clone(); } public static final Parcelable.Creator<RadioAccessSpecifier> CREATOR = diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 116e711ee886..d4b4b88081d6 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -16,12 +16,15 @@ package android.telephony; +import android.annotation.IntDef; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Rlog; import android.text.TextUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Contains phone state and service related information. * @@ -105,6 +108,31 @@ public class ServiceState implements Parcelable { /** @hide */ public static final int RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED = 14; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" }, + value = { + RIL_RADIO_TECHNOLOGY_UNKNOWN, + RIL_RADIO_TECHNOLOGY_GPRS, + RIL_RADIO_TECHNOLOGY_EDGE, + RIL_RADIO_TECHNOLOGY_UMTS, + RIL_RADIO_TECHNOLOGY_IS95A, + RIL_RADIO_TECHNOLOGY_IS95B, + RIL_RADIO_TECHNOLOGY_1xRTT, + RIL_RADIO_TECHNOLOGY_EVDO_0, + RIL_RADIO_TECHNOLOGY_EVDO_A, + RIL_RADIO_TECHNOLOGY_HSDPA, + RIL_RADIO_TECHNOLOGY_HSUPA, + RIL_RADIO_TECHNOLOGY_HSPA, + RIL_RADIO_TECHNOLOGY_EVDO_B, + RIL_RADIO_TECHNOLOGY_EHRPD, + RIL_RADIO_TECHNOLOGY_LTE, + RIL_RADIO_TECHNOLOGY_HSPAP, + RIL_RADIO_TECHNOLOGY_GSM, + RIL_RADIO_TECHNOLOGY_TD_SCDMA, + RIL_RADIO_TECHNOLOGY_IWLAN, + RIL_RADIO_TECHNOLOGY_LTE_CA}) + public @interface RilRadioTechnology {} /** * Available radio technologies for GSM, UMTS and CDMA. * Duplicates the constants from hardware/radio/include/ril.h @@ -162,6 +190,12 @@ public class ServiceState implements Parcelable { */ public static final int RIL_RADIO_TECHNOLOGY_LTE_CA = 19; + /** + * Number of radio technologies for GSM, UMTS and CDMA. + * @hide + */ + private static final int NEXT_RIL_RADIO_TECHNOLOGY = 20; + /** @hide */ public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK = (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1)) @@ -216,6 +250,11 @@ public class ServiceState implements Parcelable { */ public static final int ROAMING_TYPE_INTERNATIONAL = 3; + /** + * Unknown ID. Could be returned by {@link #getNetworkId()} or {@link #getSystemId()} + */ + public static final int UNKNOWN_ID = -1; + private int mVoiceRoamingType; private int mDataRoamingType; private String mVoiceOperatorAlphaLong; @@ -1153,7 +1192,8 @@ public class ServiceState implements Parcelable { return getRilDataRadioTechnology(); } - private int rilRadioTechnologyToNetworkType(int rt) { + /** @hide */ + public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rt) { switch(rt) { case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: return TelephonyManager.NETWORK_TYPE_GPRS; @@ -1212,12 +1252,20 @@ public class ServiceState implements Parcelable { return this.mCssIndicator ? 1 : 0; } - /** @hide */ + /** + * Get the CDMA NID (Network Identification Number), a number uniquely identifying a network + * within a wireless system. (Defined in 3GPP2 C.S0023 3.4.8) + * @return The CDMA NID or {@link #UNKNOWN_ID} if not available. + */ public int getNetworkId() { return this.mNetworkId; } - /** @hide */ + /** + * Get the CDMA SID (System Identification Number), a number uniquely identifying a wireless + * system. (Defined in 3GPP2 C.S0023 3.4.8) + * @return The CDMA SID or {@link #UNKNOWN_ID} if not available. + */ public int getSystemId() { return this.mSystemId; } @@ -1300,6 +1348,34 @@ public class ServiceState implements Parcelable { return bearerBitmask; } + /** @hide */ + public static int convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask) { + if (networkTypeBitmask == 0) { + return 0; + } + int bearerBitmask = 0; + for (int bearerInt = 0; bearerInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerInt++) { + if (bitmaskHasTech(networkTypeBitmask, rilRadioTechnologyToNetworkType(bearerInt))) { + bearerBitmask |= getBitmaskForTech(bearerInt); + } + } + return bearerBitmask; + } + + /** @hide */ + public static int convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask) { + if (bearerBitmask == 0) { + return 0; + } + int networkTypeBitmask = 0; + for (int bearerInt = 0; bearerInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerInt++) { + if (bitmaskHasTech(bearerBitmask, bearerInt)) { + networkTypeBitmask |= getBitmaskForTech(rilRadioTechnologyToNetworkType(bearerInt)); + } + } + return networkTypeBitmask; + } + /** * Returns a merged ServiceState consisting of the base SS with voice settings from the * voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned). diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 942ea009f684..e633053800bc 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -2564,6 +2564,35 @@ public final class Telephony { public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers"); /** + * The {@code content://} style URL to be called from DevicePolicyManagerService, + * can manage DPC-owned APNs. + * @hide + */ + public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc"); + + /** + * The {@code content://} style URL to be called from Telephony to query APNs. + * When DPC-owned APNs are enforced, only DPC-owned APNs are returned, otherwise only + * non-DPC-owned APNs are returned. + * @hide + */ + public static final Uri FILTERED_URI = Uri.parse("content://telephony/carriers/filtered"); + + /** + * The {@code content://} style URL to be called from DevicePolicyManagerService + * or Telephony to manage whether DPC-owned APNs are enforced. + * @hide + */ + public static final Uri ENFORCE_MANAGED_URI = Uri.parse( + "content://telephony/carriers/enforce_managed"); + + /** + * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced. + * @hide + */ + public static final String ENFORCE_KEY = "enforced"; + + /** * The default sort order for this table. */ public static final String DEFAULT_SORT_ORDER = "name ASC"; @@ -2693,6 +2722,7 @@ public final class Telephony { * but is currently only used for LTE (14) and eHRPD (13). * <P>Type: INTEGER</P> */ + @Deprecated public static final String BEARER = "bearer"; /** @@ -2704,9 +2734,19 @@ public final class Telephony { * <P>Type: INTEGER</P> * @hide */ + @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask"; /** + * Radio technology (network type) bitmask. + * To check what values can be contained, refer to + * {@link android.telephony.TelephonyManager}. + * Bitmask for a radio tech R is (1 << (R - 1)) + * <P>Type: INTEGER</P> + */ + public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask"; + + /** * MVNO type: * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}. * <P>Type: TEXT</P> diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 7245daccec65..6a683431f0aa 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -54,6 +54,7 @@ import android.util.Log; import com.android.ims.internal.IImsMMTelFeature; import com.android.ims.internal.IImsRcsFeature; +import com.android.ims.internal.IImsRegistration; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telecom.ITelecomService; @@ -957,6 +958,64 @@ public class TelephonyManager { */ public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; + /** + * An unknown carrier id. It could either be subscription unavailable or the subscription + * carrier cannot be recognized. Unrecognized carriers here means + * {@link #getSimOperator() MCC+MNC} cannot be identified. + */ + public static final int UNKNOWN_CARRIER_ID = -1; + + /** + * Broadcast Action: The subscription carrier identity has changed. + * This intent could be sent on the following events: + * <ul> + * <li>Subscription absent. Carrier identity could change from a valid id to + * {@link TelephonyManager#UNKNOWN_CARRIER_ID}.</li> + * <li>Subscription loaded. Carrier identity could change from + * {@link TelephonyManager#UNKNOWN_CARRIER_ID} to a valid id.</li> + * <li>The subscription carrier is recognized after a remote update.</li> + * </ul> + * The intent will have the following extra values: + * <ul> + * <li>{@link #EXTRA_CARRIER_ID} The up-to-date carrier id of the current subscription id. + * </li> + * <li>{@link #EXTRA_CARRIER_NAME} The up-to-date carrier name of the current subscription. + * </li> + * <li>{@link #EXTRA_SUBSCRIPTION_ID} The subscription id associated with the changed carrier + * identity. + * </li> + * </ul> + * <p class="note">This is a protected intent that can only be sent by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = + "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; + + /** + * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates + * the updated carrier id {@link TelephonyManager#getSubscriptionCarrierId()} of the current + * subscription. + * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or + * the carrier cannot be identified. + */ + public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID"; + + /** + * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which + * indicates the updated carrier name of the current subscription. + * {@see TelephonyManager#getSubscriptionCarrierName()} + * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID}, + * usually the brand name of the subsidiary (e.g. T-Mobile). + */ + public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; + + /** + * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} to indicate the + * subscription which has changed. + */ + public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID"; + + // // // Device Info @@ -4720,6 +4779,25 @@ public class TelephonyManager { } /** + * @return the {@IImsRegistration} interface that corresponds with the slot index and feature. + * @param slotIndex The SIM slot corresponding to the ImsService ImsRegistration is active for. + * @param feature An integer indicating the feature that we wish to get the ImsRegistration for. + * Corresponds to features defined in ImsFeature. + * @hide + */ + public @Nullable IImsRegistration getImsRegistration(int slotIndex, int feature) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getImsRegistration(slotIndex, feature); + } + } catch (RemoteException e) { + Rlog.e(TAG, "getImsRegistration, RemoteException: " + e.getMessage()); + } + return null; + } + + /** * Set IMS registration state * * @param Registration state @@ -5676,39 +5754,38 @@ public class TelephonyManager { * @param enable Whether to enable mobile data. * * @see #hasCarrierPrivileges + * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead. */ + @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean enable) { - setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable); + setUserMobileDataEnabled(enable); } - /** @hide */ + /** + * @hide + * @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead. + */ @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int subId, boolean enable) { - try { - Log.d(TAG, "setDataEnabled: enabled=" + enable); - ITelephony telephony = getITelephony(); - if (telephony != null) - telephony.setDataEnabled(subId, enable); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#setDataEnabled", e); - } + setUserMobileDataEnabled(subId, enable); } - /** - * @deprecated use {@link #isDataEnabled()} instead. + * @deprecated use {@link #isUserMobileDataEnabled()} instead. * @hide */ @SystemApi @Deprecated public boolean getDataEnabled() { - return isDataEnabled(); + return isUserMobileDataEnabled(); } /** - * Returns whether mobile data is enabled or not. + * Returns whether mobile data is enabled or not per user setting. There are other factors + * that could disable mobile data, but they are not considered here. * * If this object has been created with {@link #createForSubscriptionId}, applies to the given * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} @@ -5725,28 +5802,21 @@ public class TelephonyManager { * @return true if mobile data is enabled. * * @see #hasCarrierPrivileges + * @deprecated use {@link #isUserMobileDataEnabled()} instead. */ - @SuppressWarnings("deprecation") + @Deprecated public boolean isDataEnabled() { - return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); + return isUserMobileDataEnabled(); } /** - * @deprecated use {@link #isDataEnabled(int)} instead. + * @deprecated use {@link #isUserMobileDataEnabled()} instead. * @hide */ + @Deprecated @SystemApi public boolean getDataEnabled(int subId) { - boolean retVal = false; - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - retVal = telephony.getDataEnabled(subId); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#getDataEnabled", e); - } catch (NullPointerException e) { - } - return retVal; + return isUserMobileDataEnabled(subId); } /** @hide */ @@ -6556,6 +6626,55 @@ public class TelephonyManager { } /** + * Returns carrier id of the current subscription. + * <p>To recognize a carrier (including MVNO) as a first class identity, assign each carrier + * with a canonical integer a.k.a carrier id. + * + * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the + * subscription is unavailable or the carrier cannot be identified. + * @throws IllegalStateException if telephony service is unavailable. + */ + public int getSubscriptionCarrierId() { + try { + ITelephony service = getITelephony(); + return service.getSubscriptionCarrierId(getSubId()); + } catch (RemoteException ex) { + // This could happen if binder process crashes. + ex.rethrowAsRuntimeException(); + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing. + throw new IllegalStateException("Telephony service unavailable"); + } + return UNKNOWN_CARRIER_ID; + } + + /** + * Returns carrier name of the current subscription. + * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId()}, + * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure + * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name. + * Carrier name is not a canonical identity, use {@link #getSubscriptionCarrierId()} instead. + * <p>The returned carrier name is unlocalized. + * + * @return Carrier name of the current subscription. Return {@code null} if the subscription is + * unavailable or the carrier cannot be identified. + * @throws IllegalStateException if telephony service is unavailable. + */ + public String getSubscriptionCarrierName() { + try { + ITelephony service = getITelephony(); + return service.getSubscriptionCarrierName(getSubId()); + } catch (RemoteException ex) { + // This could happen if binder process crashes. + ex.rethrowAsRuntimeException(); + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing. + throw new IllegalStateException("Telephony service unavailable"); + } + return null; + } + + /** * Return the application ID for the app type like {@link APPTYPE_CSIM}. * * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission @@ -6898,4 +7017,101 @@ public class TelephonyManager { } return null; } + + /** + * Turns mobile data on or off. + * If the {@link TelephonyManager} object has been created with + * {@link #createForSubscriptionId}, this API applies to the given subId. + * Otherwise, it applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges. + * + * @param enable Whether to enable mobile data. + * + * @see #hasCarrierPrivileges + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setUserMobileDataEnabled(boolean enable) { + setUserMobileDataEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable); + } + + /** + * Returns whether mobile data is enabled or not per user setting. There are other factors + * that could disable mobile data, but they are not considered here. + * + * If this object has been created with {@link #createForSubscriptionId}, applies to the given + * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p>Requires one of the following permissions: + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE}, + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the + * calling app has carrier privileges. + * + * <p>Note that this does not take into account any data restrictions that may be present on the + * calling app. Such restrictions may be inspected with + * {@link ConnectivityManager#getRestrictBackgroundStatus}. + * + * @return true if mobile data is enabled. + * + * @see #hasCarrierPrivileges + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.ACCESS_NETWORK_STATE, + android.Manifest.permission.MODIFY_PHONE_STATE + }) + public boolean isUserMobileDataEnabled() { + return isUserMobileDataEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); + } + + /** + * @hide + * Unlike isUserMobileDataEnabled, this API also evaluates carrierDataEnabled, + * policyDataEnabled etc to give a final decision. + */ + public boolean isMobileDataEnabled() { + boolean retVal = false; + try { + int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId()); + ITelephony telephony = getITelephony(); + if (telephony != null) + retVal = telephony.isDataEnabled(subId); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#isDataEnabled", e); + } catch (NullPointerException e) { + } + return retVal; + } + + /** + * Utility class of {@link #isUserMobileDataEnabled()}; + */ + private boolean isUserMobileDataEnabled(int subId) { + boolean retVal = false; + try { + ITelephony telephony = getITelephony(); + if (telephony != null) + retVal = telephony.isUserDataEnabled(subId); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#isUserDataEnabled", e); + } catch (NullPointerException e) { + } + return retVal; + } + + /** Utility method of {@link #setUserMobileDataEnabled(boolean)} */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + private void setUserMobileDataEnabled(int subId, boolean enable) { + try { + Log.d(TAG, "setUserMobileDataEnabled: enabled=" + enable); + ITelephony telephony = getITelephony(); + if (telephony != null) + telephony.setUserDataEnabled(subId, enable); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#setUserDataEnabled", e); + } + } } diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index e42a75835008..39372019c20f 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Objects; /** * Describes a single UICC access rule according to the GlobalPlatform Secure Element Access Control @@ -205,6 +206,21 @@ public final class UiccAccessRule implements Parcelable { } @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UiccAccessRule that = (UiccAccessRule) obj; + return Arrays.equals(mCertificateHash, that.mCertificateHash) + && Objects.equals(mPackageName, that.mPackageName) + && mAccessType == that.mAccessType; + } + + @Override public String toString() { return "cert: " + IccUtils.bytesToHexString(mCertificateHash) + " pkg: " + mPackageName + " access: " + mAccessType; diff --git a/telephony/java/android/telephony/data/ApnSetting.aidl b/telephony/java/android/telephony/data/ApnSetting.aidl new file mode 100644 index 000000000000..381e5e8a3a5e --- /dev/null +++ b/telephony/java/android/telephony/data/ApnSetting.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 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.data; + +parcelable ApnSetting; diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java new file mode 100644 index 000000000000..2ab8d4fb900e --- /dev/null +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -0,0 +1,1370 @@ +/* + * Copyright (C) 2018 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.data; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.StringDef; +import android.content.ContentValues; +import android.database.Cursor; +import android.hardware.radio.V1_0.ApnTypes; +import android.net.NetworkUtils; +import android.os.Parcel; +import android.os.Parcelable; +import android.provider.Telephony; +import android.telephony.Rlog; +import android.text.TextUtils; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.MalformedURLException; +import java.net.UnknownHostException; +import java.net.URL; +import java.net.InetAddress; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * A class representing an APN configuration. + */ +public class ApnSetting implements Parcelable { + + static final String LOG_TAG = "ApnSetting"; + private static final boolean VDBG = false; + + private final String mEntryName; + private final String mApnName; + private final InetAddress mProxy; + private final int mPort; + private final URL mMmsc; + private final InetAddress mMmsProxy; + private final int mMmsPort; + private final String mUser; + private final String mPassword; + private final int mAuthType; + private final List<String> mTypes; + private final int mTypesBitmap; + private final int mId; + private final String mOperatorNumeric; + private final String mProtocol; + private final String mRoamingProtocol; + private final int mMtu; + + private final boolean mCarrierEnabled; + private final int mBearer; + private final int mBearerBitmask; + + private final int mProfileId; + + private final boolean mModemCognitive; + private final int mMaxConns; + private final int mWaitTime; + private final int mMaxConnsTime; + + private final String mMvnoType; + private final String mMvnoMatchData; + + private boolean mPermanentFailed = false; + + /** + * Returns the types bitmap of the APN. + * + * @return types bitmap of the APN + * @hide + */ + public int getTypesBitmap() { + return mTypesBitmap; + } + + /** + * Returns the MTU size of the mobile interface to which the APN connected. + * + * @return the MTU size of the APN + * @hide + */ + public int getMtu() { + return mMtu; + } + + /** + * Radio Access Technology info. + * To check what values can hold, refer to ServiceState.java. + * This should be spread to other technologies, + * but currently only used for LTE(14) and EHRPD(13). + * + * @return the bearer info of the APN + * @hide + */ + public int getBearer() { + return mBearer; + } + + /** + * Returns the radio access technology bitmask for this APN. + * + * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio + * technologies in ServiceState. + * This should be spread to other technologies, + * but currently only used for LTE(14) and EHRPD(13). + * + * @return the radio access technology bitmask + * @hide + */ + public int getBearerBitmask() { + return mBearerBitmask; + } + + /** + * Returns the profile id to which the APN saved in modem. + * + * @return the profile id of the APN + * @hide + */ + public int getProfileId() { + return mProfileId; + } + + /** + * Returns if the APN setting is to be set in modem. + * + * @return is the APN setting to be set in modem + * @hide + */ + public boolean getModemCognitive() { + return mModemCognitive; + } + + /** + * Returns the max connections of this APN. + * + * @return the max connections of this APN + * @hide + */ + public int getMaxConns() { + return mMaxConns; + } + + /** + * Returns the wait time for retry of the APN. + * + * @return the wait time for retry of the APN + * @hide + */ + public int getWaitTime() { + return mWaitTime; + } + + /** + * Returns the time to limit max connection for the APN. + * + * @return the time to limit max connection for the APN + * @hide + */ + public int getMaxConnsTime() { + return mMaxConnsTime; + } + + /** + * Returns the MVNO data. Examples: + * "spn": A MOBILE, BEN NL + * "imsi": 302720x94, 2060188 + * "gid": 4E, 33 + * "iccid": 898603 etc.. + * + * @return the mvno match data + * @hide + */ + public String getMvnoMatchData() { + return mMvnoMatchData; + } + + /** + * Indicates this APN setting is permanently failed and cannot be + * retried by the retry manager anymore. + * + * @return if this APN setting is permanently failed + * @hide + */ + public boolean getPermanentFailed() { + return mPermanentFailed; + } + + /** + * Sets if this APN setting is permanently failed. + * + * @param permanentFailed if this APN setting is permanently failed + * @hide + */ + public void setPermanentFailed(boolean permanentFailed) { + mPermanentFailed = permanentFailed; + } + + /** + * Returns the entry name of the APN. + * + * @return the entry name for the APN + */ + public String getEntryName() { + return mEntryName; + } + + /** + * Returns the name of the APN. + * + * @return APN name + */ + public String getApnName() { + return mApnName; + } + + /** + * Returns the proxy address of the APN. + * + * @return proxy address. + */ + public InetAddress getProxy() { + return mProxy; + } + + /** + * Returns the proxy port of the APN. + * + * @return proxy port + */ + public int getPort() { + return mPort; + } + /** + * Returns the MMSC URL of the APN. + * + * @return MMSC URL. + */ + public URL getMmsc() { + return mMmsc; + } + + /** + * Returns the MMS proxy address of the APN. + * + * @return MMS proxy address. + */ + public InetAddress getMmsProxy() { + return mMmsProxy; + } + + /** + * Returns the MMS proxy port of the APN. + * + * @return MMS proxy port + */ + public int getMmsPort() { + return mMmsPort; + } + + /** + * Returns the APN username of the APN. + * + * @return APN username + */ + public String getUser() { + return mUser; + } + + /** + * Returns the APN password of the APN. + * + * @return APN password + */ + public String getPassword() { + return mPassword; + } + + /** @hide */ + @IntDef({ + AUTH_TYPE_NONE, + AUTH_TYPE_PAP, + AUTH_TYPE_CHAP, + AUTH_TYPE_PAP_OR_CHAP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthType {} + + /** + * Returns the authentication type of the APN. + * + * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. + * + * @return authentication type + */ + @AuthType + public int getAuthType() { + return mAuthType; + } + + /** @hide */ + @StringDef({ + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ApnType {} + + /** + * Returns the list of APN types of the APN. + * + * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + * + * @return the list of APN types + */ + @ApnType + public List<String> getTypes() { + return mTypes; + } + + /** + * Returns the unique database id for this entry. + * + * @return the unique database id + */ + public int getId() { + return mId; + } + + /** + * Returns the numeric operator ID for the APN. Usually + * {@link android.provider.Telephony.Carriers#MCC} + + * {@link android.provider.Telephony.Carriers#MNC}. + * + * @return the numeric operator ID + */ + public String getOperatorNumeric() { + return mOperatorNumeric; + } + + /** @hide */ + @StringDef({ + PROTOCOL_IP, + PROTOCOL_IPV6, + PROTOCOL_IPV4V6, + PROTOCOL_PPP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ProtocolType {} + + /** + * Returns the protocol to use to connect to this APN. + * + * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. + * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + * + * @return the protocol + */ + @ProtocolType + public String getProtocol() { + return mProtocol; + } + + /** + * Returns the protocol to use to connect to this APN when roaming. + * + * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}. + * + * @return the roaming protocol + */ + public String getRoamingProtocol() { + return mRoamingProtocol; + } + + /** + * Returns the current status of APN. + * + * {@code true} : enabled APN. + * {@code false} : disabled APN. + * + * @return the current status + */ + public boolean isEnabled() { + return mCarrierEnabled; + } + + /** @hide */ + @StringDef({ + MVNO_TYPE_SPN, + MVNO_TYPE_IMSI, + MVNO_TYPE_GID, + MVNO_TYPE_ICCID, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MvnoType {} + + /** + * Returns the MVNO match type for this APN. + * + * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. + * + * @return the MVNO match type + */ + @MvnoType + public String getMvnoType() { + return mMvnoType; + } + + private ApnSetting(Builder builder) { + this.mEntryName = builder.mEntryName; + this.mApnName = builder.mApnName; + this.mProxy = builder.mProxy; + this.mPort = builder.mPort; + this.mMmsc = builder.mMmsc; + this.mMmsProxy = builder.mMmsProxy; + this.mMmsPort = builder.mMmsPort; + this.mUser = builder.mUser; + this.mPassword = builder.mPassword; + this.mAuthType = builder.mAuthType; + this.mTypes = (builder.mTypes == null ? new ArrayList<String>() : builder.mTypes); + this.mTypesBitmap = builder.mTypesBitmap; + this.mId = builder.mId; + this.mOperatorNumeric = builder.mOperatorNumeric; + this.mProtocol = builder.mProtocol; + this.mRoamingProtocol = builder.mRoamingProtocol; + this.mMtu = builder.mMtu; + this.mCarrierEnabled = builder.mCarrierEnabled; + this.mBearer = builder.mBearer; + this.mBearerBitmask = builder.mBearerBitmask; + this.mProfileId = builder.mProfileId; + this.mModemCognitive = builder.mModemCognitive; + this.mMaxConns = builder.mMaxConns; + this.mWaitTime = builder.mWaitTime; + this.mMaxConnsTime = builder.mMaxConnsTime; + this.mMvnoType = builder.mMvnoType; + this.mMvnoMatchData = builder.mMvnoMatchData; + } + + /** @hide */ + public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, + String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy, + int mmsPort, String user, String password, int authType, List<String> types, + String protocol, String roamingProtocol, boolean carrierEnabled, int bearer, + int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, + int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) { + return new Builder() + .setId(id) + .setOperatorNumeric(operatorNumeric) + .setEntryName(entryName) + .setApnName(apnName) + .setProxy(proxy) + .setPort(port) + .setMmsc(mmsc) + .setMmsProxy(mmsProxy) + .setMmsPort(mmsPort) + .setUser(user) + .setPassword(password) + .setAuthType(authType) + .setTypes(types) + .setProtocol(protocol) + .setRoamingProtocol(roamingProtocol) + .setCarrierEnabled(carrierEnabled) + .setBearer(bearer) + .setBearerBitmask(bearerBitmask) + .setProfileId(profileId) + .setModemCognitive(modemCognitive) + .setMaxConns(maxConns) + .setWaitTime(waitTime) + .setMaxConnsTime(maxConnsTime) + .setMtu(mtu) + .setMvnoType(mvnoType) + .setMvnoMatchData(mvnoMatchData) + .build(); + } + + /** @hide */ + public static ApnSetting makeApnSetting(Cursor cursor) { + String[] types = parseTypes( + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); + + return makeApnSetting( + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), + inetAddressFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), + URLFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), + inetAddressFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), + portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), + Arrays.asList(types), + cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.BEARER_BITMASK)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_COGNITIVE)) == 1, + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MAX_CONNS_TIME)), + cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)), + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_MATCH_DATA))); + } + + /** @hide */ + public static ApnSetting makeApnSetting(ApnSetting apn) { + return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, + apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser, + apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol, + apn.mCarrierEnabled, apn.mBearer, apn.mBearerBitmask, apn.mProfileId, + apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu, + apn.mMvnoType, apn.mMvnoMatchData); + } + + /** @hide */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[ApnSettingV3] ") + .append(mEntryName) + .append(", ").append(mId) + .append(", ").append(mOperatorNumeric) + .append(", ").append(mApnName) + .append(", ").append(inetAddressToString(mProxy)) + .append(", ").append(URLToString(mMmsc)) + .append(", ").append(inetAddressToString(mMmsProxy)) + .append(", ").append(portToString(mMmsPort)) + .append(", ").append(portToString(mPort)) + .append(", ").append(mAuthType).append(", "); + for (int i = 0; i < mTypes.size(); i++) { + sb.append(mTypes.get(i)); + if (i < mTypes.size() - 1) { + sb.append(" | "); + } + } + sb.append(", ").append(mProtocol); + sb.append(", ").append(mRoamingProtocol); + sb.append(", ").append(mCarrierEnabled); + sb.append(", ").append(mBearer); + sb.append(", ").append(mBearerBitmask); + sb.append(", ").append(mProfileId); + sb.append(", ").append(mModemCognitive); + sb.append(", ").append(mMaxConns); + sb.append(", ").append(mWaitTime); + sb.append(", ").append(mMaxConnsTime); + sb.append(", ").append(mMtu); + sb.append(", ").append(mMvnoType); + sb.append(", ").append(mMvnoMatchData); + sb.append(", ").append(mPermanentFailed); + return sb.toString(); + } + + /** + * Returns true if there are MVNO params specified. + * @hide + */ + public boolean hasMvnoParams() { + return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData); + } + + /** @hide */ + public boolean canHandleType(String type) { + if (!mCarrierEnabled) return false; + boolean wildcardable = true; + if (TYPE_IA.equalsIgnoreCase(type)) wildcardable = false; + for (String t : mTypes) { + // DEFAULT handles all, and HIPRI is handled by DEFAULT + if (t.equalsIgnoreCase(type) + || (wildcardable && t.equalsIgnoreCase(TYPE_ALL)) + || (t.equalsIgnoreCase(TYPE_DEFAULT) + && type.equalsIgnoreCase(TYPE_HIPRI))) { + return true; + } + } + return false; + } + + // check whether the types of two APN same (even only one type of each APN is same) + private boolean typeSameAny(ApnSetting first, ApnSetting second) { + if (VDBG) { + StringBuilder apnType1 = new StringBuilder(first.mApnName + ": "); + for (int index1 = 0; index1 < first.mTypes.size(); index1++) { + apnType1.append(first.mTypes.get(index1)); + apnType1.append(","); + } + + StringBuilder apnType2 = new StringBuilder(second.mApnName + ": "); + for (int index1 = 0; index1 < second.mTypes.size(); index1++) { + apnType2.append(second.mTypes.get(index1)); + apnType2.append(","); + } + Rlog.d(LOG_TAG, "APN1: is " + apnType1); + Rlog.d(LOG_TAG, "APN2: is " + apnType2); + } + + for (int index1 = 0; index1 < first.mTypes.size(); index1++) { + for (int index2 = 0; index2 < second.mTypes.size(); index2++) { + if (first.mTypes.get(index1).equals(ApnSetting.TYPE_ALL) + || second.mTypes.get(index2).equals(ApnSetting.TYPE_ALL) + || first.mTypes.get(index1).equals(second.mTypes.get(index2))) { + if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true"); + return true; + } + } + } + + if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false"); + return false; + } + + // TODO - if we have this function we should also have hashCode. + // Also should handle changes in type order and perhaps case-insensitivity + /** @hide */ + public boolean equals(Object o) { + if (o instanceof ApnSetting == false) { + return false; + } + + ApnSetting other = (ApnSetting) o; + + return mEntryName.equals(other.mEntryName) + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxy, other.mMmsProxy) + && Objects.equals(mMmsPort, other.mMmsPort) + && Objects.equals(mPort,other.mPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mTypes, other.mTypes) + && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mBearer, other.mBearer) + && Objects.equals(mBearerBitmask, other.mBearerBitmask) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData); + } + + /** + * Compare two APN settings + * + * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for + * determining if tearing a data call is needed when conditions change. See + * cleanUpConnectionsOnUpdatedApns in DcTracker. + * + * @param o the other object to compare + * @param isDataRoaming True if the device is on data roaming + * @return True if the two APN settings are same + * @hide + */ + public boolean equals(Object o, boolean isDataRoaming) { + if (!(o instanceof ApnSetting)) { + return false; + } + + ApnSetting other = (ApnSetting) o; + + return mEntryName.equals(other.mEntryName) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxy, other.mProxy) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxy, other.mMmsProxy) + && Objects.equals(mMmsPort, other.mMmsPort) + && Objects.equals(mPort, other.mPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mTypes, other.mTypes) + && Objects.equals(mTypesBitmap, other.mTypesBitmap) + && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mModemCognitive, other.mModemCognitive) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtu, other.mMtu) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData); + } + + /** + * Check if neither mention DUN and are substantially similar + * + * @param other The other APN settings to compare + * @return True if two APN settings are similar + * @hide + */ + public boolean similar(ApnSetting other) { + return (!this.canHandleType(TYPE_DUN) + && !other.canHandleType(TYPE_DUN) + && Objects.equals(this.mApnName, other.mApnName) + && !typeSameAny(this, other) + && xorEqualsInetAddress(this.mProxy, other.mProxy) + && xorEqualsPort(this.mPort, other.mPort) + && xorEquals(this.mProtocol, other.mProtocol) + && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(this.mBearerBitmask, other.mBearerBitmask) + && Objects.equals(this.mProfileId, other.mProfileId) + && Objects.equals(this.mMvnoType, other.mMvnoType) + && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) + && xorEqualsURL(this.mMmsc, other.mMmsc) + && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy) + && xorEqualsPort(this.mMmsPort, other.mMmsPort)); + } + + // Equal or one is not specified. + private boolean xorEquals(String first, String second) { + return (Objects.equals(first, second) + || TextUtils.isEmpty(first) + || TextUtils.isEmpty(second)); + } + + // Equal or one is not specified. + private boolean xorEqualsInetAddress(InetAddress first, InetAddress second) { + return first == null || second == null || first.equals(second); + } + + // Equal or one is not specified. + private boolean xorEqualsURL(URL first, URL second) { + return first == null || second == null || first.equals(second); + } + + // Equal or one is not specified. + private boolean xorEqualsPort(int first, int second) { + return first == -1 || second == -1 || Objects.equals(first, second); + } + + // Helper function to convert APN string into a 32-bit bitmask. + private static int getApnBitmask(String apn) { + switch (apn) { + case TYPE_DEFAULT: return ApnTypes.DEFAULT; + case TYPE_MMS: return ApnTypes.MMS; + case TYPE_SUPL: return ApnTypes.SUPL; + case TYPE_DUN: return ApnTypes.DUN; + case TYPE_HIPRI: return ApnTypes.HIPRI; + case TYPE_FOTA: return ApnTypes.FOTA; + case TYPE_IMS: return ApnTypes.IMS; + case TYPE_CBS: return ApnTypes.CBS; + case TYPE_IA: return ApnTypes.IA; + case TYPE_EMERGENCY: return ApnTypes.EMERGENCY; + case TYPE_ALL: return ApnTypes.ALL; + default: return ApnTypes.NONE; + } + } + + private String deParseTypes(List<String> types) { + if (types == null) { + return null; + } + return TextUtils.join(",", types); + } + + /** @hide */ + // Called by DPM. + public ContentValues toContentValues() { + ContentValues apnValue = new ContentValues(); + if (mOperatorNumeric != null) { + apnValue.put(Telephony.Carriers.NUMERIC, mOperatorNumeric); + } + if (mEntryName != null) { + apnValue.put(Telephony.Carriers.NAME, mEntryName); + } + if (mApnName != null) { + apnValue.put(Telephony.Carriers.APN, mApnName); + } + if (mProxy != null) { + apnValue.put(Telephony.Carriers.PROXY, inetAddressToString(mProxy)); + } + apnValue.put(Telephony.Carriers.PORT, portToString(mPort)); + if (mMmsc != null) { + apnValue.put(Telephony.Carriers.MMSC, URLToString(mMmsc)); + } + apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort)); + if (mMmsProxy != null) { + apnValue.put(Telephony.Carriers.MMSPROXY, inetAddressToString(mMmsProxy)); + } + if (mUser != null) { + apnValue.put(Telephony.Carriers.USER, mUser); + } + if (mPassword != null) { + apnValue.put(Telephony.Carriers.PASSWORD, mPassword); + } + apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType); + String apnType = deParseTypes(mTypes); + if (apnType != null) { + apnValue.put(Telephony.Carriers.TYPE, apnType); + } + if (mProtocol != null) { + apnValue.put(Telephony.Carriers.PROTOCOL, mProtocol); + } + if (mRoamingProtocol != null) { + apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, mRoamingProtocol); + } + apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled); + // networkTypeBit. + apnValue.put(Telephony.Carriers.BEARER_BITMASK, mBearerBitmask); + if (mMvnoType != null) { + apnValue.put(Telephony.Carriers.MVNO_TYPE, mMvnoType); + } + + return apnValue; + } + + /** + * @param types comma delimited list of APN types + * @return array of APN types + * @hide + */ + public static String[] parseTypes(String types) { + String[] result; + // If unset, set to DEFAULT. + if (TextUtils.isEmpty(types)) { + result = new String[1]; + result[0] = TYPE_ALL; + } else { + result = types.split(","); + } + return result; + } + + private static URL URLFromString(String url) { + try { + return TextUtils.isEmpty(url) ? null : new URL(url); + } catch (MalformedURLException e) { + Log.e(LOG_TAG, "Can't parse URL from string."); + return null; + } + } + + private static String URLToString(URL url) { + return url == null ? "" : url.toString(); + } + + private static InetAddress inetAddressFromString(String inetAddress) { + if (TextUtils.isEmpty(inetAddress)) { + return null; + } + try { + return InetAddress.getByName(inetAddress); + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "Can't parse InetAddress from string: unknown host."); + return null; + } + } + + private static String inetAddressToString(InetAddress inetAddress) { + if (inetAddress == null) { + return null; + } + return TextUtils.isEmpty(inetAddress.getHostName()) + ? inetAddress.getHostAddress() : inetAddress.getHostName(); + } + + private static int portFromString(String strPort) { + int port = -1; + if (!TextUtils.isEmpty(strPort)) { + try { + port = Integer.parseInt(strPort); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Can't parse port from String"); + } + } + return port; + } + + private static String portToString(int port) { + return port == -1 ? "" : Integer.toString(port); + } + + // Implement Parcelable. + @Override + /** @hide */ + public int describeContents() { + return 0; + } + + @Override + /** @hide */ + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mId); + dest.writeString(mOperatorNumeric); + dest.writeString(mEntryName); + dest.writeString(mApnName); + dest.writeValue(mProxy); + dest.writeInt(mPort); + dest.writeValue(mMmsc); + dest.writeValue(mMmsProxy); + dest.writeInt(mMmsPort); + dest.writeString(mUser); + dest.writeString(mPassword); + dest.writeInt(mAuthType); + dest.writeStringArray(mTypes.toArray(new String[0])); + dest.writeString(mProtocol); + dest.writeString(mRoamingProtocol); + dest.writeInt(mCarrierEnabled ? 1: 0); + dest.writeString(mMvnoType); + } + + private static ApnSetting readFromParcel(Parcel in) { + return makeApnSetting(in.readInt(), in.readString(), in.readString(), in.readString(), + (InetAddress)in.readValue(InetAddress.class.getClassLoader()), + in.readInt(), (URL)in.readValue(URL.class.getClassLoader()), + (InetAddress)in.readValue(InetAddress.class.getClassLoader()), + in.readInt(), in.readString(), in.readString(), in.readInt(), + Arrays.asList(in.readStringArray()), in.readString(), in.readString(), + in.readInt() > 0, 0, 0, 0, false, 0, 0, 0, 0, in.readString(), null); + } + + public static final Parcelable.Creator<ApnSetting> CREATOR = + new Parcelable.Creator<ApnSetting>() { + @Override + public ApnSetting createFromParcel(Parcel in) { + return readFromParcel(in); + } + + @Override + public ApnSetting[] newArray(int size) { + return new ApnSetting[size]; + } + }; + + /** + * APN types for data connections. These are usage categories for an APN + * entry. One APN entry may support multiple APN types, eg, a single APN + * may service regular internet traffic ("default") as well as MMS-specific + * connections.<br/> + * ALL is a special type to indicate that this APN entry can + * service all data connections. + */ + public static final String TYPE_ALL = "*"; + /** APN type for default data traffic */ + public static final String TYPE_DEFAULT = "default"; + /** APN type for MMS traffic */ + public static final String TYPE_MMS = "mms"; + /** APN type for SUPL assisted GPS */ + public static final String TYPE_SUPL = "supl"; + /** APN type for DUN traffic */ + public static final String TYPE_DUN = "dun"; + /** APN type for HiPri traffic */ + public static final String TYPE_HIPRI = "hipri"; + /** APN type for FOTA */ + public static final String TYPE_FOTA = "fota"; + /** APN type for IMS */ + public static final String TYPE_IMS = "ims"; + /** APN type for CBS */ + public static final String TYPE_CBS = "cbs"; + /** APN type for IA Initial Attach APN */ + public static final String TYPE_IA = "ia"; + /** APN type for Emergency PDN. This is not an IA apn, but is used + * for access to carrier services in an emergency call situation. */ + public static final String TYPE_EMERGENCY = "emergency"; + /** + * Array of all APN types + * + * @hide + */ + public static final String[] ALL_TYPES = { + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY + }; + + // Possible values for authentication types. + public static final int AUTH_TYPE_NONE = 0; + public static final int AUTH_TYPE_PAP = 1; + public static final int AUTH_TYPE_CHAP = 2; + public static final int AUTH_TYPE_PAP_OR_CHAP = 3; + + // Possible values for protocol. + public static final String PROTOCOL_IP = "IP"; + public static final String PROTOCOL_IPV6 = "IPV6"; + public static final String PROTOCOL_IPV4V6 = "IPV4V6"; + public static final String PROTOCOL_PPP = "PPP"; + + // Possible values for MVNO type. + public static final String MVNO_TYPE_SPN = "spn"; + public static final String MVNO_TYPE_IMSI = "imsi"; + public static final String MVNO_TYPE_GID = "gid"; + public static final String MVNO_TYPE_ICCID = "iccid"; + + public static class Builder{ + private String mEntryName; + private String mApnName; + private InetAddress mProxy; + private int mPort = -1; + private URL mMmsc; + private InetAddress mMmsProxy; + private int mMmsPort = -1; + private String mUser; + private String mPassword; + private int mAuthType; + private List<String> mTypes; + private int mTypesBitmap; + private int mId; + private String mOperatorNumeric; + private String mProtocol; + private String mRoamingProtocol; + private int mMtu; + private boolean mCarrierEnabled; + private int mBearer; + private int mBearerBitmask; + private int mProfileId; + private boolean mModemCognitive; + private int mMaxConns; + private int mWaitTime; + private int mMaxConnsTime; + private String mMvnoType; + private String mMvnoMatchData; + + /** + * Default constructor for Builder. + */ + public Builder() {} + + /** + * Set the MTU size of the mobile interface to which the APN connected. + * + * @param mtu the MTU size to set for the APN + * @hide + */ + public Builder setMtu(int mtu) { + this.mMtu = mtu; + return this; + } + + /** + * Sets bearer info. + * + * @param bearer the bearer info to set for the APN + * @hide + */ + public Builder setBearer(int bearer) { + this.mBearer = bearer; + return this; + } + + /** + * Sets the radio access technology bitmask for this APN. + * + * @param bearerBitmask the radio access technology bitmask to set for this APN + * @hide + */ + public Builder setBearerBitmask(int bearerBitmask) { + this.mBearerBitmask = bearerBitmask; + return this; + } + + /** + * Sets the profile id to which the APN saved in modem. + * + * @param profileId the profile id to set for the APN + * @hide + */ + public Builder setProfileId(int profileId) { + this.mProfileId = profileId; + return this; + } + + /** + * Sets if the APN setting is to be set in modem. + * + * @param modemCognitive if the APN setting is to be set in modem + * @hide + */ + public Builder setModemCognitive(boolean modemCognitive) { + this.mModemCognitive = modemCognitive; + return this; + } + + /** + * Sets the max connections of this APN. + * + * @param maxConns the max connections of this APN + * @hide + */ + public Builder setMaxConns(int maxConns) { + this.mMaxConns = maxConns; + return this; + } + + /** + * Sets the wait time for retry of the APN. + * + * @param waitTime the wait time for retry of the APN + * @hide + */ + public Builder setWaitTime(int waitTime) { + this.mWaitTime = waitTime; + return this; + } + + /** + * Sets the time to limit max connection for the APN. + * + * @param maxConnsTime the time to limit max connection for the APN + * @hide + */ + public Builder setMaxConnsTime(int maxConnsTime) { + this.mMaxConnsTime = maxConnsTime; + return this; + } + + /** + * Sets the MVNO match data for the APN. + * + * @param mvnoMatchData the MVNO match data for the APN + * @hide + */ + public Builder setMvnoMatchData(String mvnoMatchData) { + this.mMvnoMatchData = mvnoMatchData; + return this; + } + + /** + * Sets the entry name of the APN. + * + * @param entryName the entry name to set for the APN + */ + public Builder setEntryName(String entryName) { + this.mEntryName = entryName; + return this; + } + + /** + * Sets the name of the APN. + * + * @param apnName the name to set for the APN + */ + public Builder setApnName(String apnName) { + this.mApnName = apnName; + return this; + } + + /** + * Sets the proxy address of the APN. + * + * @param proxy the proxy address to set for the APN + */ + public Builder setProxy(InetAddress proxy) { + this.mProxy = proxy; + return this; + } + + /** + * Sets the proxy port of the APN. + * + * @param port the proxy port to set for the APN + */ + public Builder setPort(int port) { + this.mPort = port; + return this; + } + + /** + * Sets the MMSC URL of the APN. + * + * @param mmsc the MMSC URL to set for the APN + */ + public Builder setMmsc(URL mmsc) { + this.mMmsc = mmsc; + return this; + } + + /** + * Sets the MMS proxy address of the APN. + * + * @param mmsProxy the MMS proxy address to set for the APN + */ + public Builder setMmsProxy(InetAddress mmsProxy) { + this.mMmsProxy = mmsProxy; + return this; + } + + /** + * Sets the MMS proxy port of the APN. + * + * @param mmsPort the MMS proxy port to set for the APN + */ + public Builder setMmsPort(int mmsPort) { + this.mMmsPort = mmsPort; + return this; + } + + /** + * Sets the APN username of the APN. + * + * @param user the APN username to set for the APN + */ + public Builder setUser(String user) { + this.mUser = user; + return this; + } + + /** + * Sets the APN password of the APN. + * + * @see android.provider.Telephony.Carriers#PASSWORD + * @param password the APN password to set for the APN + */ + public Builder setPassword(String password) { + this.mPassword = password; + return this; + } + + /** + * Sets the authentication type of the APN. + * + * Example of possible values: {@link #AUTH_TYPE_NONE}, {@link #AUTH_TYPE_PAP}. + * + * @param authType the authentication type to set for the APN + */ + public Builder setAuthType(@AuthType int authType) { + this.mAuthType = authType; + return this; + } + + /** + * Sets the list of APN types of the APN. + * + * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}. + * + * @param types the list of APN types to set for the APN + */ + public Builder setTypes(@ApnType List<String> types) { + this.mTypes = types; + int apnBitmap = 0; + for (int i = 0; i < mTypes.size(); i++) { + mTypes.set(i, mTypes.get(i).toLowerCase()); + apnBitmap |= getApnBitmask(mTypes.get(i)); + } + this.mTypesBitmap = apnBitmap; + return this; + } + + /** + * Sets the unique database id for this entry. + * + * @param id the unique database id to set for this entry + */ + public Builder setId(int id) { + this.mId = id; + return this; + } + + /** + * Set the numeric operator ID for the APN. + * + * @param operatorNumeric the numeric operator ID to set for this entry + */ + public Builder setOperatorNumeric(String operatorNumeric) { + this.mOperatorNumeric = operatorNumeric; + return this; + } + + /** + * Sets the protocol to use to connect to this APN. + * + * One of the {@code PDP_type} values in TS 27.007 section 10.1.1. + * Example of possible values: {@link #PROTOCOL_IP}, {@link #PROTOCOL_IPV6}. + * + * @param protocol the protocol to set to use to connect to this APN + */ + public Builder setProtocol(@ProtocolType String protocol) { + this.mProtocol = protocol; + return this; + } + + /** + * Sets the protocol to use to connect to this APN when roaming. + * + * @param roamingProtocol the protocol to set to use to connect to this APN when roaming + */ + public Builder setRoamingProtocol(String roamingProtocol) { + this.mRoamingProtocol = roamingProtocol; + return this; + } + + /** + * Sets the current status of APN. + * + * @param carrierEnabled the current status to set for this APN + */ + public Builder setCarrierEnabled(boolean carrierEnabled) { + this.mCarrierEnabled = carrierEnabled; + return this; + } + + /** + * Sets the MVNO match type for this APN. + * + * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}. + * + * @param mvnoType the MVNO match type to set for this APN + */ + public Builder setMvnoType(@MvnoType String mvnoType) { + this.mMvnoType = mvnoType; + return this; + } + + public ApnSetting build() { + return new ApnSetting(this); + } + } +} + diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index da51c86151d2..ef3a183f7800 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -20,6 +20,7 @@ package android.telephony.data; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.LinkAddress; import android.os.Parcel; import android.os.Parcelable; @@ -40,7 +41,7 @@ public final class DataCallResponse implements Parcelable { private final int mActive; private final String mType; private final String mIfname; - private final List<InterfaceAddress> mAddresses; + private final List<LinkAddress> mAddresses; private final List<InetAddress> mDnses; private final List<InetAddress> mGateways; private final List<String> mPcscfs; @@ -71,7 +72,7 @@ public final class DataCallResponse implements Parcelable { */ public DataCallResponse(int status, int suggestedRetryTime, int cid, int active, @Nullable String type, @Nullable String ifname, - @Nullable List<InterfaceAddress> addresses, + @Nullable List<LinkAddress> addresses, @Nullable List<InetAddress> dnses, @Nullable List<InetAddress> gateways, @Nullable List<String> pcscfs, int mtu) { @@ -96,7 +97,7 @@ public final class DataCallResponse implements Parcelable { mType = source.readString(); mIfname = source.readString(); mAddresses = new ArrayList<>(); - source.readList(mAddresses, InterfaceAddress.class.getClassLoader()); + source.readList(mAddresses, LinkAddress.class.getClassLoader()); mDnses = new ArrayList<>(); source.readList(mDnses, InetAddress.class.getClassLoader()); mGateways = new ArrayList<>(); @@ -140,10 +141,10 @@ public final class DataCallResponse implements Parcelable { public String getIfname() { return mIfname; } /** - * @return A list of {@link InterfaceAddress} + * @return A list of {@link LinkAddress} */ @NonNull - public List<InterfaceAddress> getAddresses() { return mAddresses; } + public List<LinkAddress> getAddresses() { return mAddresses; } /** * @return A list of DNS server addresses, e.g., "192.0.1.3" or diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java new file mode 100644 index 000000000000..ea0817551369 --- /dev/null +++ b/telephony/java/android/telephony/data/DataService.java @@ -0,0 +1,540 @@ +/* + * Copyright 2017 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.data; + +import android.annotation.CallSuper; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.net.LinkProperties; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telephony.AccessNetworkConstants; +import android.telephony.Rlog; +import android.telephony.SubscriptionManager; +import android.util.SparseArray; + +import java.util.ArrayList; +import java.util.List; + +/** + * Base class of data service. Services that extend DataService must register the service in + * their AndroidManifest to be detected by the framework. They must be protected by the permission + * "android.permission.BIND_DATA_SERVICE". The data service definition in the manifest must follow + * the following format: + * ... + * <service android:name=".xxxDataService" + * android:permission="android.permission.BIND_DATA_SERVICE" > + * <intent-filter> + * <action android:name="android.telephony.data.DataService" /> + * </intent-filter> + * </service> + * @hide + */ +@SystemApi +public abstract class DataService extends Service { + private static final String TAG = DataService.class.getSimpleName(); + + public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService"; + public static final String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID"; + + private static final int DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE = 1; + private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL = 2; + private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL = 3; + private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN = 4; + private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE = 5; + private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST = 6; + private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED = 7; + private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED = 8; + private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED = 9; + + private final HandlerThread mHandlerThread; + + private final DataServiceHandler mHandler; + + private final SparseArray<DataServiceProvider> mServiceMap = new SparseArray<>(); + + private final SparseArray<IDataServiceWrapper> mBinderMap = new SparseArray<>(); + + /** + * The abstract class of the actual data service implementation. The data service provider + * must extend this class to support data connection. Note that each instance of data service + * provider is associated with one physical SIM slot. + */ + public class DataServiceProvider { + + private final int mSlotId; + + private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>(); + + /** + * Constructor + * @param slotId SIM slot id the data service provider associated with. + */ + public DataServiceProvider(int slotId) { + mSlotId = slotId; + } + + /** + * @return SIM slot id the data service provider associated with. + */ + public final int getSlotId() { + return mSlotId; + } + + /** + * Setup a data connection. The data service provider must implement this method to support + * establishing a packet data connection. When completed or error, the service must invoke + * the provided callback to notify the platform. + * + * @param accessNetworkType Access network type that the data call will be established on. + * Must be one of {@link AccessNetworkConstants.AccessNetworkType}. + * @param dataProfile Data profile used for data call setup. See {@link DataProfile} + * @param isRoaming True if the device is data roaming. + * @param allowRoaming True if data roaming is allowed by the user. + * @param isHandover True if the request is for IWLAN handover. + * @param linkProperties If {@code isHandover} is true, this is the link properties of the + * existing data connection, otherwise null. + * @param callback The result callback for this request. + */ + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, + boolean allowRoaming, boolean isHandover, + LinkProperties linkProperties, DataServiceCallback callback) { + // The default implementation is to return unsupported. + callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null); + } + + /** + * Deactivate a data connection. The data service provider must implement this method to + * support data connection tear down. When completed or error, the service must invoke the + * provided callback to notify the platform. + * + * @param cid Call id returned in the callback of {@link DataServiceProvider#setupDataCall( + * int, DataProfile, boolean, boolean, boolean, LinkProperties, DataServiceCallback)}. + * @param reasonRadioShutDown True if the deactivate request reason is device shut down. + * @param isHandover True if the request is for IWLAN handover. + * @param callback The result callback for this request. + */ + public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, + DataServiceCallback callback) { + // The default implementation is to return unsupported. + callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } + + /** + * Set an APN to initial attach network. + * + * @param dataProfile Data profile used for data call setup. See {@link DataProfile}. + * @param isRoaming True if the device is data roaming. + * @param callback The result callback for this request. + */ + public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, + DataServiceCallback callback) { + // The default implementation is to return unsupported. + callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } + + /** + * Send current carrier's data profiles to the data service for data call setup. This is + * only for CDMA carrier that can change the profile through OTA. The data service should + * always uses the latest data profile sent by the framework. + * + * @param dps A list of data profiles. + * @param isRoaming True if the device is data roaming. + * @param callback The result callback for this request. + */ + public void setDataProfile(List<DataProfile> dps, boolean isRoaming, + DataServiceCallback callback) { + // The default implementation is to return unsupported. + callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } + + /** + * Get the active data call list. + * + * @param callback The result callback for this request. + */ + public void getDataCallList(DataServiceCallback callback) { + // The default implementation is to return unsupported. + callback.onGetDataCallListComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null); + } + + private void registerForDataCallListChanged(IDataServiceCallback callback) { + synchronized (mDataCallListChangedCallbacks) { + mDataCallListChangedCallbacks.add(callback); + } + } + + private void unregisterForDataCallListChanged(IDataServiceCallback callback) { + synchronized (mDataCallListChangedCallbacks) { + mDataCallListChangedCallbacks.remove(callback); + } + } + + /** + * Notify the system that current data call list changed. Data service must invoke this + * method whenever there is any data call status changed. + * + * @param dataCallList List of the current active data call. + */ + public final void notifyDataCallListChanged(List<DataCallResponse> dataCallList) { + synchronized (mDataCallListChangedCallbacks) { + for (IDataServiceCallback callback : mDataCallListChangedCallbacks) { + mHandler.obtainMessage(DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED, mSlotId, + 0, new DataCallListChangedIndication(dataCallList, callback)) + .sendToTarget(); + } + } + } + + /** + * Called when the instance of data service is destroyed (e.g. got unbind or binder died). + */ + @CallSuper + protected void onDestroy() { + mDataCallListChangedCallbacks.clear(); + } + } + + private static final class SetupDataCallRequest { + public final int accessNetworkType; + public final DataProfile dataProfile; + public final boolean isRoaming; + public final boolean allowRoaming; + public final boolean isHandover; + public final LinkProperties linkProperties; + public final IDataServiceCallback callback; + SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, + boolean allowRoaming, boolean isHandover, + LinkProperties linkProperties, IDataServiceCallback callback) { + this.accessNetworkType = accessNetworkType; + this.dataProfile = dataProfile; + this.isRoaming = isRoaming; + this.allowRoaming = allowRoaming; + this.linkProperties = linkProperties; + this.isHandover = isHandover; + this.callback = callback; + } + } + + private static final class DeactivateDataCallRequest { + public final int cid; + public final boolean reasonRadioShutDown; + public final boolean isHandover; + public final IDataServiceCallback callback; + DeactivateDataCallRequest(int cid, boolean reasonRadioShutDown, boolean isHandover, + IDataServiceCallback callback) { + this.cid = cid; + this.reasonRadioShutDown = reasonRadioShutDown; + this.isHandover = isHandover; + this.callback = callback; + } + } + + private static final class SetInitialAttachApnRequest { + public final DataProfile dataProfile; + public final boolean isRoaming; + public final IDataServiceCallback callback; + SetInitialAttachApnRequest(DataProfile dataProfile, boolean isRoaming, + IDataServiceCallback callback) { + this.dataProfile = dataProfile; + this.isRoaming = isRoaming; + this.callback = callback; + } + } + + private static final class SetDataProfileRequest { + public final List<DataProfile> dps; + public final boolean isRoaming; + public final IDataServiceCallback callback; + SetDataProfileRequest(List<DataProfile> dps, boolean isRoaming, + IDataServiceCallback callback) { + this.dps = dps; + this.isRoaming = isRoaming; + this.callback = callback; + } + } + + private static final class DataCallListChangedIndication { + public final List<DataCallResponse> dataCallList; + public final IDataServiceCallback callback; + DataCallListChangedIndication(List<DataCallResponse> dataCallList, + IDataServiceCallback callback) { + this.dataCallList = dataCallList; + this.callback = callback; + } + } + + private class DataServiceHandler extends Handler { + + DataServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + IDataServiceCallback callback; + final int slotId = message.arg1; + DataServiceProvider service; + + synchronized (mServiceMap) { + service = mServiceMap.get(slotId); + } + + switch (message.what) { + case DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE: + service = createDataServiceProvider(message.arg1); + if (service != null) { + mServiceMap.put(slotId, service); + } + break; + case DATA_SERVICE_REQUEST_SETUP_DATA_CALL: + if (service == null) break; + SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj; + service.setupDataCall(setupDataCallRequest.accessNetworkType, + setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming, + setupDataCallRequest.allowRoaming, setupDataCallRequest.isHandover, + setupDataCallRequest.linkProperties, + new DataServiceCallback(setupDataCallRequest.callback)); + + break; + case DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL: + if (service == null) break; + DeactivateDataCallRequest deactivateDataCallRequest = + (DeactivateDataCallRequest) message.obj; + service.deactivateDataCall(deactivateDataCallRequest.cid, + deactivateDataCallRequest.reasonRadioShutDown, + deactivateDataCallRequest.isHandover, + new DataServiceCallback(deactivateDataCallRequest.callback)); + break; + case DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN: + if (service == null) break; + SetInitialAttachApnRequest setInitialAttachApnRequest = + (SetInitialAttachApnRequest) message.obj; + service.setInitialAttachApn(setInitialAttachApnRequest.dataProfile, + setInitialAttachApnRequest.isRoaming, + new DataServiceCallback(setInitialAttachApnRequest.callback)); + break; + case DATA_SERVICE_REQUEST_SET_DATA_PROFILE: + if (service == null) break; + SetDataProfileRequest setDataProfileRequest = + (SetDataProfileRequest) message.obj; + service.setDataProfile(setDataProfileRequest.dps, + setDataProfileRequest.isRoaming, + new DataServiceCallback(setDataProfileRequest.callback)); + break; + case DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST: + if (service == null) break; + + service.getDataCallList(new DataServiceCallback( + (IDataServiceCallback) message.obj)); + break; + case DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED: + if (service == null) break; + service.registerForDataCallListChanged((IDataServiceCallback) message.obj); + break; + case DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED: + if (service == null) break; + callback = (IDataServiceCallback) message.obj; + service.unregisterForDataCallListChanged(callback); + break; + case DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED: + if (service == null) break; + DataCallListChangedIndication indication = + (DataCallListChangedIndication) message.obj; + try { + indication.callback.onDataCallListChanged(indication.dataCallList); + } catch (RemoteException e) { + loge("Failed to call onDataCallListChanged. " + e); + } + break; + } + } + } + + private DataService() { + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + + mHandler = new DataServiceHandler(mHandlerThread.getLooper()); + log("Data service created"); + } + + /** + * Create the instance of {@link DataServiceProvider}. Data service provider must override + * this method to facilitate the creation of {@link DataServiceProvider} instances. The system + * will call this method after binding the data service for each active SIM slot id. + * + * @param slotId SIM slot id the data service associated with. + * @return Data service object + */ + public abstract DataServiceProvider createDataServiceProvider(int slotId); + + /** @hide */ + @Override + public IBinder onBind(Intent intent) { + if (intent == null || !DATA_SERVICE_INTERFACE.equals(intent.getAction())) { + loge("Unexpected intent " + intent); + return null; + } + + int slotId = intent.getIntExtra( + DATA_SERVICE_EXTRA_SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX); + + if (!SubscriptionManager.isValidSlotIndex(slotId)) { + loge("Invalid slot id " + slotId); + return null; + } + + log("onBind: slot id=" + slotId); + + IDataServiceWrapper binder = mBinderMap.get(slotId); + if (binder == null) { + Message msg = mHandler.obtainMessage(DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE); + msg.arg1 = slotId; + msg.sendToTarget(); + + binder = new IDataServiceWrapper(slotId); + mBinderMap.put(slotId, binder); + } + + return binder; + } + + /** @hide */ + @Override + public boolean onUnbind(Intent intent) { + int slotId = intent.getIntExtra(DATA_SERVICE_EXTRA_SLOT_ID, + SubscriptionManager.INVALID_SIM_SLOT_INDEX); + if (mBinderMap.get(slotId) != null) { + DataServiceProvider serviceImpl; + synchronized (mServiceMap) { + serviceImpl = mServiceMap.get(slotId); + } + if (serviceImpl != null) { + serviceImpl.onDestroy(); + } + mBinderMap.remove(slotId); + } + + // If all clients unbinds, quit the handler thread + if (mBinderMap.size() == 0) { + mHandlerThread.quit(); + } + + return false; + } + + /** @hide */ + @Override + public void onDestroy() { + synchronized (mServiceMap) { + for (int i = 0; i < mServiceMap.size(); i++) { + DataServiceProvider serviceImpl = mServiceMap.get(i); + if (serviceImpl != null) { + serviceImpl.onDestroy(); + } + } + mServiceMap.clear(); + } + + mHandlerThread.quit(); + } + + /** + * A wrapper around IDataService that forwards calls to implementations of {@link DataService}. + */ + private class IDataServiceWrapper extends IDataService.Stub { + + private final int mSlotId; + + IDataServiceWrapper(int slotId) { + mSlotId = slotId; + } + + @Override + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, + boolean isRoaming, boolean allowRoaming, boolean isHandover, + LinkProperties linkProperties, IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, mSlotId, 0, + new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming, + allowRoaming, isHandover, linkProperties, callback)) + .sendToTarget(); + } + + @Override + public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, + IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, mSlotId, 0, + new DeactivateDataCallRequest(cid, reasonRadioShutDown, isHandover, callback)) + .sendToTarget(); + } + + @Override + public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, + IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN, mSlotId, 0, + new SetInitialAttachApnRequest(dataProfile, isRoaming, callback)) + .sendToTarget(); + } + + @Override + public void setDataProfile(List<DataProfile> dps, boolean isRoaming, + IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_DATA_PROFILE, mSlotId, 0, + new SetDataProfileRequest(dps, isRoaming, callback)).sendToTarget(); + } + + @Override + public void getDataCallList(IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, mSlotId, 0, + callback).sendToTarget(); + } + + @Override + public void registerForDataCallListChanged(IDataServiceCallback callback) { + if (callback == null) { + loge("Callback is null"); + return; + } + mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED, mSlotId, + 0, callback).sendToTarget(); + } + + @Override + public void unregisterForDataCallListChanged(IDataServiceCallback callback) { + if (callback == null) { + loge("Callback is null"); + return; + } + mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED, mSlotId, + 0, callback).sendToTarget(); + } + } + + private void log(String s) { + Rlog.d(TAG, s); + } + + private void loge(String s) { + Rlog.e(TAG, s); + } +} diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java new file mode 100644 index 000000000000..b6a81f94028b --- /dev/null +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -0,0 +1,172 @@ +/* + * Copyright 2017 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.data; + +import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.os.RemoteException; +import android.telephony.Rlog; +import android.telephony.data.DataService.DataServiceProvider; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; +import java.util.List; + +/** + * Data service callback, which is for bound data service to invoke for solicited and unsolicited + * response. The caller is responsible to create a callback object for each single asynchronous + * request. + * + * @hide + */ +@SystemApi +public class DataServiceCallback { + + private static final String mTag = DataServiceCallback.class.getSimpleName(); + + /** + * Result of data requests + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY, + RESULT_ERROR_ILLEGAL_STATE}) + public @interface Result {} + + /** Request is completed successfully */ + public static final int RESULT_SUCCESS = 0; + /** Request is not support */ + public static final int RESULT_ERROR_UNSUPPORTED = 1; + /** Request contains invalid arguments */ + public static final int RESULT_ERROR_INVALID_ARG = 2; + /** Service is busy */ + public static final int RESULT_ERROR_BUSY = 3; + /** Request sent in illegal state */ + public static final int RESULT_ERROR_ILLEGAL_STATE = 4; + + private final WeakReference<IDataServiceCallback> mCallback; + + /** @hide */ + public DataServiceCallback(IDataServiceCallback callback) { + mCallback = new WeakReference<>(callback); + } + + /** + * Called to indicate result for the request {@link DataServiceProvider#setupDataCall(int, + * DataProfile, boolean, boolean, boolean, DataServiceCallback)}. + * + * @param result The result code. Must be one of the {@link Result}. + * @param response Setup data call response. + */ + public void onSetupDataCallComplete(@Result int result, DataCallResponse response) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onSetupDataCallComplete(result, response); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onSetupDataCallComplete on the remote"); + } + } + } + + /** + * Called to indicate result for the request {@link DataServiceProvider#deactivateDataCall(int, + * boolean, boolean, DataServiceCallback)}. + * + * @param result The result code. Must be one of the {@link Result}. + */ + public void onDeactivateDataCallComplete(@Result int result) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onDeactivateDataCallComplete(result); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onDeactivateDataCallComplete on the remote"); + } + } + } + + /** + * Called to indicate result for the request {@link DataServiceProvider#setInitialAttachApn( + * DataProfile, boolean, DataServiceCallback)}. + * + * @param result The result code. Must be one of the {@link Result}. + */ + public void onSetInitialAttachApnComplete(@Result int result) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onSetInitialAttachApnComplete(result); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onSetInitialAttachApnComplete on the remote"); + } + } + } + + /** + * Called to indicate result for the request {@link DataServiceProvider#setDataProfile(List, + * boolean, DataServiceCallback)}. + * + * @param result The result code. Must be one of the {@link Result}. + */ + @SystemApi + public void onSetDataProfileComplete(@Result int result) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onSetDataProfileComplete(result); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onSetDataProfileComplete on the remote"); + } + } + } + + /** + * Called to indicate result for the request {@link DataServiceProvider#getDataCallList( + * DataServiceCallback)}. + * + * @param result The result code. Must be one of the {@link Result}. + * @param dataCallList List of the current active data connection. + */ + public void onGetDataCallListComplete(@Result int result, List<DataCallResponse> dataCallList) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onGetDataCallListComplete(result, dataCallList); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onGetDataCallListComplete on the remote"); + } + } + } + + /** + * Called to indicate that data connection list changed. + * + * @param dataCallList List of the current active data connection. + */ + public void onDataCallListChanged(List<DataCallResponse> dataCallList) { + IDataServiceCallback callback = mCallback.get(); + if (callback != null) { + try { + callback.onDataCallListChanged(dataCallList); + } catch (RemoteException e) { + Rlog.e(mTag, "Failed to onDataCallListChanged on the remote"); + } + } + } +} diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl new file mode 100644 index 000000000000..4eaaa252da02 --- /dev/null +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -0,0 +1,39 @@ +/* + * Copyright 2017 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.data; + +import android.net.LinkProperties; +import android.telephony.data.DataProfile; +import android.telephony.data.IDataServiceCallback; + +/** + * {@hide} + */ +oneway interface IDataService +{ + void setupDataCall(int accessNetwork, in DataProfile dataProfile, boolean isRoaming, + boolean allowRoaming, boolean isHandover, in LinkProperties linkProperties, + IDataServiceCallback callback); + void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, + IDataServiceCallback callback); + void setInitialAttachApn(in DataProfile dataProfile, boolean isRoaming, + IDataServiceCallback callback); + void setDataProfile(in List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback); + void getDataCallList(IDataServiceCallback callback); + void registerForDataCallListChanged(IDataServiceCallback callback); + void unregisterForDataCallListChanged(IDataServiceCallback callback); +} diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl new file mode 100644 index 000000000000..856185b2974f --- /dev/null +++ b/telephony/java/android/telephony/data/IDataServiceCallback.aidl @@ -0,0 +1,33 @@ +/* + * Copyright 2017 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.data; + +import android.telephony.data.DataCallResponse; + +/** + * The call back interface + * @hide + */ +oneway interface IDataServiceCallback +{ + void onSetupDataCallComplete(int result, in DataCallResponse dataCallResponse); + void onDeactivateDataCallComplete(int result); + void onSetInitialAttachApnComplete(int result); + void onSetDataProfileComplete(int result); + void onGetDataCallListComplete(int result, in List<DataCallResponse> dataCallList); + void onDataCallListChanged(in List<DataCallResponse> dataCallList); +} diff --git a/telephony/java/android/telephony/data/InterfaceAddress.java b/telephony/java/android/telephony/data/InterfaceAddress.java deleted file mode 100644 index 00d212a54c6f..000000000000 --- a/telephony/java/android/telephony/data/InterfaceAddress.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2017 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.data; - -import android.annotation.SystemApi; -import android.net.NetworkUtils; -import android.os.Parcel; -import android.os.Parcelable; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * This class represents a Network Interface address. In short it's an IP address, a subnet mask - * when the address is an IPv4 one. An IP address and a network prefix length in the case of IPv6 - * address. - * - * @hide - */ -@SystemApi -public final class InterfaceAddress implements Parcelable { - - private final InetAddress mInetAddress; - - private final int mPrefixLength; - - /** - * @param inetAddress A {@link InetAddress} of the address - * @param prefixLength The network prefix length for this address. - */ - public InterfaceAddress(InetAddress inetAddress, int prefixLength) { - mInetAddress = inetAddress; - mPrefixLength = prefixLength; - } - - /** - * @param address The address in string format - * @param prefixLength The network prefix length for this address. - * @throws UnknownHostException - */ - public InterfaceAddress(String address, int prefixLength) throws UnknownHostException { - InetAddress ia; - try { - ia = NetworkUtils.numericToInetAddress(address); - } catch (IllegalArgumentException e) { - throw new UnknownHostException("Non-numeric ip addr=" + address); - } - mInetAddress = ia; - mPrefixLength = prefixLength; - } - - public InterfaceAddress(Parcel source) { - mInetAddress = (InetAddress) source.readSerializable(); - mPrefixLength = source.readInt(); - } - - /** - * @return an InetAddress for this address. - */ - public InetAddress getAddress() { return mInetAddress; } - - /** - * @return The network prefix length for this address. - */ - public int getNetworkPrefixLength() { return mPrefixLength; } - - @Override - public boolean equals (Object o) { - if (this == o) return true; - - if (o == null || !(o instanceof InterfaceAddress)) { - return false; - } - - InterfaceAddress other = (InterfaceAddress) o; - return this.mInetAddress.equals(other.mInetAddress) - && this.mPrefixLength == other.mPrefixLength; - } - - @Override - public int hashCode() { - return mInetAddress.hashCode() * 31 + mPrefixLength * 37; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public String toString() { - return mInetAddress + "/" + mPrefixLength; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeSerializable(mInetAddress); - dest.writeInt(mPrefixLength); - } - - public static final Parcelable.Creator<InterfaceAddress> CREATOR = - new Parcelable.Creator<InterfaceAddress>() { - @Override - public InterfaceAddress createFromParcel(Parcel source) { - return new InterfaceAddress(source); - } - - @Override - public InterfaceAddress[] newArray(int size) { - return new InterfaceAddress[size]; - } - }; -} diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java new file mode 100644 index 000000000000..b9ed0059a39a --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2018 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.euicc; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.service.euicc.EuiccProfileInfo; +import android.util.Log; + +import com.android.internal.telephony.euicc.IAuthenticateServerCallback; +import com.android.internal.telephony.euicc.ICancelSessionCallback; +import com.android.internal.telephony.euicc.IDeleteProfileCallback; +import com.android.internal.telephony.euicc.IDisableProfileCallback; +import com.android.internal.telephony.euicc.IEuiccCardController; +import com.android.internal.telephony.euicc.IGetAllProfilesCallback; +import com.android.internal.telephony.euicc.IGetDefaultSmdpAddressCallback; +import com.android.internal.telephony.euicc.IGetEuiccChallengeCallback; +import com.android.internal.telephony.euicc.IGetEuiccInfo1Callback; +import com.android.internal.telephony.euicc.IGetEuiccInfo2Callback; +import com.android.internal.telephony.euicc.IGetProfileCallback; +import com.android.internal.telephony.euicc.IGetRulesAuthTableCallback; +import com.android.internal.telephony.euicc.IGetSmdsAddressCallback; +import com.android.internal.telephony.euicc.IListNotificationsCallback; +import com.android.internal.telephony.euicc.ILoadBoundProfilePackageCallback; +import com.android.internal.telephony.euicc.IPrepareDownloadCallback; +import com.android.internal.telephony.euicc.IRemoveNotificationFromListCallback; +import com.android.internal.telephony.euicc.IResetMemoryCallback; +import com.android.internal.telephony.euicc.IRetrieveNotificationCallback; +import com.android.internal.telephony.euicc.IRetrieveNotificationListCallback; +import com.android.internal.telephony.euicc.ISetDefaultSmdpAddressCallback; +import com.android.internal.telephony.euicc.ISetNicknameCallback; +import com.android.internal.telephony.euicc.ISwitchToProfileCallback; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * EuiccCardManager is the application interface to an eSIM card. + * + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ +public class EuiccCardManager { + private static final String TAG = "EuiccCardManager"; + + /** Reason for canceling a profile download session */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "CANCEL_REASON_" }, value = { + CANCEL_REASON_END_USER_REJECTED, + CANCEL_REASON_POSTPONED, + CANCEL_REASON_TIMEOUT, + CANCEL_REASON_PPR_NOT_ALLOWED + }) + public @interface CancelReason {} + + /** + * The end user has rejected the download. The profile will be put into the error state and + * cannot be downloaded again without the operator's change. + */ + public static final int CANCEL_REASON_END_USER_REJECTED = 0; + + /** The download has been postponed and can be restarted later. */ + public static final int CANCEL_REASON_POSTPONED = 1; + + /** The download has been timed out and can be restarted later. */ + public static final int CANCEL_REASON_TIMEOUT = 2; + + /** + * The profile to be downloaded cannot be installed due to its policy rule is not allowed by + * the RAT (Rules Authorisation Table) on the eUICC or by other installed profiles. The + * download can be restarted later. + */ + public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; + + /** Options for resetting eUICC memory */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "RESET_OPTION_" }, value = { + RESET_OPTION_DELETE_OPERATIONAL_PROFILES, + RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, + RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS + }) + public @interface ResetOption {} + + /** Deletes all operational profiles. */ + public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; + + /** Deletes all field-loaded testing profiles. */ + public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 1 << 1; + + /** Resets the default SM-DP+ address. */ + public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 1 << 2; + + /** Result code of execution with no error. */ + public static final int RESULT_OK = 0; + + /** + * Callback to receive the result of an eUICC card API. + * + * @param <T> Type of the result. + */ + public interface ResultCallback<T> { + /** + * This method will be called when an eUICC card API call is completed. + * + * @param resultCode This can be {@link #RESULT_OK} or other positive values returned by the + * eUICC. + * @param result The result object. It can be null if the {@code resultCode} is not + * {@link #RESULT_OK}. + */ + void onComplete(int resultCode, T result); + } + + private final Context mContext; + + /** @hide */ + public EuiccCardManager(Context context) { + mContext = context; + } + + private IEuiccCardController getIEuiccCardController() { + return IEuiccCardController.Stub.asInterface( + ServiceManager.getService("euicc_card_controller")); + } + + /** + * Gets all the profiles on eUicc. + * + * @param callback The callback to get the result code and all the profiles. + */ + public void getAllProfiles(ResultCallback<EuiccProfileInfo[]> callback) { + try { + getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(), + new IGetAllProfilesCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccProfileInfo[] profiles) { + callback.onComplete(resultCode, profiles); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getAllProfiles", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the profile of the given iccid. + * + * @param iccid The iccid of the profile. + * @param callback The callback to get the result code and profile. + */ + public void getProfile(String iccid, ResultCallback<EuiccProfileInfo> callback) { + try { + getIEuiccCardController().getProfile(mContext.getOpPackageName(), iccid, + new IGetProfileCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccProfileInfo profile) { + callback.onComplete(resultCode, profile); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getProfile", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Disables the profile of the given iccid. + * + * @param iccid The iccid of the profile. + * @param refresh Whether sending the REFRESH command to modem. + * @param callback The callback to get the result code. + */ + public void disableProfile(String iccid, boolean refresh, ResultCallback<Void> callback) { + try { + getIEuiccCardController().disableProfile(mContext.getOpPackageName(), iccid, refresh, + new IDisableProfileCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling disableProfile", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Switches from the current profile to another profile. The current profile will be disabled + * and the specified profile will be enabled. + * + * @param iccid The iccid of the profile to switch to. + * @param refresh Whether sending the REFRESH command to modem. + * @param callback The callback to get the result code and the EuiccProfileInfo enabled. + */ + public void switchToProfile(String iccid, boolean refresh, + ResultCallback<EuiccProfileInfo> callback) { + try { + getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), iccid, refresh, + new ISwitchToProfileCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccProfileInfo profile) { + callback.onComplete(resultCode, profile); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling switchToProfile", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the EID of the eUICC. + * + * @return The EID. + */ + public String getEid() { + try { + return getIEuiccCardController().getEid(); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getEid", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the nickname of the profile of the given iccid. + * + * @param iccid The iccid of the profile. + * @param nickname The nickname of the profile. + * @param callback The callback to get the result code. + */ + public void setNickname(String iccid, String nickname, ResultCallback<Void> callback) { + try { + getIEuiccCardController().setNickname(mContext.getOpPackageName(), iccid, nickname, + new ISetNicknameCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling setNickname", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Deletes the profile of the given iccid from eUICC. + * + * @param iccid The iccid of the profile. + * @param callback The callback to get the result code. + */ + public void deleteProfile(String iccid, ResultCallback<Void> callback) { + try { + getIEuiccCardController().deleteProfile(mContext.getOpPackageName(), iccid, + new IDeleteProfileCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling deleteProfile", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Resets the eUICC memory. + * + * @param options Bits of the options of resetting which parts of the eUICC memory. See + * EuiccCard for details. + * @param callback The callback to get the result code. + */ + public void resetMemory(@ResetOption int options, ResultCallback<Void> callback) { + try { + getIEuiccCardController().resetMemory(mContext.getOpPackageName(), options, + new IResetMemoryCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling resetMemory", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the default SM-DP+ address from eUICC. + * + * @param callback The callback to get the result code and the default SM-DP+ address. + */ + public void getDefaultSmdpAddress(ResultCallback<String> callback) { + try { + getIEuiccCardController().getDefaultSmdpAddress(mContext.getOpPackageName(), + new IGetDefaultSmdpAddressCallback.Stub() { + @Override + public void onComplete(int resultCode, String address) { + callback.onComplete(resultCode, address); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getDefaultSmdpAddress", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the SM-DS address from eUICC. + * + * @param callback The callback to get the result code and the SM-DS address. + */ + public void getSmdsAddress(ResultCallback<String> callback) { + try { + getIEuiccCardController().getSmdsAddress(mContext.getOpPackageName(), + new IGetSmdsAddressCallback.Stub() { + @Override + public void onComplete(int resultCode, String address) { + callback.onComplete(resultCode, address); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getSmdsAddress", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the default SM-DP+ address of eUICC. + * + * @param defaultSmdpAddress The default SM-DP+ address to set. + * @param callback The callback to get the result code. + */ + public void setDefaultSmdpAddress(String defaultSmdpAddress, ResultCallback<Void> callback) { + try { + getIEuiccCardController().setDefaultSmdpAddress(mContext.getOpPackageName(), + defaultSmdpAddress, + new ISetDefaultSmdpAddressCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling setDefaultSmdpAddress", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets Rules Authorisation Table. + * + * @param callback the callback to get the result code and the rule authorisation table. + */ + public void getRulesAuthTable(ResultCallback<EuiccRulesAuthTable> callback) { + try { + getIEuiccCardController().getRulesAuthTable(mContext.getOpPackageName(), + new IGetRulesAuthTableCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccRulesAuthTable rat) { + callback.onComplete(resultCode, rat); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getRulesAuthTable", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the eUICC challenge for new profile downloading. + * + * @param callback the callback to get the result code and the challenge. + */ + public void getEuiccChallenge(ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().getEuiccChallenge(mContext.getOpPackageName(), + new IGetEuiccChallengeCallback.Stub() { + @Override + public void onComplete(int resultCode, byte[] challenge) { + callback.onComplete(resultCode, challenge); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getEuiccChallenge", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading. + * + * @param callback the callback to get the result code and the info1. + */ + public void getEuiccInfo1(ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().getEuiccInfo1(mContext.getOpPackageName(), + new IGetEuiccInfo1Callback.Stub() { + @Override + public void onComplete(int resultCode, byte[] info) { + callback.onComplete(resultCode, info); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getEuiccInfo1", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading. + * + * @param callback the callback to get the result code and the info2. + */ + public void getEuiccInfo2(ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().getEuiccInfo2(mContext.getOpPackageName(), + new IGetEuiccInfo2Callback.Stub() { + @Override + public void onComplete(int resultCode, byte[] info) { + callback.onComplete(resultCode, info); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getEuiccInfo2", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Authenticates the SM-DP+ server by the eUICC. + * + * @param matchingId the activation code token defined in GSMA RSP v2.0+ or empty when it is not + * required. + * @param serverSigned1 ASN.1 data in byte array signed and returned by the SM-DP+ server. + * @param serverSignature1 ASN.1 data in byte array indicating a SM-DP+ signature which is + * returned by SM-DP+ server. + * @param euiccCiPkIdToBeUsed ASN.1 data in byte array indicating CI Public Key Identifier to be + * used by the eUICC for signature which is returned by SM-DP+ server. This is defined in + * GSMA RSP v2.0+. + * @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by + * SM-DP+ server. + * @param callback the callback to get the result code and a byte array which represents a + * {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+. + */ + public void authenticateServer(String matchingId, byte[] serverSigned1, + byte[] serverSignature1, byte[] euiccCiPkIdToBeUsed, byte[] serverCertificate, + ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().authenticateServer( + mContext.getOpPackageName(), + matchingId, + serverSigned1, + serverSignature1, + euiccCiPkIdToBeUsed, + serverCertificate, + new IAuthenticateServerCallback.Stub() { + @Override + public void onComplete(int resultCode, byte[] response) { + callback.onComplete(resultCode, response); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling authenticateServer", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Prepares the profile download request sent to SM-DP+. + * + * @param hashCc the hash of confirmation code. It can be null if there is no confirmation code + * required. + * @param smdpSigned2 ASN.1 data in byte array indicating the data to be signed by the SM-DP+ + * returned by SM-DP+ server. + * @param smdpSignature2 ASN.1 data in byte array indicating the SM-DP+ signature returned by + * SM-DP+ server. + * @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned + * by SM-DP+ server. + * @param callback the callback to get the result code and a byte array which represents a + * {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+ + */ + public void prepareDownload(@Nullable byte[] hashCc, byte[] smdpSigned2, + byte[] smdpSignature2, byte[] smdpCertificate, ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().prepareDownload( + mContext.getOpPackageName(), + hashCc, + smdpSigned2, + smdpSignature2, + smdpCertificate, + new IPrepareDownloadCallback.Stub() { + @Override + public void onComplete(int resultCode, byte[] response) { + callback.onComplete(resultCode, response); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling prepareDownload", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Loads a downloaded bound profile package onto the eUICC. + * + * @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server. + * @param callback the callback to get the result code and a byte array which represents a + * {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+. + */ + public void loadBoundProfilePackage(byte[] boundProfilePackage, + ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().loadBoundProfilePackage( + mContext.getOpPackageName(), + boundProfilePackage, + new ILoadBoundProfilePackageCallback.Stub() { + @Override + public void onComplete(int resultCode, byte[] response) { + callback.onComplete(resultCode, response); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling loadBoundProfilePackage", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Cancels the current profile download session. + * + * @param transactionId the transaction ID returned by SM-DP+ server. + * @param reason the cancel reason. + * @param callback the callback to get the result code and an byte[] which represents a + * {@code CancelSessionResponse} defined in GSMA RSP v2.0+. + */ + public void cancelSession(byte[] transactionId, @CancelReason int reason, + ResultCallback<byte[]> callback) { + try { + getIEuiccCardController().cancelSession( + mContext.getOpPackageName(), + transactionId, + reason, + new ICancelSessionCallback.Stub() { + @Override + public void onComplete(int resultCode, byte[] response) { + callback.onComplete(resultCode, response); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling cancelSession", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Lists all notifications of the given {@code notificationEvents}. + * + * @param events bits of the event types ({@link EuiccNotification.Event}) to list. + * @param callback the callback to get the result code and the list of notifications. + */ + public void listNotifications(@EuiccNotification.Event int events, + ResultCallback<EuiccNotification[]> callback) { + try { + getIEuiccCardController().listNotifications(mContext.getOpPackageName(), events, + new IListNotificationsCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccNotification[] notifications) { + callback.onComplete(resultCode, notifications); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling listNotifications", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieves contents of all notification of the given {@code events}. + * + * @param events bits of the event types ({@link EuiccNotification.Event}) to list. + * @param callback the callback to get the result code and the list of notifications. + */ + public void retrieveNotificationList(@EuiccNotification.Event int events, + ResultCallback<EuiccNotification[]> callback) { + try { + getIEuiccCardController().retrieveNotificationList(mContext.getOpPackageName(), events, + new IRetrieveNotificationListCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccNotification[] notifications) { + callback.onComplete(resultCode, notifications); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling retrieveNotificationList", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieves the content of a notification of the given {@code seqNumber}. + * + * @param seqNumber the sequence number of the notification. + * @param callback the callback to get the result code and the notification. + */ + public void retrieveNotification(int seqNumber, ResultCallback<EuiccNotification> callback) { + try { + getIEuiccCardController().retrieveNotification(mContext.getOpPackageName(), seqNumber, + new IRetrieveNotificationCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccNotification notification) { + callback.onComplete(resultCode, notification); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling retrieveNotification", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes a notification from eUICC. + * + * @param seqNumber the sequence number of the notification. + * @param callback the callback to get the result code. + */ + public void removeNotificationFromList(int seqNumber, ResultCallback<Void> callback) { + try { + getIEuiccCardController().removeNotificationFromList( + mContext.getOpPackageName(), + seqNumber, + new IRemoveNotificationFromListCallback.Stub() { + @Override + public void onComplete(int resultCode) { + callback.onComplete(resultCode, null); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling removeNotificationFromList", e); + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index f777649283e7..3dfadf585c28 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -60,6 +60,20 @@ public class EuiccManager { public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; + + /** + * Broadcast Action: The eUICC OTA status is changed. + * <p class="note"> + * Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + * TODO(b/35851809): Make this a SystemApi. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_OTA_STATUS_CHANGED + = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; + /** * Intent action to provision an embedded subscription. * diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.aidl b/telephony/java/android/telephony/euicc/EuiccNotification.aidl new file mode 100644 index 000000000000..dad770da260d --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccNotification.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 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.euicc; + +parcelable EuiccNotification; diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java new file mode 100644 index 000000000000..ef3c1ce8cf3b --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccNotification.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018 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.euicc; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Objects; + +/** + * This represents a signed notification which is defined in SGP.22. It can be either a profile + * installation result or a notification generated for profile operations (e.g., enabling, + * disabling, or deleting). + * + * @hide + * + * TODO(b/35851809): Make this a @SystemApi. + */ +public class EuiccNotification implements Parcelable { + /** Event */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "EVENT_" }, value = { + EVENT_INSTALL, + EVENT_ENABLE, + EVENT_DISABLE, + EVENT_DELETE + }) + public @interface Event {} + + /** A profile is downloaded and installed. */ + public static final int EVENT_INSTALL = 1; + + /** A profile is enabled. */ + public static final int EVENT_ENABLE = 1 << 1; + + /** A profile is disabled. */ + public static final int EVENT_DISABLE = 1 << 2; + + /** A profile is deleted. */ + public static final int EVENT_DELETE = 1 << 3; + + /** Value of the bits of all above events */ + @Event + public static final int ALL_EVENTS = + EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE; + + private final int mSeq; + private final String mTargetAddr; + @Event private final int mEvent; + @Nullable private final byte[] mData; + + /** + * Creates an instance. + * + * @param seq The sequence number of this notification. + * @param targetAddr The target server where to send this notification. + * @param event The event which causes this notification. + * @param data The data which needs to be sent to the target server. This can be null for + * building a list of notification metadata without data. + */ + public EuiccNotification(int seq, String targetAddr, @Event int event, @Nullable byte[] data) { + mSeq = seq; + mTargetAddr = targetAddr; + mEvent = event; + mData = data; + } + + /** @return The sequence number of this notification. */ + public int getSeq() { + return mSeq; + } + + /** @return The target server address where this notification should be sent to. */ + public String getTargetAddr() { + return mTargetAddr; + } + + /** @return The event of this notification. */ + @Event + public int getEvent() { + return mEvent; + } + + /** @return The notification data which needs to be sent to the target server. */ + @Nullable + public byte[] getData() { + return mData; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EuiccNotification that = (EuiccNotification) obj; + return mSeq == that.mSeq + && Objects.equals(mTargetAddr, that.mTargetAddr) + && mEvent == that.mEvent + && Arrays.equals(mData, that.mData); + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + mSeq; + result = 31 * result + Objects.hashCode(mTargetAddr); + result = 31 * result + mEvent; + result = 31 * result + Arrays.hashCode(mData); + return result; + } + + @Override + public String toString() { + return "EuiccNotification (seq=" + + mSeq + + ", targetAddr=" + + mTargetAddr + + ", event=" + + mEvent + + ", data=" + + (mData == null ? "null" : "byte[" + mData.length + "]") + + ")"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSeq); + dest.writeString(mTargetAddr); + dest.writeInt(mEvent); + dest.writeByteArray(mData); + } + + private EuiccNotification(Parcel source) { + mSeq = source.readInt(); + mTargetAddr = source.readString(); + mEvent = source.readInt(); + mData = source.createByteArray(); + } + + public static final Creator<EuiccNotification> CREATOR = + new Creator<EuiccNotification>() { + @Override + public EuiccNotification createFromParcel(Parcel source) { + return new EuiccNotification(source); + } + + @Override + public EuiccNotification[] newArray(int size) { + return new EuiccNotification[size]; + } + }; +} diff --git a/core/java/android/os/Seccomp.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.aidl index f14e93fe9403..9785a4533c5b 100644 --- a/core/java/android/os/Seccomp.java +++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.aidl @@ -14,11 +14,6 @@ * limitations under the License. */ -package android.os; +package android.telephony.euicc; -/** - * @hide - */ -public final class Seccomp { - public static final native void setPolicy(); -} +parcelable EuiccRulesAuthTable;
\ No newline at end of file diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java new file mode 100644 index 000000000000..7efe04364280 --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2018 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.euicc; + +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; +import android.service.carrier.CarrierIdentifier; +import android.service.euicc.EuiccProfileInfo; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * This represents the RAT (Rules Authorisation Table) stored on eUICC. + * + * @hide + * + * TODO(b/35851809): Make this a @SystemApi. + */ +public final class EuiccRulesAuthTable implements Parcelable { + /** Profile policy rule flags */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = { + POLICY_RULE_FLAG_CONSENT_REQUIRED + }) + public @interface PolicyRuleFlag {} + + /** User consent is required to install the profile. */ + public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; + + private final int[] mPolicyRules; + private final CarrierIdentifier[][] mCarrierIds; + private final int[] mPolicyRuleFlags; + + /** This is used to build new {@link EuiccRulesAuthTable} instance. */ + public static final class Builder { + private int[] mPolicyRules; + private CarrierIdentifier[][] mCarrierIds; + private int[] mPolicyRuleFlags; + private int mPosition; + + /** + * Creates a new builder. + * + * @param ruleNum The number of authorisation rules in the table. + */ + public Builder(int ruleNum) { + mPolicyRules = new int[ruleNum]; + mCarrierIds = new CarrierIdentifier[ruleNum][]; + mPolicyRuleFlags = new int[ruleNum]; + } + + /** + * Builds the RAT instance. This builder should not be used anymore after this method is + * called, otherwise {@link NullPointerException} will be thrown. + */ + public EuiccRulesAuthTable build() { + if (mPosition != mPolicyRules.length) { + throw new IllegalStateException( + "Not enough rules are added, expected: " + + mPolicyRules.length + + ", added: " + + mPosition); + } + return new EuiccRulesAuthTable(mPolicyRules, mCarrierIds, mPolicyRuleFlags); + } + + /** + * Adds an authorisation rule. + * + * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size + * this table. + */ + public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) { + if (mPosition >= mPolicyRules.length) { + throw new ArrayIndexOutOfBoundsException(mPosition); + } + mPolicyRules[mPosition] = policyRules; + mCarrierIds[mPosition] = carrierId; + mPolicyRuleFlags[mPosition] = policyRuleFlags; + mPosition++; + return this; + } + } + + /** + * @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The + * character 'E' is used as a wild char to match any digit. + * @param mcc A 2-character or 3-character string which can be either MCC or MNC. + * @return Whether the {@code mccRule} matches {@code mcc}. + * + * @hide + */ + @VisibleForTesting + public static boolean match(String mccRule, String mcc) { + if (mccRule.length() < mcc.length()) { + return false; + } + for (int i = 0; i < mccRule.length(); i++) { + // 'E' is the wild char to match any digit. + if (mccRule.charAt(i) == 'E' + || (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) { + continue; + } + return false; + } + return true; + } + + private EuiccRulesAuthTable(int[] policyRules, CarrierIdentifier[][] carrierIds, + int[] policyRuleFlags) { + mPolicyRules = policyRules; + mCarrierIds = carrierIds; + mPolicyRuleFlags = policyRuleFlags; + } + + /** + * Finds the index of the first authorisation rule matching the given policy and carrier id. If + * the returned index is not negative, the carrier is allowed to apply this policy to its + * profile. + * + * @param policy The policy rule. + * @param carrierId The carrier id. + * @return The index of authorization rule. If no rule is found, -1 will be returned. + */ + public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) { + for (int i = 0; i < mPolicyRules.length; i++) { + if ((mPolicyRules[i] & policy) == 0) { + continue; + } + CarrierIdentifier[] carrierIds = mCarrierIds[i]; + if (carrierIds == null || carrierIds.length == 0) { + continue; + } + for (int j = 0; j < carrierIds.length; j++) { + CarrierIdentifier ruleCarrierId = carrierIds[j]; + if (!match(ruleCarrierId.getMcc(), carrierId.getMcc()) + || !match(ruleCarrierId.getMnc(), carrierId.getMnc())) { + continue; + } + String gid = ruleCarrierId.getGid1(); + if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) { + continue; + } + gid = ruleCarrierId.getGid2(); + if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) { + continue; + } + return i; + } + } + return -1; + } + + /** + * Tests if the entry in the table has the given policy rule flag. + * + * @param index The index of the entry. + * @param flag The policy rule flag to be tested. + * @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the + * size of this table. + */ + public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) { + if (index < 0 || index >= mPolicyRules.length) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (mPolicyRuleFlags[index] & flag) != 0; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mPolicyRules); + for (CarrierIdentifier[] ids : mCarrierIds) { + dest.writeTypedArray(ids, flags); + } + dest.writeIntArray(mPolicyRuleFlags); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EuiccRulesAuthTable that = (EuiccRulesAuthTable) obj; + if (mCarrierIds.length != that.mCarrierIds.length) { + return false; + } + for (int i = 0; i < mCarrierIds.length; i++) { + CarrierIdentifier[] carrierIds = mCarrierIds[i]; + CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i]; + if (carrierIds != null && thatCarrierIds != null) { + if (carrierIds.length != thatCarrierIds.length) { + return false; + } + for (int j = 0; j < carrierIds.length; j++) { + if (!carrierIds[j].equals(thatCarrierIds[j])) { + return false; + } + } + continue; + } else if (carrierIds == null && thatCarrierIds == null) { + continue; + } + return false; + } + + return Arrays.equals(mPolicyRules, that.mPolicyRules) + && Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags); + } + + private EuiccRulesAuthTable(Parcel source) { + mPolicyRules = source.createIntArray(); + int len = mPolicyRules.length; + mCarrierIds = new CarrierIdentifier[len][]; + for (int i = 0; i < len; i++) { + mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR); + } + mPolicyRuleFlags = source.createIntArray(); + } + + public static final Creator<EuiccRulesAuthTable> CREATOR = + new Creator<EuiccRulesAuthTable>() { + @Override + public EuiccRulesAuthTable createFromParcel(Parcel source) { + return new EuiccRulesAuthTable(source); + } + + @Override + public EuiccRulesAuthTable[] newArray(int size) { + return new EuiccRulesAuthTable[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 8230eafc2e4d..aaa0f08594d1 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -26,12 +26,14 @@ import android.telephony.CarrierConfigManager; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MMTelFeature; import android.telephony.ims.feature.RcsFeature; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import android.util.SparseArray; import com.android.ims.internal.IImsFeatureStatusCallback; import com.android.ims.internal.IImsMMTelFeature; import com.android.ims.internal.IImsRcsFeature; +import com.android.ims.internal.IImsRegistration; import com.android.ims.internal.IImsServiceController; import com.android.internal.annotations.VisibleForTesting; @@ -113,6 +115,12 @@ public class ImsService extends Service { throws RemoteException { ImsService.this.removeImsFeature(slotId, featureType, c); } + + @Override + public IImsRegistration getRegistration(int slotId) throws RemoteException { + ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId); + return r != null ? r.getBinder() : null; + } }; /** @@ -174,6 +182,8 @@ public class ImsService extends Service { f.setSlotId(slotId); f.addImsFeatureStatusCallback(c); addImsFeature(slotId, featureType, f); + // TODO: Remove once new onFeatureReady AIDL is merged in. + f.onFeatureReady(); } private void addImsFeature(int slotId, int featureType, ImsFeature f) { @@ -236,4 +246,13 @@ public class ImsService extends Service { public @Nullable RcsFeature onCreateRcsFeature(int slotId) { return null; } + + /** + * @param slotId The slot that is associated with the IMS Registration. + * @return the ImsRegistration implementation associated with the slot. + * @hide + */ + public ImsRegistrationImplBase getRegistration(int slotId) { + return new ImsRegistrationImplBase(); + } } diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index ca4a210e30cc..d47cea3097f3 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -96,7 +96,7 @@ public abstract class ImsFeature { new WeakHashMap<IImsFeatureStatusCallback, Boolean>()); private @ImsState int mState = STATE_NOT_AVAILABLE; private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - private Context mContext; + protected Context mContext; public void setContext(Context context) { mContext = context; diff --git a/telephony/java/android/telephony/ims/internal/ImsService.java b/telephony/java/android/telephony/ims/internal/ImsService.java index b7c8ca0f9799..afaf33294d8a 100644 --- a/telephony/java/android/telephony/ims/internal/ImsService.java +++ b/telephony/java/android/telephony/ims/internal/ImsService.java @@ -24,7 +24,6 @@ import android.telephony.CarrierConfigManager; import android.telephony.ims.internal.aidl.IImsConfig; import android.telephony.ims.internal.aidl.IImsMmTelFeature; import android.telephony.ims.internal.aidl.IImsRcsFeature; -import android.telephony.ims.internal.aidl.IImsRegistration; import android.telephony.ims.internal.aidl.IImsServiceController; import android.telephony.ims.internal.aidl.IImsServiceControllerListener; import android.telephony.ims.internal.feature.ImsFeature; @@ -32,11 +31,12 @@ import android.telephony.ims.internal.feature.MmTelFeature; import android.telephony.ims.internal.feature.RcsFeature; import android.telephony.ims.internal.stub.ImsConfigImplBase; import android.telephony.ims.internal.stub.ImsFeatureConfiguration; -import android.telephony.ims.internal.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import android.util.SparseArray; import com.android.ims.internal.IImsFeatureStatusCallback; +import com.android.ims.internal.IImsRegistration; import com.android.internal.annotations.VisibleForTesting; /** diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl index 8332bc024e37..43f5098af3ca 100644 --- a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl @@ -24,4 +24,5 @@ import com.android.ims.internal.IImsCallSession; */ oneway interface IImsMmTelListener { void onIncomingCall(IImsCallSession c); + void onVoiceMessageCountUpdate(int count); }
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl index 8afb95588b01..82a85254bbca 100644 --- a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl @@ -18,12 +18,12 @@ package android.telephony.ims.internal.aidl; import android.telephony.ims.internal.aidl.IImsMmTelFeature; import android.telephony.ims.internal.aidl.IImsRcsFeature; -import android.telephony.ims.internal.aidl.IImsRegistration; import android.telephony.ims.internal.aidl.IImsConfig; import android.telephony.ims.internal.aidl.IImsServiceControllerListener; import android.telephony.ims.internal.stub.ImsFeatureConfiguration; import com.android.ims.internal.IImsFeatureStatusCallback; +import com.android.ims.internal.IImsRegistration; /** * See ImsService and MmTelFeature for more information. diff --git a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java index 4d188734c10e..5dbf077ee7c5 100644 --- a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java +++ b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java @@ -18,7 +18,7 @@ package android.telephony.ims.internal.feature; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.ims.internal.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.ArraySet; import java.util.ArrayList; diff --git a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java index 2f350c86a6f6..057c9a86d04e 100644 --- a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java @@ -28,8 +28,8 @@ import android.telephony.ims.internal.aidl.IImsCallSessionListener; import android.telephony.ims.internal.aidl.IImsCapabilityCallback; import android.telephony.ims.internal.aidl.IImsMmTelFeature; import android.telephony.ims.internal.aidl.IImsMmTelListener; -import android.telephony.ims.internal.stub.ImsRegistrationImplBase; import android.telephony.ims.internal.aidl.IImsSmsListener; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsEcbmImplBase; import android.telephony.ims.stub.ImsMultiEndpointImplBase; import android.telephony.ims.stub.ImsUtImplBase; @@ -261,6 +261,15 @@ public class MmTelFeature extends ImsFeature { } /** + * Updates the Listener when the voice message count for IMS has changed. + * @param count an integer representing the new message count. + */ + @Override + public void onVoiceMessageCountUpdate(int count) { + + } + + /** * Called when the IMS provider receives an incoming call. * @param c The {@link ImsCallSession} associated with the new call. */ diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 558b009ab4c2..42af08365f61 100644 --- a/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -14,16 +14,19 @@ * limitations under the License */ -package android.telephony.ims.internal.stub; +package android.telephony.ims.stub; import android.annotation.IntDef; +import android.net.Uri; +import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.telephony.ims.internal.aidl.IImsRegistration; -import android.telephony.ims.internal.aidl.IImsRegistrationCallback; import android.util.Log; import com.android.ims.ImsReasonInfo; +import com.android.ims.internal.IImsRegistration; +import com.android.ims.internal.IImsRegistrationCallback; +import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -62,23 +65,25 @@ public class ImsRegistrationImplBase { // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current // state. + // The unknown state is set as the initialization state. This is so that we do not call back + // with NOT_REGISTERED in the case where the ImsService has not updated the registration state + // yet. + private static final int REGISTRATION_STATE_UNKNOWN = -1; private static final int REGISTRATION_STATE_NOT_REGISTERED = 0; private static final int REGISTRATION_STATE_REGISTERING = 1; private static final int REGISTRATION_STATE_REGISTERED = 2; - /** * Callback class for receiving Registration callback events. + * @hide */ - public static class Callback extends IImsRegistrationCallback.Stub { - + public static class Callback { /** * Notifies the framework when the IMS Provider is connected to the IMS network. * * @param imsRadioTech the radio access technology. Valid values are defined in * {@link ImsRegistrationTech}. */ - @Override public void onRegistered(@ImsRegistrationTech int imsRadioTech) { } @@ -88,7 +93,6 @@ public class ImsRegistrationImplBase { * @param imsRadioTech the radio access technology. Valid values are defined in * {@link ImsRegistrationTech}. */ - @Override public void onRegistering(@ImsRegistrationTech int imsRadioTech) { } @@ -97,7 +101,6 @@ public class ImsRegistrationImplBase { * * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. */ - @Override public void onDeregistered(ImsReasonInfo info) { } @@ -108,10 +111,19 @@ public class ImsRegistrationImplBase { * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed * @param info A {@link ImsReasonInfo} that identifies the reason for failure. */ - @Override public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) { } + + /** + * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when + * it changes. + * @param uris new array of subscriber {@link Uri}s that are associated with this IMS + * subscription. + */ + public void onSubscriberAssociatedUriChanged(Uri[] uris) { + + } } private final IImsRegistration mBinder = new IImsRegistration.Stub() { @@ -139,9 +151,9 @@ public class ImsRegistrationImplBase { private @ImsRegistrationTech int mConnectionType = REGISTRATION_TECH_NONE; // Locked on mLock - private int mRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; - // Locked on mLock - private ImsReasonInfo mLastDisconnectCause; + private int mRegistrationState = REGISTRATION_STATE_UNKNOWN; + // Locked on mLock, create unspecified disconnect cause. + private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo(); public final IImsRegistration getBinder() { return mBinder; @@ -221,6 +233,17 @@ public class ImsRegistrationImplBase { }); } + public final void onSubscriberAssociatedUriChanged(Uri[] uris) { + mCallbacks.broadcast((c) -> { + try { + c.onSubscriberAssociatedUriChanged(uris); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " + + "callback."); + } + }); + } + private void updateToState(@ImsRegistrationTech int connType, int newState) { synchronized (mLock) { mConnectionType = connType; @@ -241,7 +264,8 @@ public class ImsRegistrationImplBase { } } - private @ImsRegistrationTech int getConnectionType() { + @VisibleForTesting + public final @ImsRegistrationTech int getConnectionType() { synchronized (mLock) { return mConnectionType; } @@ -271,6 +295,10 @@ public class ImsRegistrationImplBase { c.onRegistered(getConnectionType()); break; } + case REGISTRATION_STATE_UNKNOWN: { + // Do not callback if the state has not been updated yet by the ImsService. + break; + } } } } diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java index 489c208a0d46..693aaff8ce0f 100644 --- a/telephony/java/com/android/ims/ImsCallProfile.java +++ b/telephony/java/com/android/ims/ImsCallProfile.java @@ -351,7 +351,7 @@ public class ImsCallProfile implements Parcelable { mServiceType = in.readInt(); mCallType = in.readInt(); mCallExtras = in.readBundle(); - mMediaProfile = in.readParcelable(null); + mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader()); } public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() { diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl b/telephony/java/com/android/ims/internal/IImsRegistration.aidl index 687b7ca408d5..6de264ec90fb 100644 --- a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl +++ b/telephony/java/com/android/ims/internal/IImsRegistration.aidl @@ -15,10 +15,9 @@ */ -package android.telephony.ims.internal.aidl; +package com.android.ims.internal; -import android.telephony.ims.internal.aidl.IImsRegistrationCallback; -import android.telephony.ims.internal.stub.ImsFeatureConfiguration; +import com.android.ims.internal.IImsRegistrationCallback; /** * See ImsRegistration for more information. diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl index a50575b96865..5f21167422dc 100644 --- a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl +++ b/telephony/java/com/android/ims/internal/IImsRegistrationCallback.aidl @@ -15,8 +15,9 @@ */ -package android.telephony.ims.internal.aidl; +package com.android.ims.internal; +import android.net.Uri; import android.telephony.ims.internal.stub.ImsFeatureConfiguration; import com.android.ims.ImsReasonInfo; @@ -31,4 +32,5 @@ oneway interface IImsRegistrationCallback { void onRegistering(int imsRadioTech); void onDeregistered(in ImsReasonInfo info); void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info); + void onSubscriberAssociatedUriChanged(in Uri[] uris); }
\ No newline at end of file diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl index 857089fac33a..7ac25ac13fbe 100644 --- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl +++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl @@ -18,6 +18,7 @@ package com.android.ims.internal; import com.android.ims.internal.IImsFeatureStatusCallback; import com.android.ims.internal.IImsMMTelFeature; +import com.android.ims.internal.IImsRegistration; import com.android.ims.internal.IImsRcsFeature; /** @@ -29,4 +30,5 @@ interface IImsServiceController { IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c); IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c); void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c); + IImsRegistration getRegistration(int slotId); } diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index ac161397af04..8e3f4c070d2e 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -46,5 +46,6 @@ oneway interface IPhoneStateListener { void onVoiceActivationStateChanged(int activationState); void onDataActivationStateChanged(int activationState); void onCarrierNetworkChange(in boolean active); + void onUserMobileDataStateChanged(in boolean enabled); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 64083e38de31..fba82ee17f77 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -40,6 +40,7 @@ import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; import com.android.ims.internal.IImsMMTelFeature; import com.android.ims.internal.IImsRcsFeature; +import com.android.ims.internal.IImsRegistration; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.telephony.CellNetworkScanResult; import com.android.internal.telephony.OperatorInfo; @@ -808,6 +809,11 @@ interface ITelephony { IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback); /** + * Returns the IImsRegistration associated with the slot and feature specified. + */ + IImsRegistration getImsRegistration(int slotId, int feature); + + /** * Set the network selection mode to automatic. * * @param subId the id of the subscription to update. @@ -870,16 +876,35 @@ interface ITelephony { * * @param enable true to turn on, else false */ - void setDataEnabled(int subId, boolean enable); + void setUserDataEnabled(int subId, boolean enable); /** * Get the user enabled state of Mobile Data. * + * TODO: remove and use isUserDataEnabled. + * This can't be removed now because some vendor codes + * calls through ITelephony directly while they should + * use TelephonyManager. + * * @return true on enabled */ boolean getDataEnabled(int subId); /** + * Get the user enabled state of Mobile Data. + * + * @return true on enabled + */ + boolean isUserDataEnabled(int subId); + + /** + * Get the overall enabled state of Mobile Data. + * + * @return true on enabled + */ + boolean isDataEnabled(int subId); + + /** * Get P-CSCF address from PCO after data connection is established or modified. * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN * @param callingPackage The package making the call. @@ -1298,6 +1323,34 @@ interface ITelephony { */ List<CarrierIdentifier> getAllowedCarriers(int slotIndex); + /** + * Returns carrier id of the given subscription. + * <p>To recognize carrier as a first class identity, assign each carrier with a canonical + * integer a.k.a carrier id. + * + * @param subId The subscription id + * @return Carrier id of given subscription id. return {@link #UNKNOWN_CARRIER_ID} if + * subscription is unavailable or carrier cannot be identified. + * @throws IllegalStateException if telephony service is unavailable. + * @hide + */ + int getSubscriptionCarrierId(int subId); + + /** + * Returns carrier name of the given subscription. + * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId(int)}, + * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure + * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name. + * Carrier name is not canonical identity, use {@link #getSubscriptionCarrierId(int)} instead. + * <p>Returned carrier name is unlocalized. + * + * @return Carrier name of given subscription id. return {@code null} if subscription is + * unavailable or carrier cannot be identified. + * @throws IllegalStateException if telephony service is unavailable. + * @hide + */ + String getSubscriptionCarrierName(int subId); + /** * Action set from carrier signalling broadcast receivers to enable/disable metered apns * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 75d8f3fcb9b6..188167cc14f6 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -69,4 +69,5 @@ interface ITelephonyRegistry { int activationState, int activationType); void notifySubscriptionInfoChanged(); void notifyCarrierNetworkChange(in boolean active); + void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state); } diff --git a/telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl new file mode 100644 index 000000000000..8a77bf127f9e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IAuthenticateServerCallback { + void onComplete(int resultCode, in byte[] response); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl new file mode 100644 index 000000000000..f6b99e2b9801 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface ICancelSessionCallback { + void onComplete(int resultCode, in byte[] response); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl new file mode 100644 index 000000000000..23a642e8167f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IDeleteProfileCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl new file mode 100644 index 000000000000..3ee0b3a0fb69 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.service.euicc.EuiccProfileInfo; + +/** @hide */ +oneway interface IDisableProfileCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl new file mode 100644 index 000000000000..abc55c77cc1f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.euicc; + +import com.android.internal.telephony.euicc.IGetAllProfilesCallback; +import com.android.internal.telephony.euicc.IGetProfileCallback; +import com.android.internal.telephony.euicc.IDisableProfileCallback; +import com.android.internal.telephony.euicc.ISwitchToProfileCallback; +import com.android.internal.telephony.euicc.ISetNicknameCallback; +import com.android.internal.telephony.euicc.IDeleteProfileCallback; +import com.android.internal.telephony.euicc.IResetMemoryCallback; +import com.android.internal.telephony.euicc.IGetDefaultSmdpAddressCallback; +import com.android.internal.telephony.euicc.IGetSmdsAddressCallback; +import com.android.internal.telephony.euicc.ISetDefaultSmdpAddressCallback; +import com.android.internal.telephony.euicc.IAuthenticateServerCallback; +import com.android.internal.telephony.euicc.ICancelSessionCallback; +import com.android.internal.telephony.euicc.IGetEuiccChallengeCallback; +import com.android.internal.telephony.euicc.IGetEuiccInfo1Callback; +import com.android.internal.telephony.euicc.IGetEuiccInfo2Callback; +import com.android.internal.telephony.euicc.IGetRulesAuthTableCallback; +import com.android.internal.telephony.euicc.IListNotificationsCallback; +import com.android.internal.telephony.euicc.ILoadBoundProfilePackageCallback; +import com.android.internal.telephony.euicc.IPrepareDownloadCallback; +import com.android.internal.telephony.euicc.IRemoveNotificationFromListCallback; +import com.android.internal.telephony.euicc.IRetrieveNotificationCallback; +import com.android.internal.telephony.euicc.IRetrieveNotificationListCallback; + +/** @hide */ +interface IEuiccCardController { + oneway void getAllProfiles(String callingPackage, in IGetAllProfilesCallback callback); + oneway void getProfile(String callingPackage, String iccid, in IGetProfileCallback callback); + oneway void disableProfile(String callingPackage, String iccid, boolean refresh, + in IDisableProfileCallback callback); + oneway void switchToProfile(String callingPackage, String iccid, boolean refresh, + in ISwitchToProfileCallback callback); + String getEid(); + oneway void setNickname(String callingPackage, String iccid, String nickname, + in ISetNicknameCallback callback); + oneway void deleteProfile(String callingPackage, String iccid, + in IDeleteProfileCallback callback); + oneway void resetMemory(String callingPackage, int options, in IResetMemoryCallback callback); + oneway void getDefaultSmdpAddress(String callingPackage, + in IGetDefaultSmdpAddressCallback callback); + oneway void getSmdsAddress(String callingPackage, in IGetSmdsAddressCallback callback); + oneway void setDefaultSmdpAddress(String callingPackage, String address, + in ISetDefaultSmdpAddressCallback callback); + oneway void getRulesAuthTable(String callingPackage, in IGetRulesAuthTableCallback callback); + oneway void getEuiccChallenge(String callingPackage, in IGetEuiccChallengeCallback callback); + oneway void getEuiccInfo1(String callingPackage, in IGetEuiccInfo1Callback callback); + oneway void getEuiccInfo2(String callingPackage, in IGetEuiccInfo2Callback callback); + oneway void authenticateServer(String callingPackage, String matchingId, + in byte[] serverSigned1, in byte[] serverSignature1, in byte[] euiccCiPkIdToBeUsed, + in byte[] serverCertificatein, in IAuthenticateServerCallback callback); + oneway void prepareDownload(String callingPackage, in byte[] hashCc, in byte[] smdpSigned2, + in byte[] smdpSignature2, in byte[] smdpCertificate, in IPrepareDownloadCallback callback); + oneway void loadBoundProfilePackage(String callingPackage, in byte[] boundProfilePackage, + in ILoadBoundProfilePackageCallback callback); + oneway void cancelSession(String callingPackage, in byte[] transactionId, int reason, + in ICancelSessionCallback callback); + oneway void listNotifications(String callingPackage, int events, + in IListNotificationsCallback callback); + oneway void retrieveNotificationList(String callingPackage, int events, + in IRetrieveNotificationListCallback callback); + oneway void retrieveNotification(String callingPackage, int seqNumber, + in IRetrieveNotificationCallback callback); + oneway void removeNotificationFromList(String callingPackage, int seqNumber, + in IRemoveNotificationFromListCallback callback); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl new file mode 100644 index 000000000000..97b076846534 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.service.euicc.EuiccProfileInfo; + +/** @hide */ +oneway interface IGetAllProfilesCallback { + void onComplete(int resultCode, in EuiccProfileInfo[] profiles); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl new file mode 100644 index 000000000000..79b659d9316d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IGetDefaultSmdpAddressCallback { + void onComplete(int resultCode, String address); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl new file mode 100644 index 000000000000..5ffb3400912a --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IGetEuiccChallengeCallback { + void onComplete(int resultCode, in byte[] challenge); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl new file mode 100644 index 000000000000..9592acb6d330 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IGetEuiccInfo1Callback { + void onComplete(int resultCode, in byte[] info); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl new file mode 100644 index 000000000000..5256b35c7516 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IGetEuiccInfo2Callback { + void onComplete(int resultCode, in byte[] info); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl new file mode 100644 index 000000000000..e9fc9e9d5e6e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.service.euicc.EuiccProfileInfo; + +/** @hide */ +oneway interface IGetProfileCallback { + void onComplete(int resultCode, in EuiccProfileInfo profile); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl new file mode 100644 index 000000000000..58f0bde65b86 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.telephony.euicc.EuiccRulesAuthTable; + +/** @hide */ +oneway interface IGetRulesAuthTableCallback { + void onComplete(int resultCode, in EuiccRulesAuthTable rat); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl new file mode 100644 index 000000000000..09a83aab3200 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IGetSmdsAddressCallback { + void onComplete(int resultCode, String address); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl new file mode 100644 index 000000000000..65aa302a6a64 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.telephony.euicc.EuiccNotification; + +/** @hide */ +oneway interface IListNotificationsCallback { + void onComplete(int resultCode, in EuiccNotification[] notifications); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl new file mode 100644 index 000000000000..4ad7081c2e67 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface ILoadBoundProfilePackageCallback { + void onComplete(int resultCode, in byte[] response); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl new file mode 100644 index 000000000000..c0351841084e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IPrepareDownloadCallback { + void onComplete(int resultCode, in byte[] response); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl new file mode 100644 index 000000000000..b22d0da5dc5f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.telephony.euicc.EuiccNotification; + +/** @hide */ +oneway interface IRemoveNotificationFromListCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl new file mode 100644 index 000000000000..860c158e2b70 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface IResetMemoryCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl new file mode 100644 index 000000000000..dd8889a94143 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.telephony.euicc.EuiccNotification; + +/** @hide */ +oneway interface IRetrieveNotificationCallback { + void onComplete(int resultCode, in EuiccNotification notification); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl new file mode 100644 index 000000000000..bc4e451329af --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.telephony.euicc.EuiccNotification; + +/** @hide */ +oneway interface IRetrieveNotificationListCallback { + void onComplete(int resultCode, in EuiccNotification[] notifications); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl new file mode 100644 index 000000000000..1e47125123ee --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface ISetDefaultSmdpAddressCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl new file mode 100644 index 000000000000..589998069d92 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +/** @hide */ +oneway interface ISetNicknameCallback { + void onComplete(int resultCode); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl new file mode 100644 index 000000000000..21ff0848f65e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.service.euicc.EuiccProfileInfo; + +/** @hide */ +oneway interface ISwitchToProfileCallback { + void onComplete(int resultCode, in EuiccProfileInfo profile); +} diff --git a/legacy-test/Android.bp b/test-base/Android.bp index 1173bc6e656b..a42dc5a10ec9 100644 --- a/legacy-test/Android.bp +++ b/test-base/Android.bp @@ -14,30 +14,52 @@ // limitations under the License. // -// Build the legacy-test library -// ============================= +// Build the android.test.base library +// =================================== // This contains the junit.framework and android.test classes that were in // Android API level 25 excluding those from android.test.runner. // Also contains the com.android.internal.util.Predicate[s] classes. java_library { - name: "legacy-test", + name: "android.test.base", srcs: ["src/**/*.java"], no_framework_libs: true, + hostdex: true, libs: [ "framework", ], } -// Build the repackaged-legacy-test library -// ======================================== -// This contains repackaged versions of the classes from legacy-test. +// Build the legacy-test library +// ============================= +// This contains the junit.framework and android.test classes that were in +// Android API level 25 excluding those from android.test.runner. +// Also contains the com.android.internal.util.Predicate[s] classes. +java_library { + name: "legacy-test", + static_libs: ["android.test.base"], + + no_framework_libs: true, + libs: [ + "framework", + ], +} + +// Build the repackaged.android.test.base library +// ============================================== +// This contains repackaged versions of the classes from +// android.test.base. java_library_static { - name: "repackaged-legacy-test", + name: "repackaged.android.test.base", - static_libs: ["legacy-test"], + static_libs: ["android.test.base"], + + no_framework_libs: true, + libs: [ + "framework", + ], jarjar_rules: "jarjar-rules.txt", } @@ -56,7 +78,7 @@ java_library_static { ], static_libs: [ - "android.test.runner", + "android.test.runner-minus-junit", "android.test.mock", ], diff --git a/legacy-test/Android.mk b/test-base/Android.mk index 793bbe859eda..25c3d7646df6 100644 --- a/legacy-test/Android.mk +++ b/test-base/Android.mk @@ -31,79 +31,81 @@ LOCAL_JAVA_LIBRARIES := \ LOCAL_MODULE_CLASS := JAVA_LIBRARIES LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src -LEGACY_TEST_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/api.txt -LEGACY_TEST_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/removed.txt +ANDROID_TEST_BASE_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/api.txt +ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/removed.txt -LEGACY_TEST_API_FILE := $(LOCAL_PATH)/api/legacy-test-current.txt -LEGACY_TEST_REMOVED_API_FILE := $(LOCAL_PATH)/api/legacy-test-removed.txt +ANDROID_TEST_BASE_API_FILE := $(LOCAL_PATH)/api/android-test-base-current.txt +ANDROID_TEST_BASE_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-base-removed.txt LOCAL_DROIDDOC_OPTIONS:= \ -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \ -stubsourceonly \ - -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/src \ + -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/src \ -nodocs \ - -api $(LEGACY_TEST_OUTPUT_API_FILE) \ - -removedApi $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) \ + -api $(ANDROID_TEST_BASE_OUTPUT_API_FILE) \ + -removedApi $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) \ LOCAL_UNINSTALLABLE_MODULE := true -LOCAL_MODULE := legacy-test-api-stubs-gen +LOCAL_MODULE := android-test-base-api-stubs-gen include $(BUILD_DROIDDOC) # Remember the target that will trigger the code generation. -legacy_test_api_gen_stamp := $(full_target) +android_test_base_gen_stamp := $(full_target) # Add some additional dependencies -$(LEGACY_TEST_OUTPUT_API_FILE): $(full_target) -$(LEGACY_TEST_OUTPUT_REMOVED_API_FILE): $(full_target) +$(ANDROID_TEST_BASE_OUTPUT_API_FILE): $(full_target) +$(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE): $(full_target) -# Build the legacy.test.stubs library -# =================================== +# Build the android.test.base.stubs library +# ========================================= include $(CLEAR_VARS) -LOCAL_MODULE := legacy.test.stubs +LOCAL_MODULE := android.test.base.stubs LOCAL_SOURCE_FILES_ALL_GENERATED := true +LOCAL_SDK_VERSION := current # Make sure to run droiddoc first to generate the stub source files. -LOCAL_ADDITIONAL_DEPENDENCIES := $(legacy_test_api_gen_stamp) +LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_base_gen_stamp) +android_test_base_gen_stamp := include $(BUILD_STATIC_JAVA_LIBRARY) # Archive a copy of the classes.jar in SDK build. -$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):legacy.test.stubs.jar) +$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.base.stubs.jar) -# Check that the legacy.test.stubs library has not changed -# ======================================================== +# Check that the android.test.base.stubs library has not changed +# ============================================================== # Check that the API we're building hasn't changed from the not-yet-released # SDK version. $(eval $(call check-api, \ - check-legacy-test-api-current, \ - $(LEGACY_TEST_API_FILE), \ - $(LEGACY_TEST_OUTPUT_API_FILE), \ - $(LEGACY_TEST_REMOVED_API_FILE), \ - $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE), \ + check-android-test-base-api-current, \ + $(ANDROID_TEST_BASE_API_FILE), \ + $(ANDROID_TEST_BASE_OUTPUT_API_FILE), \ + $(ANDROID_TEST_BASE_REMOVED_API_FILE), \ + $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE), \ -error 2 -error 3 -error 4 -error 5 -error 6 \ -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \ -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \ -error 25 -error 26 -error 27, \ - cat $(LOCAL_PATH)/api/apicheck_msg_legacy_test.txt, \ - check-legacy-test-api, \ - $(call doc-timestamp-for,legacy-test-api-stubs-gen) \ + cat $(LOCAL_PATH)/api/apicheck_msg_android_test_base.txt, \ + check-android-test-base-api, \ + $(call doc-timestamp-for,android-test-base-api-stubs-gen) \ )) -.PHONY: check-legacy-test-api -checkapi: check-legacy-test-api +.PHONY: check-android-test-base-api +checkapi: check-android-test-base-api -.PHONY: update-legacy-test-api -update-api: update-legacy-test-api +.PHONY: update-android-test-base-api +update-api: update-android-test-base-api -update-legacy-test-api: $(LEGACY_TEST_OUTPUT_API_FILE) | $(ACP) +update-android-test-base-api: $(ANDROID_TEST_BASE_OUTPUT_API_FILE) | $(ACP) @echo Copying current.txt - $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_API_FILE) $(LEGACY_TEST_API_FILE) + $(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_API_FILE) $(ANDROID_TEST_BASE_API_FILE) @echo Copying removed.txt - $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) $(LEGACY_TEST_REMOVED_API_FILE) + $(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE) ifeq ($(HOST_OS),linux) # Build the legacy-performance-test-hostdex library diff --git a/legacy-test/api/legacy-test-current.txt b/test-base/api/android-test-base-current.txt index 7ebd6aa8a4a2..7ebd6aa8a4a2 100644 --- a/legacy-test/api/legacy-test-current.txt +++ b/test-base/api/android-test-base-current.txt diff --git a/legacy-test/api/legacy-test-removed.txt b/test-base/api/android-test-base-removed.txt index e69de29bb2d1..e69de29bb2d1 100644 --- a/legacy-test/api/legacy-test-removed.txt +++ b/test-base/api/android-test-base-removed.txt diff --git a/legacy-test/api/apicheck_msg_legacy_test.txt b/test-base/api/apicheck_msg_android_test_base.txt index ad5f2359b8b1..144aecc21bce 100644 --- a/legacy-test/api/apicheck_msg_legacy_test.txt +++ b/test-base/api/apicheck_msg_android_test_base.txt @@ -6,10 +6,10 @@ To make these errors go away, you have two choices: 1) You can add "@hide" javadoc comments to the methods, etc. listed in the errors above. - 2) You can update legacy-test-current.txt by executing the following command: - make update-legacy-test-api + 2) You can update android-test-base-current.txt by executing the following command: + make update-android-test-base-api - To submit the revised legacy-test-current.txt to the main Android repository, + To submit the revised android-test-base-current.txt to the main Android repository, you will need approval. ****************************** diff --git a/legacy-test/jarjar-rules.txt b/test-base/jarjar-rules.txt index fd8555c8931c..fd8555c8931c 100644 --- a/legacy-test/jarjar-rules.txt +++ b/test-base/jarjar-rules.txt diff --git a/legacy-test/src/android/test/AndroidTestCase.java b/test-base/src/android/test/AndroidTestCase.java index 1e6bd9c14fd9..1e6bd9c14fd9 100644 --- a/legacy-test/src/android/test/AndroidTestCase.java +++ b/test-base/src/android/test/AndroidTestCase.java diff --git a/legacy-test/src/android/test/FlakyTest.java b/test-base/src/android/test/FlakyTest.java index 4e5c4e35a8c6..4e5c4e35a8c6 100644 --- a/legacy-test/src/android/test/FlakyTest.java +++ b/test-base/src/android/test/FlakyTest.java diff --git a/legacy-test/src/android/test/InstrumentationTestCase.java b/test-base/src/android/test/InstrumentationTestCase.java index 6b79314a4385..6b79314a4385 100644 --- a/legacy-test/src/android/test/InstrumentationTestCase.java +++ b/test-base/src/android/test/InstrumentationTestCase.java diff --git a/legacy-test/src/android/test/InstrumentationTestSuite.java b/test-base/src/android/test/InstrumentationTestSuite.java index a53fa267f1e1..a53fa267f1e1 100644 --- a/legacy-test/src/android/test/InstrumentationTestSuite.java +++ b/test-base/src/android/test/InstrumentationTestSuite.java diff --git a/legacy-test/src/android/test/PerformanceTestCase.java b/test-base/src/android/test/PerformanceTestCase.java index 65bd4a48f7f5..65bd4a48f7f5 100644 --- a/legacy-test/src/android/test/PerformanceTestCase.java +++ b/test-base/src/android/test/PerformanceTestCase.java diff --git a/legacy-test/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java index 6a7130e68e61..6a7130e68e61 100644 --- a/legacy-test/src/android/test/RepetitiveTest.java +++ b/test-base/src/android/test/RepetitiveTest.java diff --git a/legacy-test/src/android/test/UiThreadTest.java b/test-base/src/android/test/UiThreadTest.java index cd06ab890074..cd06ab890074 100644 --- a/legacy-test/src/android/test/UiThreadTest.java +++ b/test-base/src/android/test/UiThreadTest.java diff --git a/legacy-test/src/android/test/package.html b/test-base/src/android/test/package.html index 5be51359630e..5be51359630e 100644 --- a/legacy-test/src/android/test/package.html +++ b/test-base/src/android/test/package.html diff --git a/legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java b/test-base/src/android/test/suitebuilder/annotation/LargeTest.java index dc77ee6b2739..dc77ee6b2739 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/LargeTest.java +++ b/test-base/src/android/test/suitebuilder/annotation/LargeTest.java diff --git a/legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java b/test-base/src/android/test/suitebuilder/annotation/MediumTest.java index b941da03ac9a..b941da03ac9a 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/MediumTest.java +++ b/test-base/src/android/test/suitebuilder/annotation/MediumTest.java diff --git a/legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java b/test-base/src/android/test/suitebuilder/annotation/SmallTest.java index d3c74f019b53..d3c74f019b53 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/SmallTest.java +++ b/test-base/src/android/test/suitebuilder/annotation/SmallTest.java diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Smoke.java b/test-base/src/android/test/suitebuilder/annotation/Smoke.java index aac293796be1..aac293796be1 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/Smoke.java +++ b/test-base/src/android/test/suitebuilder/annotation/Smoke.java diff --git a/legacy-test/src/android/test/suitebuilder/annotation/Suppress.java b/test-base/src/android/test/suitebuilder/annotation/Suppress.java index 629a3cf4a2cd..629a3cf4a2cd 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/Suppress.java +++ b/test-base/src/android/test/suitebuilder/annotation/Suppress.java diff --git a/legacy-test/src/android/test/suitebuilder/annotation/package.html b/test-base/src/android/test/suitebuilder/annotation/package.html index ffba2e9bf980..ffba2e9bf980 100644 --- a/legacy-test/src/android/test/suitebuilder/annotation/package.html +++ b/test-base/src/android/test/suitebuilder/annotation/package.html diff --git a/legacy-test/src/com/android/internal/util/Predicate.java b/test-base/src/com/android/internal/util/Predicate.java index e87f489f4670..e87f489f4670 100644 --- a/legacy-test/src/com/android/internal/util/Predicate.java +++ b/test-base/src/com/android/internal/util/Predicate.java diff --git a/legacy-test/src/junit/MODULE_LICENSE_CPL b/test-base/src/junit/MODULE_LICENSE_CPL index e69de29bb2d1..e69de29bb2d1 100644 --- a/legacy-test/src/junit/MODULE_LICENSE_CPL +++ b/test-base/src/junit/MODULE_LICENSE_CPL diff --git a/legacy-test/src/junit/README.android b/test-base/src/junit/README.android index 1384a1fedda2..1384a1fedda2 100644 --- a/legacy-test/src/junit/README.android +++ b/test-base/src/junit/README.android diff --git a/legacy-test/src/junit/cpl-v10.html b/test-base/src/junit/cpl-v10.html index 36aa208d4a29..36aa208d4a29 100644 --- a/legacy-test/src/junit/cpl-v10.html +++ b/test-base/src/junit/cpl-v10.html diff --git a/legacy-test/src/junit/framework/Assert.java b/test-base/src/junit/framework/Assert.java index 3dcc23d71c19..3dcc23d71c19 100644 --- a/legacy-test/src/junit/framework/Assert.java +++ b/test-base/src/junit/framework/Assert.java diff --git a/legacy-test/src/junit/framework/AssertionFailedError.java b/test-base/src/junit/framework/AssertionFailedError.java index 0d7802c431c6..0d7802c431c6 100644 --- a/legacy-test/src/junit/framework/AssertionFailedError.java +++ b/test-base/src/junit/framework/AssertionFailedError.java diff --git a/legacy-test/src/junit/framework/ComparisonCompactor.java b/test-base/src/junit/framework/ComparisonCompactor.java index e540f03b87d3..e540f03b87d3 100644 --- a/legacy-test/src/junit/framework/ComparisonCompactor.java +++ b/test-base/src/junit/framework/ComparisonCompactor.java diff --git a/legacy-test/src/junit/framework/ComparisonFailure.java b/test-base/src/junit/framework/ComparisonFailure.java index 507799328a44..507799328a44 100644 --- a/legacy-test/src/junit/framework/ComparisonFailure.java +++ b/test-base/src/junit/framework/ComparisonFailure.java diff --git a/legacy-test/src/junit/framework/Protectable.java b/test-base/src/junit/framework/Protectable.java index e1432370cfaf..e1432370cfaf 100644 --- a/legacy-test/src/junit/framework/Protectable.java +++ b/test-base/src/junit/framework/Protectable.java diff --git a/legacy-test/src/junit/framework/Test.java b/test-base/src/junit/framework/Test.java index a016ee8308f1..a016ee8308f1 100644 --- a/legacy-test/src/junit/framework/Test.java +++ b/test-base/src/junit/framework/Test.java diff --git a/legacy-test/src/junit/framework/TestCase.java b/test-base/src/junit/framework/TestCase.java index b047ec9e1afc..b047ec9e1afc 100644 --- a/legacy-test/src/junit/framework/TestCase.java +++ b/test-base/src/junit/framework/TestCase.java diff --git a/legacy-test/src/junit/framework/TestFailure.java b/test-base/src/junit/framework/TestFailure.java index 6662b1fab1b2..6662b1fab1b2 100644 --- a/legacy-test/src/junit/framework/TestFailure.java +++ b/test-base/src/junit/framework/TestFailure.java diff --git a/legacy-test/src/junit/framework/TestListener.java b/test-base/src/junit/framework/TestListener.java index 9b6944361b9d..9b6944361b9d 100644 --- a/legacy-test/src/junit/framework/TestListener.java +++ b/test-base/src/junit/framework/TestListener.java diff --git a/legacy-test/src/junit/framework/TestResult.java b/test-base/src/junit/framework/TestResult.java index 3052e94074fd..3052e94074fd 100644 --- a/legacy-test/src/junit/framework/TestResult.java +++ b/test-base/src/junit/framework/TestResult.java diff --git a/legacy-test/src/junit/framework/TestSuite.java b/test-base/src/junit/framework/TestSuite.java index 336efd1800d7..336efd1800d7 100644 --- a/legacy-test/src/junit/framework/TestSuite.java +++ b/test-base/src/junit/framework/TestSuite.java diff --git a/test-mock/Android.bp b/test-mock/Android.bp index 8eddec48611b..b1ae40e17b9d 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -24,7 +24,6 @@ java_library { no_framework_libs: true, libs: [ "framework", - "legacy-test", ], } diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt index b0e4beaf5a4c..f6f79139d511 120000 --- a/test-mock/jarjar-rules.txt +++ b/test-mock/jarjar-rules.txt @@ -1 +1 @@ -../legacy-test/jarjar-rules.txt
\ No newline at end of file +../test-base/jarjar-rules.txt
\ No newline at end of file diff --git a/test-runner/Android.bp b/test-runner/Android.bp index 104ae8236368..dfaeed5e271e 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -24,11 +24,28 @@ java_library { no_framework_libs: true, libs: [ "framework", - "legacy-test", + "android.test.base", "android.test.mock", ], } +// Build the android.test.runner-minus-junit library +// ================================================= +// This is provided solely for use by the legacy-android-test module. +java_library { + name: "android.test.runner-minus-junit", + + srcs: ["src/android/**/*.java"], + + no_framework_libs: true, + libs: [ + "framework", + "android.test.base", + "android.test.mock", + "junit", + ], +} + // Build the repackaged.android.test.runner library // ================================================ java_library_static { diff --git a/test-runner/Android.mk b/test-runner/Android.mk index 6cf2d5646ffb..cdc7756d5754 100644 --- a/test-runner/Android.mk +++ b/test-runner/Android.mk @@ -26,7 +26,7 @@ LOCAL_JAVA_LIBRARIES := \ core-oj \ core-libart \ framework \ - legacy-test \ + android.test.base \ android.test.mock \ LOCAL_MODULE_CLASS := JAVA_LIBRARIES @@ -65,7 +65,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := android.test.runner.stubs LOCAL_JAVA_LIBRARIES := \ - legacy.test.stubs \ + android.test.base.stubs \ android.test.mock.stubs \ LOCAL_SOURCE_FILES_ALL_GENERATED := true diff --git a/test-runner/jarjar-rules.txt b/test-runner/jarjar-rules.txt index b0e4beaf5a4c..f6f79139d511 120000 --- a/test-runner/jarjar-rules.txt +++ b/test-runner/jarjar-rules.txt @@ -1 +1 @@ -../legacy-test/jarjar-rules.txt
\ No newline at end of file +../test-base/jarjar-rules.txt
\ No newline at end of file diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java index efc01f2ace6f..f6c5532363e8 100644 --- a/tests/net/java/android/net/IpSecConfigTest.java +++ b/tests/net/java/android/net/IpSecConfigTest.java @@ -36,19 +36,16 @@ public class IpSecConfigTest { public void testDefaults() throws Exception { IpSecConfig c = new IpSecConfig(); assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode()); - assertEquals("", c.getLocalAddress()); - assertEquals("", c.getRemoteAddress()); + assertEquals("", c.getSourceAddress()); + assertEquals("", c.getDestinationAddress()); assertNull(c.getNetwork()); assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType()); assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId()); assertEquals(0, c.getEncapRemotePort()); assertEquals(0, c.getNattKeepaliveInterval()); - for (int direction : - new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}) { - assertNull(c.getEncryption(direction)); - assertNull(c.getAuthentication(direction)); - assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId(direction)); - } + assertNull(c.getEncryption()); + assertNull(c.getAuthentication()); + assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId()); } @Test @@ -57,34 +54,21 @@ public class IpSecConfigTest { IpSecConfig c = new IpSecConfig(); c.setMode(IpSecTransform.MODE_TUNNEL); - c.setLocalAddress("0.0.0.0"); - c.setRemoteAddress("1.2.3.4"); + c.setSourceAddress("0.0.0.0"); + c.setDestinationAddress("1.2.3.4"); c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP); c.setEncapSocketResourceId(7); c.setEncapRemotePort(22); c.setNattKeepaliveInterval(42); c.setEncryption( - IpSecTransform.DIRECTION_OUT, new IpSecAlgorithm( IpSecAlgorithm.CRYPT_AES_CBC, new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF})); c.setAuthentication( - IpSecTransform.DIRECTION_OUT, new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_MD5, new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0})); - c.setSpiResourceId(IpSecTransform.DIRECTION_OUT, 1984); - c.setEncryption( - IpSecTransform.DIRECTION_IN, - new IpSecAlgorithm( - IpSecAlgorithm.CRYPT_AES_CBC, - new byte[] {2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF})); - c.setAuthentication( - IpSecTransform.DIRECTION_IN, - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_MD5, - new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 1})); - c.setSpiResourceId(IpSecTransform.DIRECTION_IN, 99); + c.setSpiResourceId(1984); assertParcelingIsLossless(c); } diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java index 0f40b4562b0d..cc3366fbc832 100644 --- a/tests/net/java/android/net/IpSecManagerTest.java +++ b/tests/net/java/android/net/IpSecManagerTest.java @@ -81,15 +81,13 @@ public class IpSecManagerTest { IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI); when(mMockIpSecService.allocateSecurityParameterIndex( - eq(IpSecTransform.DIRECTION_IN), eq(GOOGLE_DNS_4.getHostAddress()), eq(DROID_SPI), anyObject())) .thenReturn(spiResp); IpSecManager.SecurityParameterIndex droidSpi = - mIpSecManager.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_IN, GOOGLE_DNS_4, DROID_SPI); + mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI); assertEquals(DROID_SPI, droidSpi.getSpi()); droidSpi.close(); @@ -103,15 +101,13 @@ public class IpSecManagerTest { IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI); when(mMockIpSecService.allocateSecurityParameterIndex( - eq(IpSecTransform.DIRECTION_OUT), eq(GOOGLE_DNS_4.getHostAddress()), eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX), anyObject())) .thenReturn(spiResp); IpSecManager.SecurityParameterIndex randomSpi = - mIpSecManager.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4); + mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); assertEquals(DROID_SPI, randomSpi.getSpi()); @@ -124,16 +120,15 @@ public class IpSecManagerTest { * Throws resource unavailable exception */ @Test - public void testAllocSpiResUnavaiableExeption() throws Exception { + public void testAllocSpiResUnavailableException() throws Exception { IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0); when(mMockIpSecService.allocateSecurityParameterIndex( - anyInt(), anyString(), anyInt(), anyObject())) + anyString(), anyInt(), anyObject())) .thenReturn(spiResp); try { - mIpSecManager.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4); + mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); fail("ResourceUnavailableException was not thrown"); } catch (IpSecManager.ResourceUnavailableException e) { } @@ -143,15 +138,14 @@ public class IpSecManagerTest { * Throws spi unavailable exception */ @Test - public void testAllocSpiSpiUnavaiableExeption() throws Exception { + public void testAllocSpiSpiUnavailableException() throws Exception { IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0); when(mMockIpSecService.allocateSecurityParameterIndex( - anyInt(), anyString(), anyInt(), anyObject())) + anyString(), anyInt(), anyObject())) .thenReturn(spiResp); try { - mIpSecManager.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4); + mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4); fail("ResourceUnavailableException was not thrown"); } catch (IpSecManager.ResourceUnavailableException e) { } @@ -163,8 +157,7 @@ public class IpSecManagerTest { @Test public void testRequestAllocInvalidSpi() throws Exception { try { - mIpSecManager.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4, 0); + mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0); fail("Able to allocate invalid spi"); } catch (IllegalArgumentException e) { } diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java index 52da79a18c6e..f3c22a51e267 100644 --- a/tests/net/java/android/net/LinkPropertiesTest.java +++ b/tests/net/java/android/net/LinkPropertiesTest.java @@ -79,6 +79,9 @@ public class LinkPropertiesTest { assertTrue(source.isIdenticalDnses(target)); assertTrue(target.isIdenticalDnses(source)); + assertTrue(source.isIdenticalPrivateDns(target)); + assertTrue(target.isIdenticalPrivateDns(source)); + assertTrue(source.isIdenticalRoutes(target)); assertTrue(target.isIdenticalRoutes(source)); @@ -91,6 +94,9 @@ public class LinkPropertiesTest { assertTrue(source.isIdenticalMtu(target)); assertTrue(target.isIdenticalMtu(source)); + assertTrue(source.isIdenticalTcpBufferSizes(target)); + assertTrue(target.isIdenticalTcpBufferSizes(source)); + // Check result of equals(). assertTrue(source.equals(target)); assertTrue(target.equals(source)); diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index 473dc538f09d..9aad413c354b 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -67,7 +67,7 @@ public class MacAddressTest { assertEquals(msg, t.expectedType, got); if (got != MacAddress.TYPE_UNKNOWN) { - assertEquals(got, MacAddress.fromBytes(t.addr).addressType()); + assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType()); } } } @@ -191,7 +191,7 @@ public class MacAddressTest { assertTrue(stringRepr + " expected to be a locally assigned address", mac.isLocallyAssigned()); - assertEquals(MacAddress.TYPE_UNICAST, mac.addressType()); + assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType()); assertTrue(stringRepr + " expected to begin with " + expectedLocalOui, stringRepr.startsWith(expectedLocalOui)); } diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/java/android/net/NetworkTest.java index bacf986b3627..94d01e91d03b 100644 --- a/tests/net/java/android/net/NetworkTest.java +++ b/tests/net/java/android/net/NetworkTest.java @@ -147,9 +147,9 @@ public class NetworkTest { // Adjust as necessary to test an implementation's specific constants. // When running with runtest, "adb logcat -s TestRunner" can be useful. - assertEquals(4311403230L, one.getNetworkHandle()); - assertEquals(8606370526L, two.getNetworkHandle()); - assertEquals(12901337822L, three.getNetworkHandle()); + assertEquals(7700664333L, one.getNetworkHandle()); + assertEquals(11995631629L, two.getNetworkHandle()); + assertEquals(16290598925L, three.getNetworkHandle()); } private static <T> void assertNotEqual(T t1, T t2) { diff --git a/core/tests/coretests/src/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java index 8d51c3b01258..8d51c3b01258 100644 --- a/core/tests/coretests/src/android/net/NetworkUtilsTest.java +++ b/tests/net/java/android/net/NetworkUtilsTest.java diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/tests/net/java/android/net/RouteInfoTest.java index 831fefd283db..831fefd283db 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/tests/net/java/android/net/RouteInfoTest.java diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 725ddb9ccbca..9b75a509288f 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -35,6 +35,7 @@ import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; +import android.net.util.InterfaceParams; import android.os.ConditionVariable; import android.os.Parcelable; import android.os.SystemClock; @@ -62,7 +63,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; -import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.List; import java.util.Random; @@ -635,7 +635,7 @@ public class ApfTest { public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception { - super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log); + super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log); } // Pretend an RA packet has been received and show it to ApfFilter. diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java index 54776dbd3c52..e65585f8ff0f 100644 --- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java +++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.when; +import android.net.util.InterfaceParams; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -54,8 +55,8 @@ public class IpReachabilityMonitorTest { } IpReachabilityMonitor makeMonitor() { - return new IpReachabilityMonitor( - "fake0", 1, mHandler, mLog, mCallback, null, mDependencies); + final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null); + return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies); } @Test diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java index 38d3d74e64cf..f9b7ec8f0322 100644 --- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java +++ b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java @@ -20,6 +20,7 @@ import static android.net.util.NetworkConstants.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.net.MacAddress; import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; @@ -36,9 +37,7 @@ import libcore.util.HexEncoding; @RunWith(AndroidJUnit4.class) @SmallTest public class ConnectivityPacketSummaryTest { - private static final byte[] MYHWADDR = { - asByte(0x80), asByte(0x7a), asByte(0xbf), asByte(0x6f), asByte(0x48), asByte(0xf3) - }; + private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3"); private String getSummary(String hexBytes) { hexBytes = hexBytes.replaceAll("\\s+", ""); diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java new file mode 100644 index 000000000000..21728afdd5de --- /dev/null +++ b/tests/net/java/android/net/util/InterfaceParamsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceParamsTest { + @Test + public void testNullInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName(null)); + } + + @Test + public void testNonExistentInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName("doesnotexist0")); + } + + @Test + public void testLoopback() { + final InterfaceParams ifParams = InterfaceParams.getByName("lo"); + assertNotNull(ifParams); + assertEquals("lo", ifParams.name); + assertTrue(ifParams.index > 0); + assertNotNull(ifParams.macAddr); + assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU); + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 113cd37f1a27..b8e37f3a10ea 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -55,14 +55,20 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -116,6 +122,7 @@ import android.test.mock.MockContentResolver; import android.util.ArraySet; import android.util.Log; +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; @@ -132,6 +139,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -174,8 +182,11 @@ public class ConnectivityServiceTest { @Mock IpConnectivityMetrics.Logger mMetricsService; @Mock DefaultNetworkMetrics mDefaultNetworkMetrics; + @Mock INetworkManagementService mNetworkManagementService; @Mock INetworkStatsService mStatsService; + private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); + // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods // do not go through ConnectivityService but talk to netd directly, so they don't automatically // reflect the state of our test ConnectivityService. @@ -872,7 +883,7 @@ public class ConnectivityServiceTest { LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); mService = new WrappedConnectivityService(mServiceContext, - mock(INetworkManagementService.class), + mNetworkManagementService, mStatsService, mock(INetworkPolicyManager.class), mock(IpConnectivityLog.class)); @@ -1381,39 +1392,75 @@ public class ConnectivityServiceTest { return null; } - void expectAvailableCallbacks( - MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) { + // Expects onAvailable and the callbacks that follow it. These are: + // - onSuspended, iff the network was suspended when the callbacks fire. + // - onCapabilitiesChanged. + // - onLinkPropertiesChanged. + // + // @param agent the network to expect the callbacks on. + // @param expectSuspended whether to expect a SUSPENDED callback. + // @param expectValidated the expected value of the VALIDATED capability in the + // onCapabilitiesChanged callback. + // @param timeoutMs how long to wait for the callbacks. + void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, + boolean expectValidated, int timeoutMs) { expectCallback(CallbackState.AVAILABLE, agent, timeoutMs); if (expectSuspended) { expectCallback(CallbackState.SUSPENDED, agent, timeoutMs); } - expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs); + if (expectValidated) { + expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent); + } else { + expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent); + } expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs); } - void expectAvailableCallbacks(MockNetworkAgent agent) { - expectAvailableCallbacks(agent, false, TIMEOUT_MS); + // Expects the available callbacks (validated), plus onSuspended. + void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) { + expectAvailableCallbacks(agent, true, expectValidated, TIMEOUT_MS); } - void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) { - expectAvailableCallbacks(agent, true, TIMEOUT_MS); + void expectAvailableCallbacksValidated(MockNetworkAgent agent) { + expectAvailableCallbacks(agent, false, true, TIMEOUT_MS); } - void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) { - expectAvailableCallbacks(agent, false, TIMEOUT_MS); + void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) { + expectAvailableCallbacks(agent, false, false, TIMEOUT_MS); + } + + // Expects the available callbacks (where the onCapabilitiesChanged must contain the + // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the + // one we just sent. + // TODO: this is likely a bug. Fix it and remove this method. + void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) { + expectCallback(CallbackState.AVAILABLE, agent, TIMEOUT_MS); + NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent); + expectCallback(CallbackState.LINK_PROPERTIES, agent, TIMEOUT_MS); + NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent); + assertEquals(nc1, nc2); + } + + // Expects the available callbacks where the onCapabilitiesChanged must not have validated, + // then expects another onCapabilitiesChanged that has the validated bit set. This is used + // when a network connects and satisfies a callback, and then immediately validates. + void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) { + expectAvailableCallbacksUnvalidated(agent); expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent); } - void expectCapabilitiesWith(int capability, MockNetworkAgent agent) { + NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) { CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent); NetworkCapabilities nc = (NetworkCapabilities) cbi.arg; assertTrue(nc.hasCapability(capability)); + return nc; } - void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) { + NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) { CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent); NetworkCapabilities nc = (NetworkCapabilities) cbi.arg; assertFalse(nc.hasCapability(capability)); + return nc; } void assertNoCallback() { @@ -1450,8 +1497,8 @@ public class ConnectivityServiceTest { ConditionVariable cv = waitForConnectivityBroadcasts(1); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); - genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent); - cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); waitFor(cv); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); @@ -1465,8 +1512,8 @@ public class ConnectivityServiceTest { cv = waitForConnectivityBroadcasts(2); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); - genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent); - wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); waitFor(cv); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); @@ -1489,8 +1536,8 @@ public class ConnectivityServiceTest { // Test validated networks mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); @@ -1502,10 +1549,10 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback); @@ -1541,32 +1588,32 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); mCellNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.connect(true); // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request. // We then get LOSING when wifi validates and cell is outscored. - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // TODO: Investigate sending validated before losing. callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); mEthernetNetworkAgent.connect(true); - callback.expectAvailableCallbacks(mEthernetNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); // TODO: Investigate sending validated before losing. callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); mEthernetNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); for (int i = 0; i < 4; i++) { MockNetworkAgent oldNetwork, newNetwork; @@ -1583,7 +1630,7 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOSING, oldNetwork); // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no // longer lingering? - defaultCallback.expectAvailableCallbacks(newNetwork); + defaultCallback.expectAvailableCallbacksValidated(newNetwork); assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork()); } assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); @@ -1603,7 +1650,7 @@ public class ConnectivityServiceTest { // Disconnect our test networks. mWiFiNetworkAgent.disconnect(); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); mCellNetworkAgent.disconnect(); defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); @@ -1619,22 +1666,22 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false); // Score: 10 - callback.expectAvailableCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); // Bring up wifi with a score of 20. // Cell stays up because it would satisfy the default request if it validated. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); // Score: 20 - callback.expectAvailableCallbacks(mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); // Bring up wifi with a score of 70. @@ -1642,33 +1689,33 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.adjustScore(50); mWiFiNetworkAgent.connect(false); // Score: 70 - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); // Tear down wifi. mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but // it's arguably correct to linger it, since it was the default network before it validated. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // TODO: Investigate sending validated before losing. callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); mCellNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); @@ -1676,12 +1723,12 @@ public class ConnectivityServiceTest { // If a network is lingering, and we add and remove a request from it, resume lingering. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // TODO: Investigate sending validated before losing. callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); @@ -1700,7 +1747,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); // Cell is now the default network. Pin it with a cell-specific request. noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525 @@ -1709,8 +1756,8 @@ public class ConnectivityServiceTest { // Now connect wifi, and expect it to become the default network. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); // The default request is lingering on cell, but nothing happens to cell, and we send no // callbacks for it, because it's kept up by cellRequest. callback.assertNoCallback(); @@ -1726,14 +1773,14 @@ public class ConnectivityServiceTest { // Register a TRACK_DEFAULT request and check that it does not affect lingering. TestNetworkCallback trackDefaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(trackDefaultCallback); - trackDefaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); mEthernetNetworkAgent.connect(true); - callback.expectAvailableCallbacks(mEthernetNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); - trackDefaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent); + trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); // Let linger run its course. callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs); @@ -1760,13 +1807,13 @@ public class ConnectivityServiceTest { // Bring up validated cell. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); // Bring up unvalidated wifi with explicitlySelected=true. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(false); mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // Cell Remains the default. assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); @@ -1789,7 +1836,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(false); mWiFiNetworkAgent.connect(false); - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the // network to disconnect. @@ -1800,7 +1847,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(false); mWiFiNetworkAgent.connect(true); - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); @@ -1809,7 +1856,7 @@ public class ConnectivityServiceTest { // TODO: fix this. mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); mEthernetNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); callback.assertNoCallback(); @@ -1982,7 +2029,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS); mCellNetworkAgent.connectWithoutInternet(); - networkCallback.expectAvailableCallbacks(mCellNetworkAgent); + networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); verifyActiveNetwork(TRANSPORT_WIFI); // Test releasing NetworkRequest disconnects cellular with MMS @@ -2011,7 +2058,7 @@ public class ConnectivityServiceTest { MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS); mmsNetworkAgent.connectWithoutInternet(); - networkCallback.expectAvailableCallbacks(mmsNetworkAgent); + networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent); verifyActiveNetwork(TRANSPORT_CELLULAR); // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent @@ -2038,7 +2085,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); String firstRedirectUrl = "http://example.com/firstPath"; mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); - captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); // Take down network. @@ -2051,7 +2098,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); String secondRedirectUrl = "http://example.com/secondPath"; mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); - captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl); // Make captive portal disappear then revalidate. @@ -2061,9 +2108,7 @@ public class ConnectivityServiceTest { captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); // Expect NET_CAPABILITY_VALIDATED onAvailable callback. - validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent); - // TODO: Investigate only sending available callbacks. - validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); // Break network connectivity. // Expect NET_CAPABILITY_VALIDATED onLost callback. @@ -2087,7 +2132,7 @@ public class ConnectivityServiceTest { // Bring up wifi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - validatedCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); // Check that calling startCaptivePortalApp does nothing. @@ -2098,7 +2143,7 @@ public class ConnectivityServiceTest { // Turn into a captive portal. mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302; mCm.reportNetworkConnectivity(wifiNetwork, false); - captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); // Check that startCaptivePortalApp sends the expected intent. @@ -2111,7 +2156,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204; CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); c.reportCaptivePortalDismissed(); - validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); mCm.unregisterNetworkCallback(validatedCallback); @@ -2154,7 +2199,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); // Expect NET_CAPABILITY_VALIDATED onAvailable callback. - validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); // But there should be no CaptivePortal callback. captivePortalCallback.assertNoCallback(); } @@ -2192,14 +2237,14 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); - cEmpty1.expectAvailableCallbacks(mWiFiNetworkAgent); - cEmpty2.expectAvailableCallbacks(mWiFiNetworkAgent); - cEmpty3.expectAvailableCallbacks(mWiFiNetworkAgent); - cEmpty4.expectAvailableCallbacks(mWiFiNetworkAgent); + cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + cEmpty3.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertNoCallbacks(cFoo, cBar); mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo")); - cFoo.expectAvailableCallbacks(mWiFiNetworkAgent); + cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); for (TestNetworkCallback c: emptyCallbacks) { c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); } @@ -2208,7 +2253,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar")); cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - cBar.expectAvailableCallbacks(mWiFiNetworkAgent); + cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); for (TestNetworkCallback c: emptyCallbacks) { c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); } @@ -2337,14 +2382,14 @@ public class ConnectivityServiceTest { // Bring up cell and expect CALLBACK_AVAILABLE. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); // Bring up wifi and expect CALLBACK_AVAILABLE. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); cellNetworkCallback.assertNoCallback(); - defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); // Bring down cell. Expect no default network callback, since it wasn't the default. mCellNetworkAgent.disconnect(); @@ -2354,7 +2399,7 @@ public class ConnectivityServiceTest { // Bring up cell. Expect no default network callback, since it won't be the default. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultNetworkCallback.assertNoCallback(); // Bring down wifi. Expect the default network callback to notified of LOST wifi @@ -2362,7 +2407,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); cellNetworkCallback.assertNoCallback(); defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); mCellNetworkAgent.disconnect(); cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); @@ -2383,7 +2428,7 @@ public class ConnectivityServiceTest { // We should get onAvailable(), onCapabilitiesChanged(), and // onLinkPropertiesChanged() in rapid succession. Additionally, we // should get onCapabilitiesChanged() when the mobile network validates. - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); // Update LinkProperties. @@ -2404,7 +2449,7 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(dfltNetworkCallback); // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(), // as well as onNetworkSuspended() in rapid succession. - dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent); + dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true); dfltNetworkCallback.assertNoCallback(); mCm.unregisterNetworkCallback(dfltNetworkCallback); @@ -2444,18 +2489,18 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertTrue(isForegroundNetwork(mCellNetworkAgent)); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); // When wifi connects, cell lingers. - callback.expectAvailableCallbacks(mWiFiNetworkAgent); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); - fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); assertTrue(isForegroundNetwork(mCellNetworkAgent)); @@ -2479,8 +2524,8 @@ public class ConnectivityServiceTest { // is currently delivered before the onAvailable() callbacks. // TODO: Fix this. cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); - cellCallback.expectAvailableCallbacks(mCellNetworkAgent); - fgCallback.expectAvailableCallbacks(mCellNetworkAgent); + cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); // Expect a network capabilities update with FOREGROUND, because the most recent // request causes its state to change. callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent); @@ -2500,7 +2545,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); - fgCallback.expectAvailableCallbacks(mCellNetworkAgent); + fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertTrue(isForegroundNetwork(mCellNetworkAgent)); mCm.unregisterNetworkCallback(callback); @@ -2640,7 +2685,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); testFactory.expectAddRequests(2); // Because the cell request changes score twice. mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); testFactory.waitForNetworkRequests(2); assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us. @@ -2731,16 +2776,15 @@ public class ConnectivityServiceTest { // Bring up validated cell. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); - defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); Network cellNetwork = mCellNetworkAgent.getNetwork(); // Bring up validated wifi. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); // Fail validation on wifi. @@ -2761,18 +2805,18 @@ public class ConnectivityServiceTest { // that we switch back to cell. tracker.configRestrictsAvoidBadWifi = false; tracker.reevaluate(); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); // Switch back to a restrictive carrier. tracker.configRestrictsAvoidBadWifi = true; tracker.reevaluate(); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); // Simulate the user selecting "switch" on the dialog, and check that we switch to cell. mCm.setAvoidUnvalidated(wifiNetwork); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( NET_CAPABILITY_VALIDATED)); assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability( @@ -2783,9 +2827,8 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); - defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent); - validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); wifiNetwork = mWiFiNetworkAgent.getNetwork(); // Fail validation on wifi and expect the dialog to appear. @@ -2799,7 +2842,7 @@ public class ConnectivityServiceTest { tracker.reevaluate(); // We now switch to cell. - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability( NET_CAPABILITY_VALIDATED)); assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability( @@ -2810,17 +2853,17 @@ public class ConnectivityServiceTest { // We switch to wifi and then to cell. Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null); tracker.reevaluate(); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mCm.getActiveNetwork(), wifiNetwork); Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1); tracker.reevaluate(); - defaultCallback.expectAvailableCallbacks(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); assertEquals(mCm.getActiveNetwork(), cellNetwork); // If cell goes down, we switch to wifi. mCellNetworkAgent.disconnect(); defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); - defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); validatedWifiCallback.assertNoCallback(); mCm.unregisterNetworkCallback(cellNetworkCallback); @@ -2862,7 +2905,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); - networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs); + networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, timeoutMs); // pass timeout and validate that UNAVAILABLE is not called networkCallback.assertNoCallback(); @@ -2883,7 +2926,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); final int assertTimeoutMs = 100; - networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs); + networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, assertTimeoutMs); mWiFiNetworkAgent.disconnect(); networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); @@ -3370,7 +3413,7 @@ public class ConnectivityServiceTest { // Bring up wifi aware network. wifiAware.connect(false, false); - callback.expectAvailableCallbacks(wifiAware); + callback.expectAvailableCallbacksUnvalidated(wifiAware); assertNull(mCm.getActiveNetworkInfo()); assertNull(mCm.getActiveNetwork()); @@ -3489,6 +3532,44 @@ public class ConnectivityServiceTest { reset(mStatsService); } + @Test + public void testBasicDnsConfigurationPushed() throws Exception { + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + waitForIdle(); + verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork( + anyInt(), any(), any(), any(), anyBoolean(), anyString()); + + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName("test_rmnet_data0"); + mCellNetworkAgent.sendLinkProperties(cellLp); + mCellNetworkAgent.connect(false); + waitForIdle(); + verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( + anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString()); + // CS tells netd about the empty DNS config for this network. + assertEmpty(mStringArrayCaptor.getValue()); + reset(mNetworkManagementService); + + cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); + mCellNetworkAgent.sendLinkProperties(cellLp); + waitForIdle(); + verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( + anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString()); + assertEquals(1, mStringArrayCaptor.getValue().length); + assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1")); + reset(mNetworkManagementService); + + cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); + mCellNetworkAgent.sendLinkProperties(cellLp); + waitForIdle(); + verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( + anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString()); + assertEquals(2, mStringArrayCaptor.getValue().length); + assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + new String[]{"2001:db8::1", "192.0.2.1"})); + reset(mNetworkManagementService); + } + private void checkDirectlyConnectedRoutes(Object callbackObj, Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) { assertTrue(callbackObj instanceof LinkProperties); diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 80e42a33b3cc..4fbb228e6e53 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -32,7 +32,6 @@ import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; import android.net.IpSecSpiResponse; -import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.NetworkUtils; import android.os.Binder; @@ -54,14 +53,14 @@ import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class IpSecServiceParameterizedTest { - private static final int TEST_SPI_OUT = 0xD1201D; - private static final int TEST_SPI_IN = TEST_SPI_OUT + 1; + private static final int TEST_SPI = 0xD1201D; - private final String mRemoteAddr; + private final String mDestinationAddr; + private final String mSourceAddr; @Parameterized.Parameters public static Collection ipSecConfigs() { - return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}}); + return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}}); } private static final byte[] AEAD_KEY = { @@ -96,11 +95,9 @@ public class IpSecServiceParameterizedTest { private static final IpSecAlgorithm AEAD_ALGO = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); - private static final int[] DIRECTIONS = - new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT}; - - public IpSecServiceParameterizedTest(String remoteAddr) { - mRemoteAddr = remoteAddr; + public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) { + mSourceAddr = sourceAddr; + mDestinationAddr = destAddr; } @Before @@ -116,44 +113,30 @@ public class IpSecServiceParameterizedTest { @Test public void testIpSecServiceReserveSpi() throws Exception { - when(mMockNetd.ipSecAllocateSpi( - anyInt(), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - eq(mRemoteAddr), - eq(TEST_SPI_OUT))) - .thenReturn(TEST_SPI_OUT); + when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI))) + .thenReturn(TEST_SPI); IpSecSpiResponse spiResp = mIpSecService.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); + mDestinationAddr, TEST_SPI, new Binder()); assertEquals(IpSecManager.Status.OK, spiResp.status); - assertEquals(TEST_SPI_OUT, spiResp.spi); + assertEquals(TEST_SPI, spiResp.spi); } @Test public void testReleaseSecurityParameterIndex() throws Exception { - when(mMockNetd.ipSecAllocateSpi( - anyInt(), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - eq(mRemoteAddr), - eq(TEST_SPI_OUT))) - .thenReturn(TEST_SPI_OUT); + when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI))) + .thenReturn(TEST_SPI); IpSecSpiResponse spiResp = mIpSecService.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); + mDestinationAddr, TEST_SPI, new Binder()); mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId); verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(spiResp.resourceId), - anyInt(), - anyString(), - anyString(), - eq(TEST_SPI_OUT)); + eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI)); // Verify quota and RefcountedResource objects cleaned up IpSecService.UserRecord userRecord = @@ -169,17 +152,12 @@ public class IpSecServiceParameterizedTest { @Test public void testSecurityParameterIndexBinderDeath() throws Exception { - when(mMockNetd.ipSecAllocateSpi( - anyInt(), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - eq(mRemoteAddr), - eq(TEST_SPI_OUT))) - .thenReturn(TEST_SPI_OUT); + when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI))) + .thenReturn(TEST_SPI); IpSecSpiResponse spiResp = mIpSecService.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); + mDestinationAddr, TEST_SPI, new Binder()); IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); @@ -190,11 +168,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(spiResp.resourceId), - anyInt(), - anyString(), - anyString(), - eq(TEST_SPI_OUT)); + eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI)); // Verify quota and RefcountedResource objects cleaned up assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent); @@ -206,14 +180,12 @@ public class IpSecServiceParameterizedTest { } } - private int getNewSpiResourceId(int direction, String remoteAddress, int returnSpi) - throws Exception { - when(mMockNetd.ipSecAllocateSpi(anyInt(), anyInt(), anyString(), anyString(), anyInt())) + private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception { + when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt())) .thenReturn(returnSpi); IpSecSpiResponse spi = mIpSecService.allocateSecurityParameterIndex( - direction, NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(), IpSecManager.INVALID_SECURITY_PARAMETER_INDEX, new Binder()); @@ -221,20 +193,14 @@ public class IpSecServiceParameterizedTest { } private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception { - config.setSpiResourceId( - IpSecTransform.DIRECTION_OUT, - getNewSpiResourceId(IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT)); - config.setSpiResourceId( - IpSecTransform.DIRECTION_IN, - getNewSpiResourceId(IpSecTransform.DIRECTION_IN, mRemoteAddr, TEST_SPI_IN)); - config.setRemoteAddress(mRemoteAddr); + config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI)); + config.setSourceAddress(mSourceAddr); + config.setDestinationAddress(mDestinationAddr); } private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception { - for (int direction : DIRECTIONS) { - config.setEncryption(direction, CRYPT_ALGO); - config.setAuthentication(direction, AUTH_ALGO); - } + config.setEncryption(CRYPT_ALGO); + config.setAuthentication(AUTH_ALGO); } @Test @@ -251,32 +217,10 @@ public class IpSecServiceParameterizedTest { .ipSecAddSecurityAssociation( eq(createTransformResp.resourceId), anyInt(), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - anyString(), - anyLong(), - eq(TEST_SPI_OUT), - eq(IpSecAlgorithm.AUTH_HMAC_SHA256), - eq(AUTH_KEY), - anyInt(), - eq(IpSecAlgorithm.CRYPT_AES_CBC), - eq(CRYPT_KEY), - anyInt(), - eq(""), - eq(new byte[] {}), - eq(0), - anyInt(), - anyInt(), - anyInt()); - verify(mMockNetd) - .ipSecAddSecurityAssociation( - eq(createTransformResp.resourceId), - anyInt(), - eq(IpSecTransform.DIRECTION_IN), anyString(), anyString(), anyLong(), - eq(TEST_SPI_IN), + eq(TEST_SPI), eq(IpSecAlgorithm.AUTH_HMAC_SHA256), eq(AUTH_KEY), anyInt(), @@ -296,8 +240,7 @@ public class IpSecServiceParameterizedTest { IpSecConfig ipSecConfig = new IpSecConfig(); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); - ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_OUT, AEAD_ALGO); - ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO); + ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO); IpSecTransformResponse createTransformResp = mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); @@ -307,32 +250,10 @@ public class IpSecServiceParameterizedTest { .ipSecAddSecurityAssociation( eq(createTransformResp.resourceId), anyInt(), - eq(IpSecTransform.DIRECTION_OUT), anyString(), anyString(), anyLong(), - eq(TEST_SPI_OUT), - eq(""), - eq(new byte[] {}), - eq(0), - eq(""), - eq(new byte[] {}), - eq(0), - eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM), - eq(AEAD_KEY), - anyInt(), - anyInt(), - anyInt(), - anyInt()); - verify(mMockNetd) - .ipSecAddSecurityAssociation( - eq(createTransformResp.resourceId), - anyInt(), - eq(IpSecTransform.DIRECTION_IN), - anyString(), - anyString(), - anyLong(), - eq(TEST_SPI_IN), + eq(TEST_SPI), eq(""), eq(new byte[] {}), eq(0), @@ -348,64 +269,6 @@ public class IpSecServiceParameterizedTest { } @Test - public void testCreateInvalidConfigAeadWithAuth() throws Exception { - IpSecConfig ipSecConfig = new IpSecConfig(); - addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); - - for (int direction : DIRECTIONS) { - ipSecConfig.setAuthentication(direction, AUTH_ALGO); - ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO); - } - - try { - mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); - fail( - "IpSecService should have thrown an error on authentication being" - + " enabled with authenticated encryption"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testCreateInvalidConfigAeadWithCrypt() throws Exception { - IpSecConfig ipSecConfig = new IpSecConfig(); - addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); - - for (int direction : DIRECTIONS) { - ipSecConfig.setEncryption(direction, CRYPT_ALGO); - ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO); - } - - try { - mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); - fail( - "IpSecService should have thrown an error on encryption being" - + " enabled with authenticated encryption"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testCreateInvalidConfigAeadWithAuthAndCrypt() throws Exception { - IpSecConfig ipSecConfig = new IpSecConfig(); - addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); - - for (int direction : DIRECTIONS) { - ipSecConfig.setAuthentication(direction, AUTH_ALGO); - ipSecConfig.setEncryption(direction, CRYPT_ALGO); - ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO); - } - - try { - mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); - fail( - "IpSecService should have thrown an error on authentication and encryption being" - + " enabled with authenticated encryption"); - } catch (IllegalArgumentException expected) { - } - } - - @Test public void testDeleteTransportModeTransform() throws Exception { IpSecConfig ipSecConfig = new IpSecConfig(); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); @@ -417,18 +280,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - anyString(), - eq(TEST_SPI_OUT)); - verify(mMockNetd) - .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), - eq(IpSecTransform.DIRECTION_IN), - anyString(), - anyString(), - eq(TEST_SPI_IN)); + eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI)); // Verify quota and RefcountedResource objects cleaned up IpSecService.UserRecord userRecord = @@ -462,18 +314,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - anyString(), - eq(TEST_SPI_OUT)); - verify(mMockNetd) - .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), - eq(IpSecTransform.DIRECTION_IN), - anyString(), - anyString(), - eq(TEST_SPI_IN)); + eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI)); // Verify quota and RefcountedResource objects cleaned up assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent); @@ -497,30 +338,22 @@ public class IpSecServiceParameterizedTest { ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); int resourceId = createTransformResp.resourceId; - mIpSecService.applyTransportModeTransform(pfd, resourceId); + mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId); verify(mMockNetd) .ipSecApplyTransportModeTransform( eq(pfd.getFileDescriptor()), eq(resourceId), - eq(IpSecTransform.DIRECTION_OUT), - anyString(), - anyString(), - eq(TEST_SPI_OUT)); - verify(mMockNetd) - .ipSecApplyTransportModeTransform( - eq(pfd.getFileDescriptor()), - eq(resourceId), - eq(IpSecTransform.DIRECTION_IN), + eq(IpSecManager.DIRECTION_OUT), anyString(), anyString(), - eq(TEST_SPI_IN)); + eq(TEST_SPI)); } @Test public void testRemoveTransportModeTransform() throws Exception { ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); - mIpSecService.removeTransportModeTransform(pfd, 1); + mIpSecService.removeTransportModeTransforms(pfd); verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor()); } diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index 5d1e10eab572..3eba881df427 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -35,6 +35,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.INetd; +import android.net.IpSecAlgorithm; +import android.net.IpSecConfig; import android.net.IpSecManager; import android.net.IpSecSpiResponse; import android.net.IpSecTransform; @@ -76,6 +78,33 @@ public class IpSecServiceTest { private static final InetAddress INADDR_ANY; + private static final byte[] AEAD_KEY = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x73, 0x61, 0x6C, 0x74 + }; + private static final byte[] CRYPT_KEY = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F + }; + private static final byte[] AUTH_KEY = { + 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F + }; + + private static final IpSecAlgorithm AUTH_ALGO = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4); + private static final IpSecAlgorithm CRYPT_ALGO = + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); + private static final IpSecAlgorithm AEAD_ALGO = + new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); @@ -270,6 +299,119 @@ public class IpSecServiceTest { } @Test + public void testValidateAlgorithmsAuth() { + // Validate that correct algorithm type succeeds + IpSecConfig config = new IpSecConfig(); + config.setAuthentication(AUTH_ALGO); + mIpSecService.validateAlgorithms(config); + + // Validate that incorrect algorithm types fails + for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) { + try { + config = new IpSecConfig(); + config.setAuthentication(algo); + mIpSecService.validateAlgorithms(config); + fail("Did not throw exception on invalid algorithm type"); + } catch (IllegalArgumentException expected) { + } + } + } + + @Test + public void testValidateAlgorithmsCrypt() { + // Validate that correct algorithm type succeeds + IpSecConfig config = new IpSecConfig(); + config.setEncryption(CRYPT_ALGO); + mIpSecService.validateAlgorithms(config); + + // Validate that incorrect algorithm types fails + for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) { + try { + config = new IpSecConfig(); + config.setEncryption(algo); + mIpSecService.validateAlgorithms(config); + fail("Did not throw exception on invalid algorithm type"); + } catch (IllegalArgumentException expected) { + } + } + } + + @Test + public void testValidateAlgorithmsAead() { + // Validate that correct algorithm type succeeds + IpSecConfig config = new IpSecConfig(); + config.setAuthenticatedEncryption(AEAD_ALGO); + mIpSecService.validateAlgorithms(config); + + // Validate that incorrect algorithm types fails + for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) { + try { + config = new IpSecConfig(); + config.setAuthenticatedEncryption(algo); + mIpSecService.validateAlgorithms(config); + fail("Did not throw exception on invalid algorithm type"); + } catch (IllegalArgumentException expected) { + } + } + } + + @Test + public void testValidateAlgorithmsAuthCrypt() { + // Validate that correct algorithm type succeeds + IpSecConfig config = new IpSecConfig(); + config.setAuthentication(AUTH_ALGO); + config.setEncryption(CRYPT_ALGO); + mIpSecService.validateAlgorithms(config); + } + + @Test + public void testValidateAlgorithmsNoAlgorithms() { + IpSecConfig config = new IpSecConfig(); + try { + mIpSecService.validateAlgorithms(config); + fail("Expected exception; no algorithms specified"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testValidateAlgorithmsAeadWithAuth() { + IpSecConfig config = new IpSecConfig(); + config.setAuthenticatedEncryption(AEAD_ALGO); + config.setAuthentication(AUTH_ALGO); + try { + mIpSecService.validateAlgorithms(config); + fail("Expected exception; both AEAD and auth algorithm specified"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testValidateAlgorithmsAeadWithCrypt() { + IpSecConfig config = new IpSecConfig(); + config.setAuthenticatedEncryption(AEAD_ALGO); + config.setEncryption(CRYPT_ALGO); + try { + mIpSecService.validateAlgorithms(config); + fail("Expected exception; both AEAD and crypt algorithm specified"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testValidateAlgorithmsAeadWithAuthAndCrypt() { + IpSecConfig config = new IpSecConfig(); + config.setAuthenticatedEncryption(AEAD_ALGO); + config.setAuthentication(AUTH_ALGO); + config.setEncryption(CRYPT_ALGO); + try { + mIpSecService.validateAlgorithms(config); + fail("Expected exception; AEAD, auth and crypt algorithm specified"); + } catch (IllegalArgumentException expected) { + } + } + + @Test public void testDeleteInvalidTransportModeTransform() throws Exception { try { mIpSecService.deleteTransportModeTransform(1); @@ -281,7 +423,7 @@ public class IpSecServiceTest { @Test public void testRemoveTransportModeTransform() throws Exception { ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); - mIpSecService.removeTransportModeTransform(pfd, 1); + mIpSecService.removeTransportModeTransforms(pfd); verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor()); } @@ -294,7 +436,7 @@ public class IpSecServiceTest { try { IpSecSpiResponse spiResp = mIpSecService.allocateSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, address, DROID_SPI, new Binder()); + address, DROID_SPI, new Binder()); fail("Invalid address was passed through IpSecService validation: " + address); } catch (IllegalArgumentException e) { } catch (Exception e) { @@ -366,7 +508,6 @@ public class IpSecServiceTest { // tracks the resource ID. when(mMockNetd.ipSecAllocateSpi( anyInt(), - eq(IpSecTransform.DIRECTION_OUT), anyString(), eq(InetAddress.getLoopbackAddress().getHostAddress()), anyInt())) @@ -375,7 +516,6 @@ public class IpSecServiceTest { for (int i = 0; i < MAX_NUM_SPIS; i++) { IpSecSpiResponse newSpi = mIpSecService.allocateSecurityParameterIndex( - 0x1, InetAddress.getLoopbackAddress().getHostAddress(), DROID_SPI + i, new Binder()); @@ -391,7 +531,6 @@ public class IpSecServiceTest { // Try to reserve one more SPI, and should fail. IpSecSpiResponse extraSpi = mIpSecService.allocateSecurityParameterIndex( - 0x1, InetAddress.getLoopbackAddress().getHostAddress(), DROID_SPI + MAX_NUM_SPIS, new Binder()); @@ -405,7 +544,6 @@ public class IpSecServiceTest { // Should successfully reserve one more spi. extraSpi = mIpSecService.allocateSecurityParameterIndex( - 0x1, InetAddress.getLoopbackAddress().getHostAddress(), DROID_SPI + MAX_NUM_SPIS, new Binder()); diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index c29363cd1a4f..1dbf9b2dfced 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -22,6 +22,7 @@ import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_RESTRICTED; import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -436,11 +437,13 @@ public class VpnTest { .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_NOT_METERED) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) .setLinkDownstreamBandwidthKbps(10)); networks.put(wifi, new NetworkCapabilities() .addTransportType(TRANSPORT_WIFI) .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_NOT_ROAMING) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) .setLinkUpstreamBandwidthKbps(20)); setMockedNetworks(networks); @@ -454,6 +457,7 @@ public class VpnTest { assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); @@ -463,6 +467,7 @@ public class VpnTest { assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); @@ -472,6 +477,7 @@ public class VpnTest { assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); @@ -481,6 +487,7 @@ public class VpnTest { assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); } /** |