diff options
68 files changed, 3799 insertions, 764 deletions
diff --git a/Android.bp b/Android.bp index d4b15caf3047..34cc52c46693 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", @@ -595,6 +596,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..2d74249d9bb9 100644 --- a/Android.mk +++ b/Android.mk @@ -698,4 +698,4 @@ ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call first-makefiles-under,$(LOCAL_PATH)) endif -endif # ANDROID_BUILD_EMBEDDED +endif # ANDROID_BUILD_EMBEDDED
\ No newline at end of file diff --git a/api/current.txt b/api/current.txt index d9d2dfe8b20c..392f4db7edd9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35516,7 +35516,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 +35529,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 +37411,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 +39430,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); @@ -40088,8 +40093,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(); @@ -40101,8 +40111,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(); @@ -40119,8 +40128,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(); @@ -40136,8 +40144,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(); @@ -40468,11 +40485,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); @@ -40485,6 +40504,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 { @@ -40729,11 +40749,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(); @@ -40743,12 +40764,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); @@ -40909,6 +40931,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 e2a7ae498ca2..4eb5c0875e6d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4047,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); diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index a1382428a61a..a68f485f4374 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -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/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/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/Seccomp.java b/core/java/android/os/Seccomp.java index 335e44b65711..f14e93fe9403 100644 --- a/core/java/android/os/Seccomp.java +++ b/core/java/android/os/Seccomp.java @@ -20,6 +20,5 @@ package android.os; * @hide */ public final class Seccomp { - public static native void setSystemServerPolicy(); - public static native void setAppPolicy(); + public static final native void setPolicy(); } 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.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/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index ebebad2950ce..3ee8b472869b 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -17,7 +17,6 @@ package com.android.internal.os; -import android.os.Seccomp; import android.os.Trace; import dalvik.system.ZygoteHooks; import android.system.ErrnoException; @@ -156,9 +155,6 @@ public final class Zygote { */ public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { - // Set system server specific seccomp policy. - Seccomp.setSystemServerPolicy(); - VM_HOOKS.preFork(); // Resets nice priority for zygote process. resetNicePriority(); diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 24c4a8d8d438..6a87b1f4d3fd 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -30,7 +30,6 @@ import android.net.Credentials; import android.net.LocalSocket; import android.os.FactoryTest; import android.os.Process; -import android.os.Seccomp; import android.os.SystemProperties; import android.os.Trace; import android.system.ErrnoException; @@ -768,9 +767,6 @@ class ZygoteConnection { Process.setArgV0(parsedArgs.niceName); } - // Set app specific seccomp policy. - Seccomp.setAppPolicy(); - // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (parsedArgs.invokeWith != null) { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 40168328c5bc..2be6212b9f1e 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -782,6 +782,9 @@ public class ZygoteInit { // Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); + // Set seccomp policy + Seccomp.setPolicy(); + ZygoteHooks.stopZygoteNoThreadCreation(); if (startSystemServer) { diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp index b9006e4403cd..06e2a167de0a 100644 --- a/core/jni/android_os_seccomp.cpp +++ b/core/jni/android_os_seccomp.cpp @@ -21,33 +21,20 @@ #include "seccomp_policy.h" -static void Seccomp_setSystemServerPolicy(JNIEnv* /*env*/) { +static void Seccomp_setPolicy(JNIEnv* /*env*/) { if (security_getenforce() == 0) { ALOGI("seccomp disabled by setenforce 0"); return; } - if (!set_system_seccomp_filter()) { - ALOGE("Failed to set seccomp policy - killing"); - exit(1); - } -} - -static void Seccomp_setAppPolicy(JNIEnv* /*env*/) { - if (security_getenforce() == 0) { - ALOGI("seccomp disabled by setenforce 0"); - return; - } - - if (!set_app_seccomp_filter()) { + if (!set_seccomp_filter()) { ALOGE("Failed to set seccomp policy - killing"); exit(1); } } static const JNINativeMethod method_table[] = { - NATIVE_METHOD(Seccomp, setSystemServerPolicy, "()V"), - NATIVE_METHOD(Seccomp, setAppPolicy, "()V"), + NATIVE_METHOD(Seccomp, setPolicy, "()V"), }; namespace android { 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/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/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/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5228498ba883..f34730c084fc 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -130,6 +130,7 @@ 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.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; @@ -232,8 +233,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; @@ -407,6 +406,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 +857,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultinetworkPolicyTracker = createMultinetworkPolicyTracker( mContext, mHandler, () -> rematchForAvoidBadWifiUpdate()); mMultinetworkPolicyTracker.start(); + + mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties); } private Tethering makeTethering() { @@ -1803,24 +1805,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( @@ -4558,41 +4542,17 @@ public class ConnectivityService extends IConnectivityManager.Stub return; // no updating necessary } + final NetworkAgentInfo defaultNai = getDefaultNetwork(); + final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); + 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()); + mDnsManager.setDnsConfigurationForNetwork( + netId, dnses, newLp.getDomains(), isDefaultNetwork); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); } - final NetworkAgentInfo defaultNai = getDefaultNetwork(); - if (defaultNai != null && defaultNai.network.netId == netId) { - setDefaultDnsSystemProperties(dnses); - } - flushVmDnsCache(); - } - - 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, ""); - } - 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); - } catch (Exception e) { - Log.e(TAG, "Error setting unsupported net.dns property: ", e); - } } private String getNetworkPermission(NetworkCapabilities nc) { @@ -4865,7 +4825,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) { diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 8a15ded2960f..40e6d2645b69 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -18,6 +18,7 @@ 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; @@ -209,12 +210,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 +1763,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,66 +1944,14 @@ 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); } 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..a4170cede361 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -0,0 +1,226 @@ +/* + * 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_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.NetworkUtils; +import android.os.Binder; +import android.os.INetworkManagementService; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.server.connectivity.MockableSystemProperties; + +import java.net.InetAddress; +import java.util.Collection; + + +/** + * 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; + + private final Context mContext; + private final ContentResolver mContentResolver; + private final INetworkManagementService mNMS; + private final MockableSystemProperties mSystemProperties; + + 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; + + // TODO: Create and register ContentObservers to track every setting + // used herein, posting messages to respond to changes. + } + + public boolean isPrivateDnsInStrictMode() { + return !TextUtils.isEmpty(mPrivateDnsMode) && + mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) && + !TextUtils.isEmpty(mPrivateDnsSpecifier); + } + + public void setDnsConfigurationForNetwork( + int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) { + updateParametersSettings(); + updatePrivateDnsSettings(); + + final String[] serverStrs = NetworkUtils.makeStrings(servers); + final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" "); + final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; + final boolean useTls = shouldUseTls(mPrivateDnsMode); + // 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 = ""; + 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(servers); + 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 updatePrivateDnsSettings() { + mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE); + mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER); + } + + 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 String getStringSetting(String which) { + return Settings.Global.getString(mContentResolver, which); + } + + 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 boolean shouldUseTls(String mode) { + if (TextUtils.isEmpty(mode)) { + mode = PRIVATE_DNS_DEFAULT_MODE; + } + return mode.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) || + mode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + } +} 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/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/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 72b2211f1a82..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; @@ -120,7 +118,6 @@ 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_SM = "shutdown_storage_manager"; @@ -415,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(); @@ -627,27 +624,10 @@ public final class ShutdownThread extends Thread { Thread t = new Thread() { public void run() { TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog(); - boolean bluetoothReadyForShutdown; boolean radioOff; final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - final IBluetoothManager bluetooth = - IBluetoothManager.Stub.asInterface(ServiceManager.checkService( - BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE)); - - 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(); @@ -661,7 +641,7 @@ public final class ShutdownThread extends Thread { radioOff = true; } - Log.i(TAG, "Waiting for Bluetooth and Radio..."); + Log.i(TAG, "Waiting for Radio..."); long delay = endTime - SystemClock.elapsedRealtime(); while (delay > 0) { @@ -672,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(); @@ -706,8 +667,8 @@ public final class ShutdownThread extends Thread { } } - if (radioOff && bluetoothReadyForShutdown) { - Log.i(TAG, "Radio and Bluetooth shutdown complete."); + if (radioOff) { + Log.i(TAG, "Radio shutdown complete."); done[0] = true; break; } @@ -724,7 +685,7 @@ public final class ShutdownThread extends Thread { } catch (InterruptedException ex) { } if (!done[0]) { - Log.w(TAG, "Timed out waiting for Radio and Bluetooth shutdown."); + Log.w(TAG, "Timed out waiting for Radio shutdown."); } } 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..1b057f9b9681 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -434,6 +434,8 @@ public class UsbDeviceManager { 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); @@ -662,8 +664,7 @@ public class UsbDeviceManager { } if ((!functions.equals(oemFunctions) && - (mCurrentOemFunctions == null || - !mCurrentOemFunctions.equals(oemFunctions))) + !mCurrentOemFunctions.equals(oemFunctions)) || !mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied || forceRestart) { 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/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/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/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0a8d9cb4197a..d0fb9821eefd 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1006,6 +1006,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 +2019,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/CellIdentity.aidl b/telephony/java/android/telephony/CellIdentity.aidl new file mode 100644 index 000000000000..aeee769edab2 --- /dev/null +++ b/telephony/java/android/telephony/CellIdentity.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 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/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java index 85a4ed8e465e..81e7ed0111f4 100644 --- a/telephony/java/android/telephony/RadioAccessSpecifier.java +++ b/telephony/java/android/telephony/RadioAccessSpecifier.java @@ -72,8 +72,16 @@ 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; + } } /** @@ -93,12 +101,12 @@ public final class RadioAccessSpecifier implements Parcelable { * 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..e0b6f610ab55 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -2693,6 +2693,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 +2705,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..f278d7c22e75 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5676,39 +5676,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 +5724,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 */ @@ -6898,4 +6890,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/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/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 64083e38de31..b0af9a84553b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -870,16 +870,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. 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..2b0349c6fa83 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)); @@ -3489,6 +3500,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); |