Merge "Add constants for reporting criteria"
diff --git a/Android.bp b/Android.bp
index cbb4369..80df8c5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -478,7 +478,8 @@
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
- "telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl",
+ "telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
+ "telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl",
"telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
"telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
"telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
@@ -903,6 +904,7 @@
],
resourcesdir: "docs/html/reference/images",
resourcesoutdir: "reference/android/images",
+ installable: false,
}
droiddoc {
@@ -914,14 +916,11 @@
"core/java/overview.html",
":current-support-api",
],
- args: framework_docs_args +
- "-referenceonly -api $(genDir)/PACKAGING/public_api.txt -privateApi $(genDir)/PACKAGING/private.txt "+
- "-privateDexApi $(genDir)/PACKAGING/private-dex.txt -removedApi $(genDir)/PACKAGING/removed.txt -nodocs",
- out: [
- "PACKAGING/public_api.txt",
- "PACKAGING/private.txt",
- "PACKAGING/private-dex.txt",
- ]
+ api_filename: "public_api.txt",
+ private_api_filename: "private.txt",
+ private_dex_api_filename: "private-dex.txt",
+ removed_api_filename: "removed.txt",
+ args: framework_docs_args + " -referenceonly -nodocs",
}
droiddoc {
@@ -933,16 +932,13 @@
"core/java/overview.html",
":current-support-api",
],
- args: framework_docs_args +
- "-referenceonly -showAnnotation android.annotation.SystemApi " +
- "-api $(genDir)/PACKAGING/system-api.txt -privateApi $(genDir)/PACKAGING/system-private.txt " +
- "-privateDexApi $(genDir)/PACKAGING/system-private-dex.txt -removedApi $(genDir)/PACKAGING/system-removed.txt " +
- "-exactApi $(genDir)/PACKAGING/system-exact.txt -nodocs",
- out: [
- "PACKAGING/system-api.txt",
- "PACKAGING/system-private.txt",
- "PACKAGING/system-private-dex.txt",
- ]
+ api_tag_name: "SYSTEM",
+ api_filename: "system-api.txt",
+ private_api_filename: "system-private.txt",
+ private_dex_api_filename: "system-private-dex.txt",
+ removed_api_filename: "system-removed.txt",
+ exact_api_filename: "system-exact.txt",
+ args: framework_docs_args + " -referenceonly -showAnnotation android.annotation.SystemApi -nodocs",
}
droiddoc {
@@ -954,12 +950,9 @@
"core/java/overview.html",
":current-support-api",
],
- args: framework_docs_args +
- "-referenceonly -showAnnotation android.annotation.TestApi " +
- "-api $(genDir)/PACKAGING/test-api.txt " +
- "-removedApi $(genDir)/PACKAGING/test-removed.txt " +
- "-exactApi $(genDir)/PACKAGING/test-exact.txt -nodocs",
- out: [
- "PACKAGING/test-api.txt",
- ]
+ api_tag_name: "TEST",
+ api_filename: "test-api.txt",
+ removed_api_filename: "test-removed.txt",
+ exact_api_filename: "test-exact.txt",
+ args: framework_docs_args + " -referenceonly -showAnnotation android.annotation.TestApi -nodocs",
}
diff --git a/Android.mk b/Android.mk
index 147d2cf..b5b4627 100644
--- a/Android.mk
+++ b/Android.mk
@@ -260,116 +260,9 @@
-federate SupportLib https://developer.android.com \
-federationapi SupportLib prebuilts/sdk/current/support-api.txt
-# ==== the api stubs and current.xml ===========================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
-LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-
-LOCAL_MODULE := api-stubs
-
-LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src
-
-LOCAL_DROIDDOC_OPTIONS:=\
- $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
- -referenceonly \
- -api $(INTERNAL_PLATFORM_API_FILE) \
- -privateApi $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
- -privateDexApi $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
- -removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
- -nodocs
-
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
-
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_DROIDDOC)
-
-$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_API_FILE) \
- $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
- $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
-
-# ==== the system api stubs ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
-LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-
-LOCAL_MODULE := system-api-stubs
-
-LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_system_stubs_current_intermediates/src
-
-LOCAL_DROIDDOC_OPTIONS:=\
- $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
- -referenceonly \
- -showAnnotation android.annotation.SystemApi \
- -api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
- -privateApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
- -privateDexApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE) \
- -removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
- -exactApi $(INTERNAL_PLATFORM_SYSTEM_EXACT_API_FILE) \
- -nodocs
-
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
-
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_DROIDDOC)
-
-$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
- $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
- $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
-
-# ==== the test api stubs ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
-LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-
-LOCAL_MODULE := test-api-stubs
-
-LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src
-
-LOCAL_DROIDDOC_OPTIONS:=\
- $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
- -referenceonly \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
- -showAnnotation android.annotation.TestApi \
- -api $(INTERNAL_PLATFORM_TEST_API_FILE) \
- -removedApi $(INTERNAL_PLATFORM_TEST_REMOVED_API_FILE) \
- -exactApi $(INTERNAL_PLATFORM_TEST_EXACT_API_FILE) \
- -nodocs
-
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
-
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_DROIDDOC)
-
-$(INTERNAL_PLATFORM_TEST_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
# ==== check javadoc comments but don't generate docs ========
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 50a5974..75b7491 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,4 +6,5 @@
packages/PrintSpooler/
services/print/
services/usb/
+ telephony/
diff --git a/api/current.txt b/api/current.txt
index ca505eb..749c710 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7922,7 +7922,7 @@
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceCallback);
+ method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
@@ -7952,49 +7952,8 @@
field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0
}
- public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
- ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
- method public int describeContents();
- method public int[] toArray();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
- field public static final int MAX = -1; // 0xffffffff
- field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
- field public static final int SERVICE_GUARANTEED = 2; // 0x2
- field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
- field public final int delayVariation;
- field public final int latency;
- field public final int peakBandwidth;
- field public final int serviceType;
- field public final int tokenBucketSize;
- field public final int tokenRate;
- }
-
- public static class BluetoothHidDeviceAppQosSettings.Builder {
- ctor public BluetoothHidDeviceAppQosSettings.Builder();
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings build();
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder delayVariation(int);
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder latency(int);
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder peakBandwidth(int);
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder serviceType(int);
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenBucketSize(int);
- method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenRate(int);
- }
-
- public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
- ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
- field public final java.lang.String description;
- field public final byte[] descriptors;
- field public final java.lang.String name;
- field public final java.lang.String provider;
- field public final byte subclass;
- }
-
- public abstract class BluetoothHidDeviceCallback {
- ctor public BluetoothHidDeviceCallback();
+ public static abstract class BluetoothHidDevice.Callback {
+ ctor public BluetoothHidDevice.Callback();
method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean);
method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int);
method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int);
@@ -8004,6 +7963,35 @@
method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice);
}
+ public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
+ ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
+ method public int describeContents();
+ method public int getDelayVariation();
+ method public int getLatency();
+ method public int getPeakBandwidth();
+ method public int getServiceType();
+ method public int getTokenBucketSize();
+ method public int getTokenRate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
+ field public static final int MAX = -1; // 0xffffffff
+ field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
+ field public static final int SERVICE_GUARANTEED = 2; // 0x2
+ field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
+ }
+
+ public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
+ ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
+ method public int describeContents();
+ method public java.lang.String getDescription();
+ method public byte[] getDescriptors();
+ method public java.lang.String getName();
+ method public java.lang.String getProvider();
+ method public byte getSubclass();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
+ }
+
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -27546,7 +27534,7 @@
field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID";
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
- field public static final java.lang.String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME";
+ field public static final java.lang.String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
field public static final int FLAG_READER_NFC_A = 1; // 0x1
field public static final int FLAG_READER_NFC_B = 2; // 0x2
@@ -37049,10 +37037,8 @@
method public void shutdown();
}
- public static abstract class SEService.SecureElementListener extends android.os.Binder {
- ctor public SEService.SecureElementListener();
- method public android.os.IBinder asBinder();
- method public void serviceConnected();
+ public static abstract interface SEService.SecureElementListener {
+ method public abstract void onServiceConnected();
}
public class Session {
@@ -37062,9 +37048,7 @@
method public android.se.omapi.Reader getReader();
method public boolean isClosed();
method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
- method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
- method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
}
}
@@ -39194,7 +39178,7 @@
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
field public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2; // 0x2
- field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4; // 0x4
+ field public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4; // 0x4
field public static final int HANDOVER_FAILURE_UNKNOWN = 5; // 0x5
field public static final int HANDOVER_FAILURE_USER_REJECTED = 3; // 0x3
}
@@ -40408,6 +40392,8 @@
}
public class MbmsDownloadSession implements java.lang.AutoCloseable {
+ method public int addProgressListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadProgressListener);
+ method public int addStatusListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStatusListener);
method public int cancelDownload(android.telephony.mbms.DownloadRequest);
method public void close();
method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsDownloadSessionCallback);
@@ -40415,12 +40401,12 @@
method public int download(android.telephony.mbms.DownloadRequest);
method public java.io.File getTempFileRootDirectory();
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
- method public int registerStateCallback(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStateCallback);
+ method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener);
+ method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener);
method public void requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo);
method public void requestUpdateFileServices(java.util.List<java.lang.String>);
method public void resetDownloadKnowledge(android.telephony.mbms.DownloadRequest);
method public void setTempFileRootDirectory(java.io.File);
- method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback);
field public static final java.lang.String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot";
field public static final java.lang.String EXTRA_MBMS_COMPLETED_FILE_URI = "android.telephony.extra.MBMS_COMPLETED_FILE_URI";
field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.extra.MBMS_DOWNLOAD_REQUEST";
@@ -40607,17 +40593,17 @@
ctor public ServiceState(android.os.Parcel);
method protected void copyFrom(android.telephony.ServiceState);
method public int describeContents();
+ method public int getCdmaNetworkId();
+ method public int getCdmaSystemId();
method public int[] getCellBandwidths();
method public int getChannelNumber();
method public int getDuplexMode();
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);
@@ -41077,21 +41063,21 @@
public class ApnSetting implements android.os.Parcelable {
method public int describeContents();
method public java.lang.String getApnName();
+ method public int getApnTypeBitmask();
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.net.InetAddress getMmsProxyAddress();
+ method public int getMmsProxyPort();
+ method public android.net.Uri getMmsc();
+ method public int getMvnoType();
method public int getNetworkTypeBitmask();
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 int getProtocol();
+ method public java.net.InetAddress getProxyAddress();
+ method public int getProxyPort();
+ method public int getRoamingProtocol();
method public java.lang.String getUser();
method public boolean isEnabled();
method public void writeToParcel(android.os.Parcel, int);
@@ -41100,46 +41086,45 @@
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";
+ field public static final int MVNO_TYPE_GID = 2; // 0x2
+ field public static final int MVNO_TYPE_ICCID = 3; // 0x3
+ field public static final int MVNO_TYPE_IMSI = 1; // 0x1
+ field public static final int MVNO_TYPE_SPN = 0; // 0x0
+ field public static final int PROTOCOL_IP = 0; // 0x0
+ field public static final int PROTOCOL_IPV4V6 = 2; // 0x2
+ field public static final int PROTOCOL_IPV6 = 1; // 0x1
+ field public static final int PROTOCOL_PPP = 3; // 0x3
+ field public static final int TYPE_CBS = 128; // 0x80
+ field public static final int TYPE_DEFAULT = 17; // 0x11
+ field public static final int TYPE_DUN = 8; // 0x8
+ field public static final int TYPE_EMERGENCY = 512; // 0x200
+ field public static final int TYPE_FOTA = 32; // 0x20
+ field public static final int TYPE_HIPRI = 16; // 0x10
+ field public static final int TYPE_IA = 256; // 0x100
+ field public static final int TYPE_IMS = 64; // 0x40
+ field public static final int TYPE_MMS = 2; // 0x2
+ field public static final int TYPE_SUPL = 4; // 0x4
}
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 setApnTypeBitmask(int);
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 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 setMmsProxyAddress(java.net.InetAddress);
+ method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
+ method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
+ method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
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 setProtocol(int);
+ method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
+ method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
+ method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String);
}
@@ -41275,6 +41260,11 @@
package android.telephony.mbms {
+ public class DownloadProgressListener {
+ ctor public DownloadProgressListener();
+ method public void onProgressUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int, int, int, int);
+ }
+
public final class DownloadRequest implements android.os.Parcelable {
method public int describeContents();
method public android.net.Uri getDestinationUri();
@@ -41298,15 +41288,9 @@
method public android.telephony.mbms.DownloadRequest.Builder setSubscriptionId(int);
}
- public class DownloadStateCallback {
- ctor public DownloadStateCallback();
- ctor public DownloadStateCallback(int);
- method public final boolean isFilterFlagSet(int);
- method public void onProgressUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int, int, int, int);
- method public void onStateUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int);
- field public static final int ALL_UPDATES = 0; // 0x0
- field public static final int PROGRESS_UPDATES = 1; // 0x1
- field public static final int STATE_UPDATES = 2; // 0x2
+ public class DownloadStatusListener {
+ ctor public DownloadStatusListener();
+ method public void onStatusUpdated(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo, int);
}
public final class FileInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index ceb070b..31a6d4d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2611,8 +2611,10 @@
}
public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+ method public void addAddress(android.net.LinkAddress) throws java.io.IOException;
method public void close();
method public java.lang.String getInterfaceName();
+ method public void removeAddress(android.net.LinkAddress) throws java.io.IOException;
}
public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -4357,12 +4359,13 @@
}
public class UiccSlotInfo implements android.os.Parcelable {
- ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int);
+ ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int, boolean);
method public int describeContents();
method public java.lang.String getCardId();
method public int getCardStateInfo();
method public boolean getIsActive();
method public boolean getIsEuicc();
+ method public boolean getIsExtendedApduSupported();
method public int getLogicalSlotIdx();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
@@ -4530,6 +4533,7 @@
public class EuiccManager {
method public void continueOperation(android.content.Intent, android.os.Bundle);
+ method public void eraseSubscriptions(android.app.PendingIntent);
method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method public int getOtaStatus();
@@ -5343,18 +5347,20 @@
public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
+ method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
+ method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public void dispose(int) throws android.os.RemoteException;
method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
method public void onAppCallbackDied(int, int);
- method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+ method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
+ method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
- method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
}
public class MbmsStreamingServiceBase extends android.os.Binder {
diff --git a/api/test-current.txt b/api/test-current.txt
index bf3d0c2..ce6810f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -436,6 +436,10 @@
field public static final java.lang.String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
+ public class ServiceState implements android.os.Parcelable {
+ method public void setCdmaSystemAndNetworkId(int, int);
+ }
+
}
package android.telephony.mbms {
@@ -466,18 +470,20 @@
public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
+ method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
+ method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public void dispose(int) throws android.os.RemoteException;
method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
method public void onAppCallbackDied(int, int);
- method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+ method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
+ method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
- method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
}
public class MbmsStreamingServiceBase extends android.os.Binder {
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 1671337..12083b6 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -13,6 +13,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <android-base/macros.h>
#include <binder/IPCThreadState.h>
#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
@@ -137,27 +138,12 @@
}
static void maybeCreateDalvikCache() {
-#if defined(__aarch64__)
- static const char kInstructionSet[] = "arm64";
-#elif defined(__x86_64__)
- static const char kInstructionSet[] = "x86_64";
-#elif defined(__arm__)
- static const char kInstructionSet[] = "arm";
-#elif defined(__i386__)
- static const char kInstructionSet[] = "x86";
-#elif defined (__mips__) && !defined(__LP64__)
- static const char kInstructionSet[] = "mips";
-#elif defined (__mips__) && defined(__LP64__)
- static const char kInstructionSet[] = "mips64";
-#else
-#error "Unknown instruction set"
-#endif
const char* androidRoot = getenv("ANDROID_DATA");
LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");
char dalvikCacheDir[PATH_MAX];
const int numChars = snprintf(dalvikCacheDir, PATH_MAX,
- "%s/dalvik-cache/%s", androidRoot, kInstructionSet);
+ "%s/dalvik-cache/" ABI_STRING, androidRoot);
LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
"Error constructing dalvik cache : %s", strerror(errno));
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 565eaeb..bae2a26 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -612,7 +612,7 @@
streamingOutput);
profiling = true;
} catch (RuntimeException e) {
- Slog.w(TAG, "Profiling failed on path " + profileFile);
+ Slog.w(TAG, "Profiling failed on path " + profileFile, e);
try {
profileFd.close();
profileFd = null;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index be4e207..6aabe18 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -676,6 +676,10 @@
if (!getLeAccess()) {
return null;
}
+ if (!isMultipleAdvertisementSupported()) {
+ Log.e(TAG, "Bluetooth LE advertising not supported");
+ return null;
+ }
synchronized (mLock) {
if (sBluetoothLeAdvertiser == null) {
sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 2fab305..a3d6968 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -27,8 +27,8 @@
import android.util.Log;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Provides the public APIs to control the Bluetooth HID Device profile.
@@ -37,7 +37,6 @@
* Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
*/
public final class BluetoothHidDevice implements BluetoothProfile {
-
private static final String TAG = BluetoothHidDevice.class.getSimpleName();
/**
@@ -62,106 +61,327 @@
"android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
/**
- * Constants representing device subclass.
+ * Constant representing unspecified HID device subclass.
*
* @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
*/
public static final byte SUBCLASS1_NONE = (byte) 0x00;
+ /**
+ * Constant representing keyboard subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
+ /**
+ * Constant representing mouse subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
+ /**
+ * Constant representing combo keyboard and mouse subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
+ /**
+ * Constant representing uncategorized HID device subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
+ /**
+ * Constant representing joystick subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
+ /**
+ * Constant representing gamepad subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
+ /**
+ * Constant representing remote control subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
+ /**
+ * Constant representing sensing device subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
+ /**
+ * Constant representing digitizer tablet subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
+ /**
+ * Constant representing card reader subclass.
+ *
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)
+ */
public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
/**
- * Constants representing report types.
+ * Constant representing HID Input Report type.
*
- * @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)
- * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
- * @see BluetoothHidDeviceCallback#onInterruptData(BluetoothDevice, byte, byte[])
+ * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
*/
public static final byte REPORT_TYPE_INPUT = (byte) 1;
+ /**
+ * Constant representing HID Output Report type.
+ *
+ * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
+ */
public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
+ /**
+ * Constant representing HID Feature Report type.
+ *
+ * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
+ */
public static final byte REPORT_TYPE_FEATURE = (byte) 3;
/**
- * Constants representing error response for Set Report.
+ * Constant representing success response for Set Report.
*
- * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
*/
public static final byte ERROR_RSP_SUCCESS = (byte) 0;
+ /**
+ * Constant representing error response for Set Report due to "not ready".
+ *
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ */
public static final byte ERROR_RSP_NOT_READY = (byte) 1;
+ /**
+ * Constant representing error response for Set Report due to "invalid report ID".
+ *
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ */
public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
+ /**
+ * Constant representing error response for Set Report due to "unsupported request".
+ *
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ */
public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
+ /**
+ * Constant representing error response for Set Report due to "invalid parameter".
+ *
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ */
public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
+ /**
+ * Constant representing error response for Set Report with unknown reason.
+ *
+ * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
+ */
public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
/**
- * Constants representing protocol mode used set by host. Default is always {@link
+ * Constant representing boot protocol mode used set by host. Default is always {@link
* #PROTOCOL_REPORT_MODE} unless notified otherwise.
*
- * @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
+ * @see Callback#onSetProtocol(BluetoothDevice, byte)
*/
public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
+ /**
+ * Constant representing report protocol mode used set by host. Default is always {@link
+ * #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ *
+ * @see Callback#onSetProtocol(BluetoothDevice, byte)
+ */
public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
+ /**
+ * The template class that applications use to call callback functions on events from the HID
+ * host. Callback functions are wrapped in this class and registered to the Android system
+ * during app registration.
+ */
+ public abstract static class Callback {
+
+ private static final String TAG = "BluetoothHidDevCallback";
+
+ /**
+ * Callback called when application registration state changes. Usually it's called due to
+ * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
+ * Executor, Callback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
+ * unsolicited in case e.g. Bluetooth was turned off in which case application is
+ * unregistered automatically.
+ *
+ * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently
+ * has Virtual Cable established with device. Only valid when application is registered,
+ * can be <code>null</code>.
+ * @param registered <code>true</code> if application is registered, <code>false</code>
+ * otherwise.
+ */
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
+ Log.d(
+ TAG,
+ "onAppStatusChanged: pluggedDevice="
+ + pluggedDevice
+ + " registered="
+ + registered);
+ }
+
+ /**
+ * Callback called when connection state with remote host was changed. Application can
+ * assume than Virtual Cable is established when called with {@link
+ * BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+ *
+ * @param device {@link BluetoothDevice} object representing host device which connection
+ * state was changed.
+ * @param state Connection state as defined in {@link BluetoothProfile}.
+ */
+ public void onConnectionStateChanged(BluetoothDevice device, int state) {
+ Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
+ }
+
+ /**
+ * Callback called when GET_REPORT is received from remote host. Should be replied by
+ * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
+ * byte[])}.
+ *
+ * @param type Requested Report Type.
+ * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
+ * @param bufferSize Requested buffer size, application shall respond with at least given
+ * number of bytes.
+ */
+ public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
+ Log.d(
+ TAG,
+ "onGetReport: device="
+ + device
+ + " type="
+ + type
+ + " id="
+ + id
+ + " bufferSize="
+ + bufferSize);
+ }
+
+ /**
+ * Callback called when SET_REPORT is received from remote host. In case received data are
+ * invalid, application shall respond with {@link
+ * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
+ *
+ * @param type Report Type.
+ * @param id Report Id.
+ * @param data Report data.
+ */
+ public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+ Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
+ }
+
+ /**
+ * Callback called when SET_PROTOCOL is received from remote host. Application shall use
+ * this information to send only reports valid for given protocol mode. By default, {@link
+ * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+ *
+ * @param protocol Protocol Mode.
+ */
+ public void onSetProtocol(BluetoothDevice device, byte protocol) {
+ Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
+ }
+
+ /**
+ * Callback called when report data is received over interrupt channel. Report Type is
+ * assumed to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ *
+ * @param reportId Report Id.
+ * @param data Report data.
+ */
+ public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
+ Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
+ }
+
+ /**
+ * Callback called when Virtual Cable is removed. After this callback is received connection
+ * will be disconnected automatically.
+ */
+ public void onVirtualCableUnplug(BluetoothDevice device) {
+ Log.d(TAG, "onVirtualCableUnplug: device=" + device);
+ }
+ }
+
private Context mContext;
-
private ServiceListener mServiceListener;
-
private volatile IBluetoothHidDevice mService;
-
private BluetoothAdapter mAdapter;
- private static class BluetoothHidDeviceCallbackWrapper
- extends IBluetoothHidDeviceCallback.Stub {
+ private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
- private BluetoothHidDeviceCallback mCallback;
+ private final Executor mExecutor;
+ private final Callback mCallback;
- public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
+ CallbackWrapper(Executor executor, Callback callback) {
+ mExecutor = executor;
mCallback = callback;
}
@Override
public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- mCallback.onAppStatusChanged(pluggedDevice, registered);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered));
}
@Override
public void onConnectionStateChanged(BluetoothDevice device, int state) {
- mCallback.onConnectionStateChanged(device, state);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state));
}
@Override
public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
- mCallback.onGetReport(device, type, id, bufferSize);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize));
}
@Override
public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- mCallback.onSetReport(device, type, id, data);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data));
}
@Override
public void onSetProtocol(BluetoothDevice device, byte protocol) {
- mCallback.onSetProtocol(device, protocol);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol));
}
@Override
public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
- mCallback.onInterruptData(device, reportId, data);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data));
}
@Override
public void onVirtualCableUnplug(BluetoothDevice device) {
- mCallback.onVirtualCableUnplug(device);
+ clearCallingIdentity();
+ mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device));
}
}
@@ -213,8 +433,6 @@
};
BluetoothHidDevice(Context context, ServiceListener listener) {
- Log.v(TAG, "BluetoothHidDevice");
-
mContext = context;
mServiceListener = listener;
mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -245,7 +463,6 @@
}
void doUnbind() {
- Log.d(TAG, "Unbinding HidDevService");
if (mService != null) {
mService = null;
try {
@@ -257,8 +474,6 @@
}
void close() {
- Log.v(TAG, "close()");
-
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
@@ -277,8 +492,6 @@
/** {@inheritDoc} */
@Override
public List<BluetoothDevice> getConnectedDevices() {
- Log.v(TAG, "getConnectedDevices()");
-
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
@@ -290,14 +503,12 @@
Log.w(TAG, "Proxy not attached to service");
}
- return new ArrayList<BluetoothDevice>();
+ return new ArrayList<>();
}
/** {@inheritDoc} */
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
-
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
@@ -309,14 +520,12 @@
Log.w(TAG, "Proxy not attached to service");
}
- return new ArrayList<BluetoothDevice>();
+ return new ArrayList<>();
}
/** {@inheritDoc} */
@Override
public int getConnectionState(BluetoothDevice device) {
- Log.v(TAG, "getConnectionState(): device=" + device);
-
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
@@ -336,9 +545,9 @@
* when application is registered. Only one application can be registered at one time. When an
* application is registered, the HID Host service will be disabled until it is unregistered.
* When no longer used, application should be unregistered using {@link #unregisterApp()}. The
- * registration status should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
- * the return value of this method.
+ * app will be automatically unregistered if it is not foreground. The registration status
+ * should be tracked by the application by handling callback from Callback#onAppStatusChanged.
+ * The app registration status is not related to the return value of this method.
*
* @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
* Device SDP record is required.
@@ -348,27 +557,36 @@
* @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
* Outgoing QoS Settings is not required. Use null or default
* BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
- * sent. The BluetoothHidDeviceCallback object is required.
+ * @param executor {@link Executor} object on which callback will be executed. The Executor
+ * object is required.
+ * @param callback {@link Callback} object to which callback messages will be sent. The Callback
+ * object is required.
* @return true if the command is successfully sent; otherwise false.
*/
- public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
- BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
- BluetoothHidDeviceCallback callback) {
- Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
- + " callback=" + callback);
-
+ public boolean registerApp(
+ BluetoothHidDeviceAppSdpSettings sdp,
+ BluetoothHidDeviceAppQosSettings inQos,
+ BluetoothHidDeviceAppQosSettings outQos,
+ Executor executor,
+ Callback callback) {
boolean result = false;
- if (sdp == null || callback == null) {
- return false;
+ if (sdp == null) {
+ throw new IllegalArgumentException("sdp parameter cannot be null");
+ }
+
+ if (executor == null) {
+ throw new IllegalArgumentException("executor parameter cannot be null");
+ }
+
+ if (callback == null) {
+ throw new IllegalArgumentException("callback parameter cannot be null");
}
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
- BluetoothHidDeviceCallbackWrapper cbw =
- new BluetoothHidDeviceCallbackWrapper(callback);
+ CallbackWrapper cbw = new CallbackWrapper(executor, callback);
result = service.registerApp(sdp, inQos, outQos, cbw);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
@@ -384,16 +602,13 @@
* Unregisters application. Active connection will be disconnected and no new connections will
* be allowed until registered again using {@link #registerApp
* (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should
- * be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
- * the return value of this method.
+ * BluetoothHidDeviceAppQosSettings, Executor, Callback)}. The registration status should be
+ * tracked by the application by handling callback from Callback#onAppStatusChanged. The app
+ * registration status is not related to the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
public boolean unregisterApp() {
- Log.v(TAG, "unregisterApp()");
-
boolean result = false;
final IBluetoothHidDevice service = mService;
@@ -437,7 +652,7 @@
/**
* Sends report to remote host as reply for GET_REPORT request from {@link
- * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
+ * Callback#onGetReport(BluetoothDevice, byte, byte, int)}.
*
* @param type Report Type, as in request.
* @param id Report Id, as in request.
@@ -445,8 +660,6 @@
* @return true if the command is successfully sent; otherwise false.
*/
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
-
boolean result = false;
final IBluetoothHidDevice service = mService;
@@ -465,14 +678,12 @@
/**
* Sends error handshake message as reply for invalid SET_REPORT request from {@link
- * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
+ * Callback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
*
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
*/
public boolean reportError(BluetoothDevice device, byte error) {
- Log.v(TAG, "reportError(): device=" + device + " error=" + error);
-
boolean result = false;
final IBluetoothHidDevice service = mService;
@@ -496,8 +707,6 @@
* {@hide}
*/
public boolean unplug(BluetoothDevice device) {
- Log.v(TAG, "unplug(): device=" + device);
-
boolean result = false;
final IBluetoothHidDevice service = mService;
@@ -517,15 +726,12 @@
/**
* Initiates connection to host which is currently paired with this device. If the application
* is not registered, #connect(BluetoothDevice) will fail. The connection state should be
- * tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to
- * the return value of this method.
+ * tracked by the application by handling callback from Callback#onConnectionStateChanged. The
+ * connection state is not related to the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
public boolean connect(BluetoothDevice device) {
- Log.v(TAG, "connect(): device=" + device);
-
boolean result = false;
final IBluetoothHidDevice service = mService;
@@ -544,14 +750,12 @@
/**
* Disconnects from currently connected host. The connection state should be tracked by the
- * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged.
- * The connection state is not related to the return value of this method.
+ * application by handling callback from Callback#onConnectionStateChanged. The connection state
+ * is not related to the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
public boolean disconnect(BluetoothDevice device) {
- Log.v(TAG, "disconnect(): device=" + device);
-
boolean result = false;
final IBluetoothHidDevice service = mService;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index c05df2d..a485b89 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -29,12 +29,12 @@
*/
public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
- public final int serviceType;
- public final int tokenRate;
- public final int tokenBucketSize;
- public final int peakBandwidth;
- public final int latency;
- public final int delayVariation;
+ private final int mServiceType;
+ private final int mTokenRate;
+ private final int mTokenBucketSize;
+ private final int mPeakBandwidth;
+ private final int mLatency;
+ private final int mDelayVariation;
public static final int SERVICE_NO_TRAFFIC = 0x00;
public static final int SERVICE_BEST_EFFORT = 0x01;
@@ -44,38 +44,53 @@
/**
* Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
- * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
- * Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D for parameters.
+ * Settings is optional. Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and
+ * Appendix D for parameters.
*
- * @param serviceType L2CAP service type
- * @param tokenRate L2CAP token rate
- * @param tokenBucketSize L2CAP token bucket size
- * @param peakBandwidth L2CAP peak bandwidth
- * @param latency L2CAP latency
- * @param delayVariation L2CAP delay variation
+ * @param serviceType L2CAP service type, default = SERVICE_BEST_EFFORT
+ * @param tokenRate L2CAP token rate, default = 0
+ * @param tokenBucketSize L2CAP token bucket size, default = 0
+ * @param peakBandwidth L2CAP peak bandwidth, default = 0
+ * @param latency L2CAP latency, default = MAX
+ * @param delayVariation L2CAP delay variation, default = MAX
*/
- public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
- int peakBandwidth, int latency, int delayVariation) {
- this.serviceType = serviceType;
- this.tokenRate = tokenRate;
- this.tokenBucketSize = tokenBucketSize;
- this.peakBandwidth = peakBandwidth;
- this.latency = latency;
- this.delayVariation = delayVariation;
+ public BluetoothHidDeviceAppQosSettings(
+ int serviceType,
+ int tokenRate,
+ int tokenBucketSize,
+ int peakBandwidth,
+ int latency,
+ int delayVariation) {
+ mServiceType = serviceType;
+ mTokenRate = tokenRate;
+ mTokenBucketSize = tokenBucketSize;
+ mPeakBandwidth = peakBandwidth;
+ mLatency = latency;
+ mDelayVariation = delayVariation;
}
- @Override
- public boolean equals(Object o) {
- if (o instanceof BluetoothHidDeviceAppQosSettings) {
- BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
- return this.serviceType == qos.serviceType
- && this.tokenRate == qos.tokenRate
- && this.tokenBucketSize == qos.tokenBucketSize
- && this.peakBandwidth == qos.peakBandwidth
- && this.latency == qos.latency
- && this.delayVariation == qos.delayVariation;
- }
- return false;
+ public int getServiceType() {
+ return mServiceType;
+ }
+
+ public int getTokenRate() {
+ return mTokenRate;
+ }
+
+ public int getTokenBucketSize() {
+ return mTokenBucketSize;
+ }
+
+ public int getPeakBandwidth() {
+ return mPeakBandwidth;
+ }
+
+ public int getLatency() {
+ return mLatency;
+ }
+
+ public int getDelayVariation() {
+ return mDelayVariation;
}
@Override
@@ -106,104 +121,11 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(serviceType);
- out.writeInt(tokenRate);
- out.writeInt(tokenBucketSize);
- out.writeInt(peakBandwidth);
- out.writeInt(latency);
- out.writeInt(delayVariation);
- }
-
- /** @return an int array representation of this instance */
- public int[] toArray() {
- return new int[] {
- serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
- };
- }
-
- /** A helper to build the BluetoothHidDeviceAppQosSettings object. */
- public static class Builder {
- // Optional parameters - initialized to default values
- private int mServiceType = SERVICE_BEST_EFFORT;
- private int mTokenRate = 0;
- private int mTokenBucketSize = 0;
- private int mPeakBandwidth = 0;
- private int mLatency = MAX;
- private int mDelayVariation = MAX;
-
- /**
- * Set the service type.
- *
- * @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
- * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
- * @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
- */
- public Builder serviceType(int val) {
- mServiceType = val;
- return this;
- }
- /**
- * Set the token rate.
- *
- * @param val token rate
- * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
- */
- public Builder tokenRate(int val) {
- mTokenRate = val;
- return this;
- }
-
- /**
- * Set the bucket size.
- *
- * @param val bucket size
- * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
- */
- public Builder tokenBucketSize(int val) {
- mTokenBucketSize = val;
- return this;
- }
-
- /**
- * Set the peak bandwidth.
- *
- * @param val peak bandwidth
- * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
- */
- public Builder peakBandwidth(int val) {
- mPeakBandwidth = val;
- return this;
- }
- /**
- * Set the latency.
- *
- * @param val latency
- * @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
- */
- public Builder latency(int val) {
- mLatency = val;
- return this;
- }
-
- /**
- * Set the delay variation.
- *
- * @param val delay variation
- * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
- */
- public Builder delayVariation(int val) {
- mDelayVariation = val;
- return this;
- }
-
- /**
- * Build the BluetoothHidDeviceAppQosSettings object.
- *
- * @return BluetoothHidDeviceAppQosSettings object with current settings.
- */
- public BluetoothHidDeviceAppQosSettings build() {
- return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize,
- mPeakBandwidth, mLatency, mDelayVariation);
- }
+ out.writeInt(mServiceType);
+ out.writeInt(mTokenRate);
+ out.writeInt(mTokenBucketSize);
+ out.writeInt(mPeakBandwidth);
+ out.writeInt(mLatency);
+ out.writeInt(mDelayVariation);
}
}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 562c559..237082e 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,7 +19,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
/**
* Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
@@ -31,11 +30,11 @@
*/
public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
- public final String name;
- public final String description;
- public final String provider;
- public final byte subclass;
- public final byte[] descriptors;
+ private final String mName;
+ private final String mDescription;
+ private final String mProvider;
+ private final byte mSubclass;
+ private final byte[] mDescriptors;
/**
* Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
@@ -52,24 +51,31 @@
*/
public BluetoothHidDeviceAppSdpSettings(
String name, String description, String provider, byte subclass, byte[] descriptors) {
- this.name = name;
- this.description = description;
- this.provider = provider;
- this.subclass = subclass;
- this.descriptors = descriptors.clone();
+ mName = name;
+ mDescription = description;
+ mProvider = provider;
+ mSubclass = subclass;
+ mDescriptors = descriptors.clone();
}
- @Override
- public boolean equals(Object o) {
- if (o instanceof BluetoothHidDeviceAppSdpSettings) {
- BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
- return this.name.equals(sdp.name)
- && this.description.equals(sdp.description)
- && this.provider.equals(sdp.provider)
- && this.subclass == sdp.subclass
- && Arrays.equals(this.descriptors, sdp.descriptors);
- }
- return false;
+ public String getName() {
+ return mName;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public String getProvider() {
+ return mProvider;
+ }
+
+ public byte getSubclass() {
+ return mSubclass;
+ }
+
+ public byte[] getDescriptors() {
+ return mDescriptors;
}
@Override
@@ -99,10 +105,10 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeString(name);
- out.writeString(description);
- out.writeString(provider);
- out.writeByte(subclass);
- out.writeByteArray(descriptors);
+ out.writeString(mName);
+ out.writeString(mDescription);
+ out.writeString(mProvider);
+ out.writeByte(mSubclass);
+ out.writeByteArray(mDescriptors);
}
}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
deleted file mode 100644
index e71b00f..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.util.Log;
-
-/**
- * The template class that applications use to call callback functions on events from the HID host.
- * Callback functions are wrapped in this class and registered to the Android system during app
- * registration.
- *
- * <p>{@see BluetoothHidDevice}
- */
-public abstract class BluetoothHidDeviceCallback {
-
- private static final String TAG = "BluetoothHidDevCallback";
-
- /**
- * Callback called when application registration state changes. Usually it's called due to
- * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
- * BluetoothHidDeviceCallback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
- * unsolicited in case e.g. Bluetooth was turned off in which case application is unregistered
- * automatically.
- *
- * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has
- * Virtual Cable established with device. Only valid when application is registered, can be
- * <code>null</code>.
- * @param registered <code>true</code> if application is registered, <code>false</code>
- * otherwise.
- */
- public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- Log.d(TAG,
- "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered=" + registered);
- }
-
- /**
- * Callback called when connection state with remote host was changed. Application can assume
- * than Virtual Cable is established when called with {@link BluetoothProfile#STATE_CONNECTED}
- * <code>state</code>.
- *
- * @param device {@link BluetoothDevice} object representing host device which connection state
- * was changed.
- * @param state Connection state as defined in {@link BluetoothProfile}.
- */
- public void onConnectionStateChanged(BluetoothDevice device, int state) {
- Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
- }
-
- /**
- * Callback called when GET_REPORT is received from remote host. Should be replied by
- * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
- * byte[])}.
- *
- * @param type Requested Report Type.
- * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
- * @param bufferSize Requested buffer size, application shall respond with at least given number
- * of bytes.
- */
- public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
- Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
- + bufferSize);
- }
-
- /**
- * Callback called when SET_REPORT is received from remote host. In case received data are
- * invalid, application shall respond with {@link
- * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
- *
- * @param type Report Type.
- * @param id Report Id.
- * @param data Report data.
- */
- public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
- }
-
- /**
- * Callback called when SET_PROTOCOL is received from remote host. Application shall use this
- * information to send only reports valid for given protocol mode. By default, {@link
- * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
- *
- * @param protocol Protocol Mode.
- */
- public void onSetProtocol(BluetoothDevice device, byte protocol) {
- Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
- }
-
- /**
- * Callback called when report data is received over interrupt channel. Report Type is assumed
- * to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
- *
- * @param reportId Report Id.
- * @param data Report data.
- */
- public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
- Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
- }
-
- /**
- * Callback called when Virtual Cable is removed. After this callback is
- * received connection will be disconnected automatically.
- */
- public void onVirtualCableUnplug(BluetoothDevice device) {
- Log.d(TAG, "onVirtualCableUnplug: device=" + device);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 656188f..6aeb94d 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -38,7 +38,7 @@
* This extra represents the current connection state of the profile of the
* Bluetooth device.
*/
- public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
+ String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
/**
* Extra for the connection state intents of the individual profiles.
@@ -46,123 +46,130 @@
* This extra represents the previous connection state of the profile of the
* Bluetooth device.
*/
- public static final String EXTRA_PREVIOUS_STATE =
+ String EXTRA_PREVIOUS_STATE =
"android.bluetooth.profile.extra.PREVIOUS_STATE";
/** The profile is in disconnected state */
- public static final int STATE_DISCONNECTED = 0;
+ int STATE_DISCONNECTED = 0;
/** The profile is in connecting state */
- public static final int STATE_CONNECTING = 1;
+ int STATE_CONNECTING = 1;
/** The profile is in connected state */
- public static final int STATE_CONNECTED = 2;
+ int STATE_CONNECTED = 2;
/** The profile is in disconnecting state */
- public static final int STATE_DISCONNECTING = 3;
+ int STATE_DISCONNECTING = 3;
/**
* Headset and Handsfree profile
*/
- public static final int HEADSET = 1;
+ int HEADSET = 1;
/**
* A2DP profile.
*/
- public static final int A2DP = 2;
+ int A2DP = 2;
/**
* Health Profile
*/
- public static final int HEALTH = 3;
+ int HEALTH = 3;
/**
* HID Host
*
* @hide
*/
- public static final int HID_HOST = 4;
+ int HID_HOST = 4;
/**
* PAN Profile
*
* @hide
*/
- public static final int PAN = 5;
+ int PAN = 5;
/**
* PBAP
*
* @hide
*/
- public static final int PBAP = 6;
+ int PBAP = 6;
/**
* GATT
*/
- public static final int GATT = 7;
+ int GATT = 7;
/**
* GATT_SERVER
*/
- public static final int GATT_SERVER = 8;
+ int GATT_SERVER = 8;
/**
* MAP Profile
*
* @hide
*/
- public static final int MAP = 9;
+ int MAP = 9;
/*
* SAP Profile
* @hide
*/
- public static final int SAP = 10;
+ int SAP = 10;
/**
* A2DP Sink Profile
*
* @hide
*/
- public static final int A2DP_SINK = 11;
+ int A2DP_SINK = 11;
/**
* AVRCP Controller Profile
*
* @hide
*/
- public static final int AVRCP_CONTROLLER = 12;
+ int AVRCP_CONTROLLER = 12;
+
+ /**
+ * AVRCP Target Profile
+ *
+ * @hide
+ */
+ int AVRCP = 13;
/**
* Headset Client - HFP HF Role
*
* @hide
*/
- public static final int HEADSET_CLIENT = 16;
+ int HEADSET_CLIENT = 16;
/**
* PBAP Client
*
* @hide
*/
- public static final int PBAP_CLIENT = 17;
+ int PBAP_CLIENT = 17;
/**
* MAP Messaging Client Equipment (MCE)
*
* @hide
*/
- public static final int MAP_CLIENT = 18;
+ int MAP_CLIENT = 18;
/**
* HID Device
*/
- public static final int HID_DEVICE = 19;
+ int HID_DEVICE = 19;
/**
* Object Push Profile (OPP)
*
* @hide
*/
- public static final int OPP = 20;
+ int OPP = 20;
/**
* Hearing Aid Device
@@ -185,7 +192,7 @@
*
* @hide
**/
- public static final int PRIORITY_AUTO_CONNECT = 1000;
+ int PRIORITY_AUTO_CONNECT = 1000;
/**
* Default priority for devices that allow incoming
@@ -194,7 +201,7 @@
* @hide
**/
@SystemApi
- public static final int PRIORITY_ON = 100;
+ int PRIORITY_ON = 100;
/**
* Default priority for devices that does not allow incoming
@@ -203,14 +210,14 @@
* @hide
**/
@SystemApi
- public static final int PRIORITY_OFF = 0;
+ int PRIORITY_OFF = 0;
/**
* Default priority when not set or when the device is unpaired
*
* @hide
*/
- public static final int PRIORITY_UNDEFINED = -1;
+ int PRIORITY_UNDEFINED = -1;
/**
* Get connected devices for this specific profile.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 8ea81a4..ebc88ff 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1046,6 +1046,58 @@
/** @hide */
public String[] splitClassLoaderNames;
+ /**
+ * Represents the default policy. The actual policy used will depend on other properties of
+ * the application, e.g. the target SDK version.
+ * @hide
+ */
+ public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1;
+ /**
+ * No API enforcement; the app can access the entire internal private API. Only for use by
+ * system apps.
+ * @hide
+ */
+ public static final int HIDDEN_API_ENFORCEMENT_NONE = 0;
+ /**
+ * Light grey list enforcement, the strictest option. Enforces the light grey, dark grey and
+ * black lists.
+ * @hide
+ * */
+ public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1;
+ /**
+ * Dark grey list enforcement. Enforces the dark grey and black lists
+ * @hide
+ */
+ public static final int HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK = 2;
+ /**
+ * Blacklist enforcement only.
+ * @hide
+ */
+ public static final int HIDDEN_API_ENFORCEMENT_BLACK = 3;
+
+ private static final int HIDDEN_API_ENFORCEMENT_MAX = HIDDEN_API_ENFORCEMENT_BLACK;
+
+ /**
+ * Values in this IntDef MUST be kept in sync with enum hiddenapi::EnforcementPolicy in
+ * art/runtime/hidden_api.h
+ * @hide
+ */
+ @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = {
+ HIDDEN_API_ENFORCEMENT_DEFAULT,
+ HIDDEN_API_ENFORCEMENT_NONE,
+ HIDDEN_API_ENFORCEMENT_ALL_LISTS,
+ HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK,
+ HIDDEN_API_ENFORCEMENT_BLACK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HiddenApiEnforcementPolicy {}
+
+ private boolean isValidHiddenApiEnforcementPolicy(int policy) {
+ return policy >= HIDDEN_API_ENFORCEMENT_DEFAULT && policy <= HIDDEN_API_ENFORCEMENT_MAX;
+ }
+
+ private int mHiddenApiPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT;
+
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
@@ -1133,6 +1185,7 @@
if (category != CATEGORY_UNDEFINED) {
pw.println(prefix + "category=" + category);
}
+ pw.println(prefix + "HiddenApiEnforcementPolicy=" + getHiddenApiEnforcementPolicy());
}
super.dumpBack(pw, prefix);
}
@@ -1228,6 +1281,7 @@
targetSandboxVersion = orig.targetSandboxVersion;
classLoaderName = orig.classLoaderName;
splitClassLoaderNames = orig.splitClassLoaderNames;
+ mHiddenApiPolicy = orig.mHiddenApiPolicy;
}
public String toString() {
@@ -1298,6 +1352,7 @@
dest.writeInt(targetSandboxVersion);
dest.writeString(classLoaderName);
dest.writeStringArray(splitClassLoaderNames);
+ dest.writeInt(mHiddenApiPolicy);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1365,6 +1420,7 @@
targetSandboxVersion = source.readInt();
classLoaderName = source.readString();
splitClassLoaderNames = source.readStringArray();
+ mHiddenApiPolicy = source.readInt();
}
/**
@@ -1456,14 +1512,31 @@
}
}
+ private boolean isPackageWhitelistedForHiddenApis() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+ }
+
/**
* @hide
*/
- public boolean isAllowedToUseHiddenApi() {
- boolean whitelisted =
- SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
- return isSystemApp() || // TODO get rid of this once the whitelist has been populated
- (whitelisted && (isSystemApp() || isUpdatedSystemApp()));
+ public @HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() {
+ if (mHiddenApiPolicy != HIDDEN_API_ENFORCEMENT_DEFAULT) {
+ return mHiddenApiPolicy;
+ }
+ if (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())) {
+ return HIDDEN_API_ENFORCEMENT_NONE;
+ }
+ return HIDDEN_API_ENFORCEMENT_BLACK;
+ }
+
+ /**
+ * @hide
+ */
+ public void setHiddenApiEnforcementPolicy(@HiddenApiEnforcementPolicy int policy) {
+ if (!isValidHiddenApiEnforcementPolicy(policy)) {
+ throw new IllegalArgumentException("Invalid API enforcement policy: " + policy);
+ }
+ mHiddenApiPolicy = policy;
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index f136e27..9d518e9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1977,13 +1977,6 @@
* services.jar, possibly in com.android.server.net. */
/** {@hide} */
- public static final boolean checkChangePermission(Context context) {
- int uid = Binder.getCallingUid();
- return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
- .getPackageNameForUid(context, uid), false /* throwException */);
- }
-
- /** {@hide} */
public static final void enforceChangePermission(Context context) {
int uid = Binder.getCallingUid();
Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 3ce0283..3a3ddcc 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -16,6 +16,7 @@
package android.net;
+import android.net.LinkAddress;
import android.net.Network;
import android.net.IpSecConfig;
import android.net.IpSecUdpEncapResponse;
@@ -48,11 +49,11 @@
void addAddressToTunnelInterface(
int tunnelResourceId,
- String localAddr);
+ in LinkAddress localAddr);
void removeAddressFromTunnelInterface(
int tunnelResourceId,
- String localAddr);
+ in LinkAddress localAddr);
void deleteTunnelInterface(int resourceId);
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 90e3ffd..eab7041 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -44,6 +44,16 @@
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
+
+ /** Get a detailed snapshot of stats since boot for all UIDs.
+ *
+ * <p>Results will not always be limited to stats on requiredIfaces when specified: stats for
+ * interfaces stacked on the specified interfaces, or for interfaces on which the specified
+ * interfaces are stacked on, will also be included.
+ * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}.
+ */
+ NetworkStats getDetailedUidStats(in String[] requiredIfaces);
+
/** Return set of any ifaces associated with mobile networks since boot. */
String[] getMobileIfaces();
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index c69a4d4..57f0588 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -38,6 +38,13 @@
private static final String TAG = "IpSecAlgorithm";
/**
+ * Null cipher.
+ *
+ * @hide
+ */
+ public static final String CRYPT_NULL = "ecb(cipher_null)";
+
+ /**
* AES-CBC Encryption/Ciphering Algorithm.
*
* <p>Valid lengths for this key are {128, 192, 256}.
@@ -122,7 +129,7 @@
* @param algorithm name of the algorithm.
* @param key key padded to a multiple of 8 bits.
*/
- public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
+ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
this(algorithm, key, key.length * 8);
}
@@ -137,7 +144,8 @@
* @param key key padded to a multiple of 8 bits.
* @param truncLenBits number of bits of output hash to use.
*/
- public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+ public IpSecAlgorithm(
+ @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
mName = algorithm;
mKey = key.clone();
mTruncLenBits = truncLenBits;
@@ -145,11 +153,13 @@
}
/** Get the algorithm name */
+ @NonNull
public String getName() {
return mName;
}
/** Get the key for this algorithm */
+ @NonNull
public byte[] getKey() {
return mKey.clone();
}
@@ -263,6 +273,7 @@
}
@Override
+ @NonNull
public String toString() {
return new StringBuilder()
.append("{mName=")
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index b609847..4157845 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -58,14 +58,18 @@
private static final String TAG = "IpSecManager";
/**
- * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
- * applies to traffic towards the host.
+ * Used when applying a transform to direct traffic through an {@link IpSecTransform}
+ * towards the host.
+ *
+ * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
*/
public static final int DIRECTION_IN = 0;
/**
- * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
- * applies to traffic from the host.
+ * Used when applying a transform to direct traffic through an {@link IpSecTransform}
+ * away from the host.
+ *
+ * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
*/
public static final int DIRECTION_OUT = 1;
@@ -249,8 +253,9 @@
* @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
* currently allocated for this user
*/
- public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress)
- throws ResourceUnavailableException {
+ @NonNull
+ public SecurityParameterIndex allocateSecurityParameterIndex(
+ @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
try {
return new SecurityParameterIndex(
mService,
@@ -276,8 +281,9 @@
* @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
* reserved
*/
+ @NonNull
public SecurityParameterIndex allocateSecurityParameterIndex(
- InetAddress destinationAddress, int requestedSpi)
+ @NonNull InetAddress destinationAddress, int requestedSpi)
throws SpiUnavailableException, ResourceUnavailableException {
if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
@@ -301,20 +307,21 @@
*
* <h4>Rekey Procedure</h4>
*
- * <p>When applying a new tranform to a socket, the previous transform will be removed. However,
- * inbound traffic on the old transform will continue to be decrypted until that transform is
- * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures
- * where both transforms are valid until both endpoints are using the new transform and all
- * in-flight packets have been received.
+ * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
+ * will be removed and the new transform will take effect immediately, sending all traffic on
+ * the new transform; however, when applying a transform in the inbound direction, traffic
+ * on the old transform will continue to be decrypted and delivered until that transform is
+ * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
+ * procedures where both transforms are valid until both endpoints are using the new transform
+ * and all in-flight packets have been received.
*
* @param socket a stream socket
- * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
+ * @param direction the direction in which the transform should be applied
* @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
*/
- public void applyTransportModeTransform(
- Socket socket, int direction, IpSecTransform transform)
- throws IOException {
+ public void applyTransportModeTransform(@NonNull Socket socket,
+ @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
}
@@ -334,19 +341,21 @@
*
* <h4>Rekey Procedure</h4>
*
- * <p>When applying a new tranform to a socket, the previous transform will be removed. However,
- * inbound traffic on the old transform will continue to be decrypted until that transform is
- * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures
- * where both transforms are valid until both endpoints are using the new transform and all
- * in-flight packets have been received.
+ * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
+ * will be removed and the new transform will take effect immediately, sending all traffic on
+ * the new transform; however, when applying a transform in the inbound direction, traffic
+ * on the old transform will continue to be decrypted and delivered until that transform is
+ * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
+ * procedures where both transforms are valid until both endpoints are using the new transform
+ * and all in-flight packets have been received.
*
* @param socket a datagram socket
- * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT
+ * @param direction the direction in which the transform should be applied
* @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
*/
- public void applyTransportModeTransform(
- DatagramSocket socket, int direction, IpSecTransform transform) throws IOException {
+ public void applyTransportModeTransform(@NonNull DatagramSocket socket,
+ @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
}
@@ -366,20 +375,21 @@
*
* <h4>Rekey Procedure</h4>
*
- * <p>When applying a new tranform to a socket, the previous transform will be removed. However,
- * inbound traffic on the old transform will continue to be decrypted until that transform is
- * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures
- * where both transforms are valid until both endpoints are using the new transform and all
- * in-flight packets have been received.
+ * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
+ * will be removed and the new transform will take effect immediately, sending all traffic on
+ * the new transform; however, when applying a transform in the inbound direction, traffic
+ * on the old transform will continue to be decrypted and delivered until that transform is
+ * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
+ * procedures where both transforms are valid until both endpoints are using the new transform
+ * and all in-flight packets have been received.
*
* @param socket a socket file descriptor
- * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT
+ * @param direction the direction in which the transform should be applied
* @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
*/
- public void applyTransportModeTransform(
- FileDescriptor socket, int direction, IpSecTransform transform)
- throws IOException {
+ public void applyTransportModeTransform(@NonNull FileDescriptor socket,
+ @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
// We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
// constructor takes control and closes the user's FD when we exit the method.
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
@@ -390,21 +400,6 @@
}
/**
- * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
- * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
- * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
- * Applications should probably not use this API directly. Instead, they should use {@link
- * VpnService} to provide VPN capability in a more generic fashion.
- *
- * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
- *
- * @param net a {@link Network} that will be tunneled via IP Sec.
- * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
- * @hide
- */
- public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
-
- /**
* Remove an IPsec transform from a stream socket.
*
* <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
@@ -417,8 +412,7 @@
* @param socket a socket that previously had a transform applied to it
* @throws IOException indicating that the transform could not be removed from the socket
*/
- public void removeTransportModeTransforms(Socket socket)
- throws IOException {
+ public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
removeTransportModeTransforms(socket.getFileDescriptor$());
}
@@ -435,8 +429,7 @@
* @param socket a socket that previously had a transform applied to it
* @throws IOException indicating that the transform could not be removed from the socket
*/
- public void removeTransportModeTransforms(DatagramSocket socket)
- throws IOException {
+ public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
removeTransportModeTransforms(socket.getFileDescriptor$());
}
@@ -453,8 +446,7 @@
* @param socket a socket that previously had a transform applied to it
* @throws IOException indicating that the transform could not be removed from the socket
*/
- public void removeTransportModeTransforms(FileDescriptor socket)
- throws IOException {
+ public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
mService.removeTransportModeTransforms(pfd);
} catch (RemoteException e) {
@@ -592,6 +584,7 @@
// safely usable for Encapsulation without allowing a user to possibly unbind from/close
// the port, which could potentially impact the traffic of the next user who binds to that
// socket.
+ @NonNull
public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
throws IOException, ResourceUnavailableException {
/*
@@ -621,6 +614,7 @@
// safely usable for Encapsulation without allowing a user to possibly unbind from/close
// the port, which could potentially impact the traffic of the next user who binds to that
// socket.
+ @NonNull
public UdpEncapsulationSocket openUdpEncapsulationSocket()
throws IOException, ResourceUnavailableException {
return new UdpEncapsulationSocket(mService, 0);
@@ -649,6 +643,7 @@
private int mResourceId = INVALID_RESOURCE_ID;
/** Get the underlying SPI held by this object. */
+ @NonNull
public String getInterfaceName() {
return mInterfaceName;
}
@@ -660,10 +655,15 @@
* tunneled traffic.
*
* @param address the local address for traffic inside the tunnel
- * @throws IOException if the address could not be added
* @hide
*/
- public void addAddress(LinkAddress address) throws IOException {
+ @SystemApi
+ public void addAddress(@NonNull LinkAddress address) throws IOException {
+ try {
+ mService.addAddressToTunnelInterface(mResourceId, address);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -672,10 +672,15 @@
* <p>Remove an address which was previously added to the IpSecTunnelInterface
*
* @param address to be removed
- * @throws IOException if the address could not be removed
* @hide
*/
- public void removeAddress(LinkAddress address) throws IOException {
+ @SystemApi
+ public void removeAddress(@NonNull LinkAddress address) throws IOException {
+ try {
+ mService.removeAddressFromTunnelInterface(mResourceId, address);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
private IpSecTunnelInterface(@NonNull IIpSecService service,
@@ -762,6 +767,7 @@
* @hide
*/
@SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
@NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
@@ -770,7 +776,12 @@
}
/**
- * Apply a transform to the IpSecTunnelInterface
+ * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
+ * tunnel all traffic for the given direction through the underlying network's interface with
+ * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
+ * IP header and IPsec Header on all inbound traffic).
+ * <p>Applications should probably not use this API directly.
+ *
*
* @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
* transform.
@@ -783,8 +794,8 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
- IpSecTransform transform) throws IOException {
+ public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
+ @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
try {
mService.applyTunnelModeTransform(
tunnel.getResourceId(), direction, transform.getResourceId());
@@ -792,6 +803,7 @@
throw e.rethrowFromSystemServer();
}
}
+
/**
* Construct an instance of IpSecManager within an application context.
*
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 60e96f9..cf58647 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -350,6 +350,7 @@
*
* @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
*/
+ @NonNull
public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
Preconditions.checkNotNull(algo);
@@ -364,6 +365,7 @@
*
* @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
*/
+ @NonNull
public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
Preconditions.checkNotNull(algo);
@@ -384,6 +386,7 @@
* @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
* be applied.
*/
+ @NonNull
public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
Preconditions.checkNotNull(algo);
mConfig.setAuthenticatedEncryption(algo);
@@ -403,6 +406,7 @@
* @param remotePort the UDP port number of the remote host that will send and receive
* encapsulated traffic. In the case of IKEv2, this should be port 4500.
*/
+ @NonNull
public IpSecTransform.Builder setIpv4Encapsulation(
@NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
Preconditions.checkNotNull(localSocket);
@@ -436,6 +440,7 @@
* collides with an existing transform
* @throws IOException indicating other errors
*/
+ @NonNull
public IpSecTransform buildTransportModeTransform(
@NonNull InetAddress sourceAddress,
@NonNull IpSecManager.SecurityParameterIndex spi)
@@ -472,6 +477,7 @@
* @hide
*/
@SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public IpSecTransform buildTunnelModeTransform(
@NonNull InetAddress sourceAddress,
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 96826f8..1ee0ed7d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import java.util.Objects;
+import java.util.Set;
/**
* Defines a request for a network, made through {@link NetworkRequest.Builder} and used
@@ -204,6 +205,19 @@
}
/**
+ * Set the watched UIDs for this request. This will be reset and wiped out unless
+ * the calling app holds the CHANGE_NETWORK_STATE permission.
+ *
+ * @param uids The watched UIDs as a set of UidRanges, or null for everything.
+ * @return The builder to facilitate chaining.
+ * @hide
+ */
+ public Builder setUids(Set<UidRange> uids) {
+ mNetworkCapabilities.setUids(uids);
+ return this;
+ }
+
+ /**
* Add a capability that must not exist in the requested network.
* <p>
* If the capability was previously added to the list of required capabilities (for
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 01b2b39..940f985 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -64,6 +64,9 @@
/** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
public static final int SET_DBG_VPN_OUT = 1002;
+ /** Include all interfaces when filtering */
+ public static final String[] INTERFACES_ALL = null;
+
/** {@link #tag} value for total data across all tags. */
// TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
@@ -359,23 +362,27 @@
capacity = newLength;
}
- iface[size] = entry.iface;
- uid[size] = entry.uid;
- set[size] = entry.set;
- tag[size] = entry.tag;
- metered[size] = entry.metered;
- roaming[size] = entry.roaming;
- defaultNetwork[size] = entry.defaultNetwork;
- rxBytes[size] = entry.rxBytes;
- rxPackets[size] = entry.rxPackets;
- txBytes[size] = entry.txBytes;
- txPackets[size] = entry.txPackets;
- operations[size] = entry.operations;
+ setValues(size, entry);
size++;
return this;
}
+ private void setValues(int i, Entry entry) {
+ iface[i] = entry.iface;
+ uid[i] = entry.uid;
+ set[i] = entry.set;
+ tag[i] = entry.tag;
+ metered[i] = entry.metered;
+ roaming[i] = entry.roaming;
+ defaultNetwork[i] = entry.defaultNetwork;
+ rxBytes[i] = entry.rxBytes;
+ rxPackets[i] = entry.rxPackets;
+ txBytes[i] = entry.txBytes;
+ txPackets[i] = entry.txPackets;
+ operations[i] = entry.operations;
+ }
+
/**
* Return specific stats entry.
*/
@@ -824,6 +831,39 @@
return stats;
}
+ /**
+ * Only keep entries that match all specified filters.
+ *
+ * <p>This mutates the original structure in place. After this method is called,
+ * size is the number of matching entries, and capacity is the previous capacity.
+ * @param limitUid UID to filter for, or {@link #UID_ALL}.
+ * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
+ * @param limitTag Tag to filter for, or {@link #TAG_ALL}.
+ */
+ public void filter(int limitUid, String[] limitIfaces, int limitTag) {
+ if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
+ return;
+ }
+
+ Entry entry = new Entry();
+ int nextOutputEntry = 0;
+ for (int i = 0; i < size; i++) {
+ entry = getValues(i, entry);
+ final boolean matches =
+ (limitUid == UID_ALL || limitUid == entry.uid)
+ && (limitTag == TAG_ALL || limitTag == entry.tag)
+ && (limitIfaces == INTERFACES_ALL
+ || ArrayUtils.contains(limitIfaces, entry.iface));
+
+ if (matches) {
+ setValues(nextOutputEntry, entry);
+ nextOutputEntry++;
+ }
+ }
+
+ size = nextOutputEntry;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index b02d48d..c3f23a1 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -225,7 +225,7 @@
* Indicates the Secure Element on which the transaction occurred.
* eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc.
*/
- public static final String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME";
+ public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
public static final int STATE_OFF = 1;
public static final int STATE_TURNING_ON = 2;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 336e1b4..5652d6d 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -22,6 +22,7 @@
import android.util.Log;
import android.util.Slog;
+import com.android.internal.os.BinderInternal;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
@@ -361,7 +362,9 @@
* Add the calling thread to the IPC thread pool. This function does
* not return until the current process is exiting.
*/
- public static final native void joinThreadPool();
+ public static final void joinThreadPool() {
+ BinderInternal.joinThreadPool();
+ }
/**
* Returns true if the specified interface is a proxy.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index a5e1934..31dbafa 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -268,10 +268,12 @@
NetworkStats getNetworkStatsDetail();
/**
- * Return detailed network statistics for the requested UID,
+ * Return detailed network statistics for the requested UID and interfaces,
* including interface and tag details.
+ * @param uid UID to obtain statistics for, or {@link NetworkStats#UID_ALL}.
+ * @param ifaces Interfaces to obtain statistics for, or {@link NetworkStats#INTERFACES_ALL}.
*/
- NetworkStats getNetworkStatsUidDetail(int uid);
+ NetworkStats getNetworkStatsUidDetail(int uid, in String[] ifaces);
/**
* Return summary of network statistics all tethering interfaces.
@@ -340,7 +342,7 @@
* Configure name servers, search paths, and resolver parameters for the given network.
*/
void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains,
- in int[] params, boolean useTls, String tlsHostname);
+ in int[] params, String tlsHostname, in String[] tlsServers);
void setFirewallEnabled(boolean enabled);
boolean isFirewallEnabled();
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 4f6d322..89168ae 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -189,7 +189,12 @@
}
ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
for (int i=0; i<callbacks.size(); i++) {
- callbacks.get(i).run();
+ try {
+ callbacks.get(i).run();
+ } catch (Throwable t) {
+ Log.wtf(TAG, "Exception in SystemProperties change callback", t);
+ // Ignore and try to go on.
+ }
}
}
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index fa96dd3..0f4fc36 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -89,6 +89,8 @@
public static final long TRACE_TAG_NETWORK = 1L << 21;
/** @hide */
public static final long TRACE_TAG_ADB = 1L << 22;
+ /** @hide */
+ public static final long TRACE_TAG_AIDL = 1L << 24;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 57418c8..939c190 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -32,6 +32,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -158,6 +159,13 @@
private final Object mLock = new Object();
/**
+ * List of exemptions to the API blacklist. These are prefix matches on the runtime format
+ * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
+ * list.
+ */
+ private List<String> mApiBlacklistExemptions = Collections.emptyList();
+
+ /**
* The state of the connection to the primary zygote.
*/
private ZygoteState primaryZygoteState;
@@ -175,7 +183,7 @@
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
- * process is created and main() of <var>processClass</var> called there.
+ * process is created and main() of <var>processclass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
@@ -454,6 +462,49 @@
}
/**
+ * Push hidden API blacklisting exemptions into the zygote process(es).
+ *
+ * <p>The list of exemptions will take affect for all new processes forked from the zygote after
+ * this call.
+ *
+ * @param exemptions List of hidden API exemption prefixes.
+ */
+ public void setApiBlacklistExemptions(List<String> exemptions) {
+ synchronized (mLock) {
+ mApiBlacklistExemptions = exemptions;
+ maybeSetApiBlacklistExemptions(primaryZygoteState, true);
+ maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
+ if (state == null || state.isClosed()) {
+ return;
+ }
+ if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
+ return;
+ }
+ try {
+ state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
+ state.writer.newLine();
+ state.writer.write("--set-api-blacklist-exemptions");
+ state.writer.newLine();
+ for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
+ state.writer.write(mApiBlacklistExemptions.get(i));
+ state.writer.newLine();
+ }
+ state.writer.flush();
+ int status = state.inputStream.readInt();
+ if (status != 0) {
+ Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
+ }
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
+ }
+ }
+
+ /**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry. Requires that mLock be held.
*/
@@ -467,8 +518,8 @@
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
+ maybeSetApiBlacklistExemptions(primaryZygoteState, false);
}
-
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
@@ -480,6 +531,7 @@
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
+ maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
}
if (secondaryZygoteState.matches(abi)) {
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 8aef012..67c6fb9 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
+import android.telecom.Log;
/**
* <p>
@@ -261,9 +262,16 @@
*/
@WorkerThread
public static boolean isBlocked(Context context, String phoneNumber) {
- final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null);
- return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ try {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "isBlocked: provider not ready.");
+ return false;
+ }
}
/**
@@ -297,9 +305,16 @@
* @return {@code true} if the current user can block numbers.
*/
public static boolean canCurrentUserBlockNumbers(Context context) {
- final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS, null, null);
- return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false);
+ try {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS, null, null);
+ return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "canCurrentUserBlockNumbers: provider not ready.");
+ return false;
+ }
}
/**
@@ -368,8 +383,14 @@
* the provider unless {@link #endBlockSuppression(Context)} is called.
*/
public static void notifyEmergencyContact(Context context) {
- context.getContentResolver().call(
- AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null);
+ try {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "notifyEmergencyContact: provider not ready.");
+ }
}
/**
@@ -394,9 +415,16 @@
*/
public static boolean shouldSystemBlockNumber(Context context, String phoneNumber,
Bundle extras) {
- final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras);
- return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ try {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "shouldSystemBlockNumber: provider not ready.");
+ return false;
+ }
}
/**
@@ -416,9 +444,16 @@
* @return {@code true} if should show emergency call notification. {@code false} otherwise.
*/
public static boolean shouldShowEmergencyCallNotification(Context context) {
- final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null);
- return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false);
+ try {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null);
+ return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "shouldShowEmergencyCallNotification: provider not ready.");
+ return false;
+ }
}
/**
@@ -436,9 +471,16 @@
public static boolean getEnhancedBlockSetting(Context context, String key) {
Bundle extras = new Bundle();
extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
- final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras);
- return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false);
+ try {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras);
+ return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false);
+ } catch (NullPointerException | IllegalArgumentException ex) {
+ // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+ // either of these happen.
+ Log.w(null, "getEnhancedBlockSetting: provider not ready.");
+ return false;
+ }
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ca3f5e9..2b5353d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3621,6 +3621,14 @@
public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
/**
+ * When {@code 1}, Telecom enhanced call blocking functionality is enabled. When
+ * {@code 0}, enhanced call blocking functionality is disabled.
+ * @hide
+ */
+ public static final String DEBUG_ENABLE_ENHANCED_CALL_BLOCKING =
+ "debug.enable_enhanced_calling";
+
+ /**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
@@ -8706,6 +8714,12 @@
public static final String BLE_SCAN_LOW_LATENCY_INTERVAL_MS =
"ble_scan_low_latency_interval_ms";
+ /**
+ * The mode that BLE scanning clients will be moved to when in the background.
+ * @hide
+ */
+ public static final String BLE_SCAN_BACKGROUND_MODE = "ble_scan_background_mode";
+
/**
* Used to save the Wifi_ON state prior to tethering.
* This state will be checked to restore Wifi after
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index 65ce67f..c8efede 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -47,7 +47,8 @@
private final SEService mService;
private final Object mLock = new Object();
- Channel(SEService service, Session session, ISecureElementChannel channel) {
+ Channel(@NonNull SEService service, @NonNull Session session,
+ @NonNull ISecureElementChannel channel) {
if (service == null || session == null || channel == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
@@ -158,7 +159,7 @@
* @throws SecurityException if the command is filtered by the security policy.
* @throws NullPointerException if command is NULL.
*/
- public @NonNull byte[] transmit(byte[] command) throws IOException {
+ public @NonNull byte[] transmit(@NonNull byte[] command) throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
diff --git a/core/java/android/se/omapi/ISecureElementListener.aidl b/core/java/android/se/omapi/ISecureElementListener.aidl
index e0c6e04..e9dd181 100644
--- a/core/java/android/se/omapi/ISecureElementListener.aidl
+++ b/core/java/android/se/omapi/ISecureElementListener.aidl
@@ -24,8 +24,4 @@
* @hide
*/
interface ISecureElementListener {
- /**
- * Called by the framework when the service is connected.
- */
- void serviceConnected();
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 3dec976..9be3da6 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -46,7 +46,7 @@
private final Object mLock = new Object();
- Reader(SEService service, String name, ISecureElementReader reader) {
+ Reader(@NonNull SEService service, @NonNull String name, @NonNull ISecureElementReader reader) {
if (reader == null || service == null || name == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index d59e86a..311dc4c 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -62,17 +62,32 @@
/**
* Interface to send call-backs to the application when the service is connected.
*/
- public abstract static class SecureElementListener extends ISecureElementListener.Stub {
+ public interface SecureElementListener {
+ /**
+ * Called by the framework when the service is connected.
+ */
+ void onServiceConnected();
+ }
+
+ /**
+ * Listener object that allows the notification of the caller if this
+ * SEService could be bound to the backend.
+ */
+ private class SEListener extends ISecureElementListener.Stub {
+ public SecureElementListener mListener = null;
+
@Override
public IBinder asBinder() {
return this;
}
- /**
- * Called by the framework when the service is connected.
- */
- public void serviceConnected() {};
+ public void onServiceConnected() {
+ if (mListener != null) {
+ mListener.onServiceConnected();
+ }
+ }
}
+ private SEListener mSEListener = new SEListener();
private static final String TAG = "OMAPI.SEService";
@@ -95,34 +110,28 @@
private final HashMap<String, Reader> mReaders = new HashMap<String, Reader>();
/**
- * Listener object that allows the notification of the caller if this
- * SEService could be bound to the backend.
- */
- private ISecureElementListener mSEListener;
-
- /**
* Establishes a new connection that can be used to connect to all the
* Secure Elements available in the system. The connection process can be
* quite long, so it happens in an asynchronous way. It is usable only if
* the specified listener is called or if isConnected() returns
* <code>true</code>. <br>
* The call-back object passed as a parameter will have its
- * serviceConnected() method called when the connection actually happen.
+ * onServiceConnected() method called when the connection actually happen.
*
* @param context
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a SecureElementListener object. Can be <code>null</code>.
+ * a SecureElementListener object.
*/
- public SEService(Context context, SecureElementListener listener) {
+ public SEService(@NonNull Context context, @NonNull SecureElementListener listener) {
if (context == null) {
throw new NullPointerException("context must not be null");
}
mContext = context;
- mSEListener = listener;
+ mSEListener.mListener = listener;
mConnection = new ServiceConnection() {
@@ -131,9 +140,7 @@
mSecureElementService = ISecureElementService.Stub.asInterface(service);
if (mSEListener != null) {
- try {
- mSEListener.serviceConnected();
- } catch (RemoteException ignore) { }
+ mSEListener.onServiceConnected();
}
Log.i(TAG, "Service onServiceConnected");
}
@@ -233,7 +240,7 @@
*
* @return String containing the OpenMobile API version (e.g. "3.0").
*/
- public String getVersion() {
+ public @NonNull String getVersion() {
return "3.2";
}
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index 3d8b74b..adfeddd 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -47,7 +47,8 @@
private final ISecureElementSession mSession;
private static final String TAG = "OMAPI.Session";
- Session(SEService service, ISecureElementSession session, Reader reader) {
+ Session(@NonNull SEService service, @NonNull ISecureElementSession session,
+ @NonNull Reader reader) {
if (service == null || reader == null || session == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
@@ -195,7 +196,8 @@
* supported by the device
* @return an instance of Channel if available or null.
*/
- public @Nullable Channel openBasicChannel(byte[] aid, byte p2) throws IOException {
+ public @Nullable Channel openBasicChannel(@Nullable byte[] aid, @Nullable byte p2)
+ throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
@@ -223,32 +225,6 @@
}
/**
- * This method is provided to ease the development of mobile application and for compliancy
- * with existing applications.
- * This method is equivalent to openBasicChannel(aid, P2=0x00)
- *
- * @param aid the AID of the Applet to be selected on this channel, as a
- * byte array, or null if no Applet is to be selected.
- * @throws IOException if there is a communication problem to the reader or
- * the Secure Element.
- * @throws IllegalStateException if the Secure Element session is used after
- * being closed.
- * @throws IllegalArgumentException if the aid's length is not within 5 to
- * 16 (inclusive).
- * @throws SecurityException if the calling application cannot be granted
- * access to this AID or the default Applet on this
- * session.
- * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
- * selected.
- * @throws UnsupportedOperationException if the given P2 parameter is not
- * supported by the device
- * @return an instance of Channel if available or null.
- */
- public @Nullable Channel openBasicChannel(byte[] aid) throws IOException {
- return openBasicChannel(aid, (byte) 0x00);
- }
-
- /**
* Open a logical channel with the Secure Element, selecting the Applet represented by
* the given AID. If the AID is null, which means no Applet is to be selected on this
* channel, the default Applet is used. It's up to the Secure Element to choose which
@@ -300,7 +276,8 @@
* @return an instance of Channel. Null if the Secure Element is unable to
* provide a new logical channel.
*/
- public @Nullable Channel openLogicalChannel(byte[] aid, byte p2) throws IOException {
+ public @Nullable Channel openLogicalChannel(@Nullable byte[] aid, @Nullable byte p2)
+ throws IOException {
if (!mService.isConnected()) {
throw new IllegalStateException("service not connected to system");
}
@@ -327,32 +304,4 @@
}
}
}
-
- /**
- * This method is provided to ease the development of mobile application and for compliancy
- * with existing applications.
- * This method is equivalent to openLogicalChannel(aid, P2=0x00)
- *
- * @param aid the AID of the Applet to be selected on this channel, as a
- * byte array.
- * @throws IOException if there is a communication problem to the reader or
- * the Secure Element.
- * @throws IllegalStateException if the Secure Element is used after being
- * closed.
- * @throws IllegalArgumentException if the aid's length is not within 5 to
- * 16 (inclusive).
- * @throws SecurityException if the calling application cannot be granted
- * access to this AID or the default Applet on this
- * session.
- * @throws NoSuchElementException if the AID on the Secure Element is not
- * available or cannot be selected or a logical channel is already
- * open to a non-multiselectable Applet.
- * @throws UnsupportedOperationException if the given P2 parameter is not
- * supported by the device.
- * @return an instance of Channel. Null if the Secure Element is unable to
- * provide a new logical channel.
- */
- public @Nullable Channel openLogicalChannel(byte[] aid) throws IOException {
- return openLogicalChannel(aid, (byte) 0x00);
- }
}
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 902bd12..8172a20 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -22,16 +22,14 @@
import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+import android.annotation.Nullable;
import android.net.NetworkStats;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.util.ArrayMap;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
-import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -41,8 +39,10 @@
import java.io.FileReader;
import java.io.IOException;
import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.Objects;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Creates {@link NetworkStats} instances by parsing various {@code /proc/}
@@ -70,18 +70,55 @@
private boolean mUseBpfStats;
- // TODO: to improve testability and avoid global state, do not use a static variable.
- @GuardedBy("sStackedIfaces")
- private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>();
+ // TODO: only do adjustments in NetworkStatsService and remove this.
+ /**
+ * (Stacked interface) -> (base interface) association for all connected ifaces since boot.
+ *
+ * Because counters must never roll backwards, once a given interface is stacked on top of an
+ * underlying interface, the stacked interface can never be stacked on top of
+ * another interface. */
+ private static final ConcurrentHashMap<String, String> sStackedIfaces
+ = new ConcurrentHashMap<>();
public static void noteStackedIface(String stackedIface, String baseIface) {
- synchronized (sStackedIfaces) {
- if (baseIface != null) {
- sStackedIfaces.put(stackedIface, baseIface);
- } else {
- sStackedIfaces.remove(stackedIface);
+ if (stackedIface != null && baseIface != null) {
+ sStackedIfaces.put(stackedIface, baseIface);
+ }
+ }
+
+ /**
+ * Get a set of interfaces containing specified ifaces and stacked interfaces.
+ *
+ * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces
+ * on which the specified ones are stacked. Stacked interfaces are those noted with
+ * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
+ * is called are guaranteed to be included.
+ */
+ public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) {
+ if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
+ return null;
+ }
+
+ HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces));
+ // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse
+ // elements as they existed upon construction exactly once, and may
+ // (but are not guaranteed to) reflect any modifications subsequent to construction".
+ // This is enough here.
+ for (Map.Entry<String, String> entry : sStackedIfaces.entrySet()) {
+ if (relatedIfaces.contains(entry.getKey())) {
+ relatedIfaces.add(entry.getValue());
+ } else if (relatedIfaces.contains(entry.getValue())) {
+ relatedIfaces.add(entry.getKey());
}
}
+
+ String[] outArray = new String[relatedIfaces.size()];
+ return relatedIfaces.toArray(outArray);
+ }
+
+ @VisibleForTesting
+ public static void clearStackedIfaces() {
+ sStackedIfaces.clear();
}
public NetworkStatsFactory() {
@@ -250,12 +287,9 @@
NetworkStats lastStats) throws IOException {
final NetworkStats stats =
readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
- final ArrayMap<String, String> stackedIfaces;
- synchronized (sStackedIfaces) {
- stackedIfaces = new ArrayMap<>(sStackedIfaces);
- }
// Total 464xlat traffic to subtract from uid 0 on all base interfaces.
- final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
+ // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
+ final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size());
NetworkStats.Entry entry = null; // For recycling
@@ -269,7 +303,7 @@
if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
continue;
}
- final String baseIface = stackedIfaces.get(entry.iface);
+ final String baseIface = sStackedIfaces.get(entry.iface);
if (baseIface == null) {
continue;
}
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 4901080..f0e7796 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -115,6 +115,14 @@
command.append(' ');
command.append(appProcess);
+ // Generate bare minimum of debug information to be able to backtrace through JITed code.
+ // We assume that if the invoke wrapper is used, backtraces are desirable:
+ // * The wrap.sh script can only be used by debuggable apps, which would enable this flag
+ // without the script anyway (the fork-zygote path). So this makes the two consistent.
+ // * The wrap.* property can only be used on userdebug builds and is likely to be used by
+ // developers (e.g. enable debug-malloc), in which case backtraces are also useful.
+ command.append(" -Xcompiler-option --generate-mini-debug-info");
+
command.append(" /system/bin --application");
if (niceName != null) {
command.append(" '--nice-name=").append(niceName).append("'");
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e23cbf8..0d10888 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -55,10 +55,21 @@
public static final int DISABLE_VERIFIER = 1 << 9;
/** Only use oat files located in /system. Otherwise use dex/jar/apk . */
public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
- /** Do enfore hidden API access restrictions. */
- public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11;
/** Force generation of native debugging information for backtraces. */
- public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12;
+ public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11;
+ /**
+ * Hidden API access restrictions. This is a mask for bits representing the API enforcement
+ * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}.
+ */
+ public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13);
+ /**
+ * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}.
+ *
+ * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives
+ * @ApplicationInfo.ApiEnforcementPolicy values.
+ */
+ public static final int API_ENFORCEMENT_POLICY_SHIFT =
+ Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = 0;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a32fb43..adc5508 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -47,6 +47,8 @@
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
+
import libcore.io.IoUtils;
/**
@@ -159,6 +161,11 @@
return null;
}
+ if (parsedArgs.apiBlacklistExemptions != null) {
+ handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
+ return null;
+ }
+
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
@@ -278,6 +285,15 @@
}
}
+ private void handleApiBlacklistExemptions(String[] exemptions) {
+ try {
+ ZygoteInit.setApiBlacklistExemptions(exemptions);
+ mSocketOutStream.writeInt(0);
+ } catch (IOException ioe) {
+ throw new IllegalStateException("Error writing to command socket", ioe);
+ }
+ }
+
protected void preload() {
ZygoteInit.lazyPreload();
}
@@ -424,6 +440,12 @@
boolean startChildZygote;
/**
+ * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
+ * or when they change, via --set-api-blacklist-exemptions.
+ */
+ String[] apiBlacklistExemptions;
+
+ /**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
@@ -576,6 +598,11 @@
preloadDefault = true;
} else if (arg.equals("--start-child-zygote")) {
startChildZygote = true;
+ } else if (arg.equals("--set-api-blacklist-exemptions")) {
+ // consume all remaining args; this is a stand-alone command, never included
+ // with the regular fork command.
+ apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
+ curArg = args.length;
} else {
break;
}
@@ -590,7 +617,7 @@
throw new IllegalArgumentException(
"Unexpected arguments after --preload-package.");
}
- } else if (!preloadDefault) {
+ } else if (!preloadDefault && apiBlacklistExemptions == null) {
if (!seenRuntimeArgs) {
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index a05454f..c8e7102 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -514,6 +514,10 @@
/* should never reach here */
}
+ public static void setApiBlacklistExemptions(String[] exemptions) {
+ VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
+ }
+
/**
* Creates a PathClassLoader for the given class path that is associated with a shared
* namespace, i.e., this classloader can access platform-private native libraries. The
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3784d4d..6c46cfc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -20,6 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
+#include <android-base/macros.h>
#include <android-base/properties.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
@@ -860,34 +861,18 @@
// The runtime will compile a boot image, when necessary, not using installd. Thus, we need to
// pass the instruction-set-features/variant as an image-compiler-option.
- // TODO: Find a better way for the instruction-set.
-#if defined(__arm__)
- constexpr const char* instruction_set = "arm";
-#elif defined(__aarch64__)
- constexpr const char* instruction_set = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
- constexpr const char* instruction_set = "mips";
-#elif defined(__mips__) && defined(__LP64__)
- constexpr const char* instruction_set = "mips64";
-#elif defined(__i386__)
- constexpr const char* instruction_set = "x86";
-#elif defined(__x86_64__)
- constexpr const char* instruction_set = "x86_64";
-#else
- constexpr const char* instruction_set = "unknown";
-#endif
// Note: it is OK to reuse the buffer, as the values are exactly the same between
// * compiler-option, used for runtime compilation (DexClassLoader)
// * image-compiler-option, used for boot-image compilation on device
// Copy the variant.
- sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
+ sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING);
parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
"--instruction-set-variant=", "-Ximage-compiler-option");
parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
"--instruction-set-variant=", "-Xcompiler-option");
// Copy the features.
- sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
+ sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING);
parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
"--instruction-set-features=", "-Ximage-compiler-option");
parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index a94cac0..9ec7517 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -124,6 +124,12 @@
if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
//ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks);
+ // There should not be any exceptions. But we must guarantee
+ // there are none on return.
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ LOG(ERROR) << "Exception pending after sysprop_change!";
+ }
}
}
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 503d264..9e38efe 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -149,14 +149,17 @@
<!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. -->
<string name="RestrictedStateContent">Temporarily turned off by your carrier</string>
+ <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control when multiple SIMs are active. -->
+ <string name="RestrictedStateContentMsimTemplate">Temporarily turned off by your carrier for SIM <xliff:g id="simNumber" example="1">%d</xliff:g></string>
+
<!-- Displayed to tell the user that they should switch their network preference. -->
- <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
+ <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string>
<!-- Displayed to tell the user that they should switch their network preference. -->
- <string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at Settings > Network & Internet > Mobile networks > Preferred network type."</string>
+ <string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
- <string name="EmergencyCallWarningTitle">Wi\u2011Fi calling is active</string>
+ <string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
- <string name="EmergencyCallWarningSummary">Emergency calls require a mobile network.</string>
+ <string name="EmergencyCallWarningSummary">Can\u2019t make emergency calls over Wi\u2011Fi</string>
<!-- Telephony notification channel name for a channel containing network alert notifications. -->
<string name="notification_channel_network_alert">Alerts</string>
@@ -215,14 +218,14 @@
<string name="roamingTextSearching">Searching for Service</string>
<!-- Displayed when WFC registration fails -->
- <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
+ <string name="wfcRegErrorTitle">Couldn\u2019t set up Wi\u2011Fi calling</string>
<!-- WFC Operator Error Messages showed as alerts -->
<string-array name="wfcOperatorErrorAlertMessages">
<item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings. (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
</string-array>
<!-- WFC Operator Error Messages showed as notifications -->
<string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
+ <item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item>
</string-array>
<!-- Template for showing mobile network operator name while WFC is active -->
<string-array name="wfcSpnFormats">
@@ -4437,14 +4440,14 @@
<!-- Displayed when the USSD/SS request is modified by STK CC to a
different request. This will be displayed in a toast. -->
- <string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
- <string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
- <string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
- <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
- <string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
- <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
- <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
- <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+ <string name="stk_cc_ussd_to_dial">USSD request changed to regular call</string>
+ <string name="stk_cc_ussd_to_ss">USSD request changed to SS request</string>
+ <string name="stk_cc_ussd_to_ussd">Changed to new USSD request</string>
+ <string name="stk_cc_ussd_to_dial_video">USSD request changed to video call</string>
+ <string name="stk_cc_ss_to_dial">SS request changed to regular call</string>
+ <string name="stk_cc_ss_to_dial_video">SS request changed to video call</string>
+ <string name="stk_cc_ss_to_ussd">SS request changed to USSD request</string>
+ <string name="stk_cc_ss_to_ss">Changed to new SS request</string>
<!-- Content description of the work profile icon in the notification. -->
<string name="notification_work_profile_content_description">Work profile</string>
@@ -4682,11 +4685,17 @@
<!-- Primary ETWS (Earthquake and Tsunami Warning System) default message for others -->
<string name="etws_primary_default_message_others"></string>
- <!-- Title of notification when UE fails to register network with MM reject cause code. -->
- <string name="mmcc_authentication_reject">SIM not allowed</string>
- <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned</string>
- <string name="mmcc_illegal_ms">SIM not allowed</string>
- <string name="mmcc_illegal_me">Phone not allowed</string>
+ <!-- Title of notification when UE fails CS registration network with MM reject cause code from network. -->
+ <string name="mmcc_authentication_reject">SIM not allowed for voice</string>
+ <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned for voice</string>
+ <string name="mmcc_illegal_ms">SIM not allowed for voice</string>
+ <string name="mmcc_illegal_me">Phone not allowed for voice</string>
+
+ <!-- Title of notification when UE fails to register network with MM reject cause code when multiple SIMs are active. -->
+ <string name="mmcc_authentication_reject_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+ <string name="mmcc_imsi_unknown_in_hlr_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not provisioned</string>
+ <string name="mmcc_illegal_ms_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+ <string name="mmcc_illegal_me_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
<!-- Popup window default title to be read by a screen reader-->
<string name="popup_window_default_title">Popup Window</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f089ff0..e52f0f8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -547,6 +547,7 @@
<java-symbol type="string" name="RestrictedOnEmergencyTitle" />
<java-symbol type="string" name="RestrictedOnNormalTitle" />
<java-symbol type="string" name="RestrictedStateContent" />
+ <java-symbol type="string" name="RestrictedStateContentMsimTemplate" />
<java-symbol type="string" name="notification_channel_network_alert" />
<java-symbol type="string" name="notification_channel_call_forward" />
<java-symbol type="string" name="notification_channel_emergency_callback" />
@@ -1956,6 +1957,10 @@
<java-symbol type="string" name="mmcc_imsi_unknown_in_hlr" />
<java-symbol type="string" name="mmcc_illegal_ms" />
<java-symbol type="string" name="mmcc_illegal_me" />
+ <java-symbol type="string" name="mmcc_authentication_reject_msim_template" />
+ <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr_msim_template" />
+ <java-symbol type="string" name="mmcc_illegal_ms_msim_template" />
+ <java-symbol type="string" name="mmcc_illegal_me_msim_template" />
<java-symbol type="string" name="notification_listener_binding_label" />
<java-symbol type="string" name="vr_listener_binding_label" />
<java-symbol type="string" name="condition_provider_service_binding_label" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 757a70c..8a7c586 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -64,6 +64,7 @@
Settings.System.NOTIFICATION_LIGHT_PULSE, // candidate for backup?
Settings.System.NOTIFICATION_SOUND_CACHE, // internal cache
Settings.System.POINTER_LOCATION, // backup candidate?
+ Settings.System.DEBUG_ENABLE_ENHANCED_CALL_BLOCKING, // used for testing only
Settings.System.RINGTONE_CACHE, // internal cache
Settings.System.SETUP_WIZARD_HAS_RUN, // Only used by SuW
Settings.System.SHOW_GTALK_SERVICE_STATUS, // candidate for backup?
@@ -117,6 +118,7 @@
Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
+ Settings.Global.BLE_SCAN_BACKGROUND_MODE,
Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 282b001..933e54e 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -16,6 +16,9 @@
package android.os;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import junit.framework.TestCase;
import android.os.SystemProperties;
@@ -141,4 +144,48 @@
} catch (NullPointerException npe) {
}
}
+
+ @SmallTest
+ public void testCallbacks() {
+ // Latches are not really necessary, but are easy to use.
+ final CountDownLatch wait1 = new CountDownLatch(1);
+ final CountDownLatch wait2 = new CountDownLatch(1);
+
+ Runnable r1 = new Runnable() {
+ boolean done = false;
+ @Override
+ public void run() {
+ if (done) {
+ return;
+ }
+ done = true;
+
+ wait1.countDown();
+ throw new RuntimeException("test");
+ }
+ };
+
+ Runnable r2 = new Runnable() {
+ @Override
+ public void run() {
+ wait2.countDown();
+ }
+ };
+
+ SystemProperties.addChangeCallback(r1);
+ SystemProperties.addChangeCallback(r2);
+
+ SystemProperties.reportSyspropChanged();
+
+ try {
+ assertTrue(wait1.await(5, TimeUnit.SECONDS));
+ } catch (InterruptedException e) {
+ fail("InterruptedException");
+ }
+ try {
+ assertTrue(wait2.await(5, TimeUnit.SECONDS));
+ } catch (InterruptedException e) {
+ fail("InterruptedException");
+ }
+ }
}
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index be0372d..bacddf14 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -25,42 +25,50 @@
<hidden-api-whitelisted-app package="android.car.input.service" />
<hidden-api-whitelisted-app package="android.car.usb.handler" />
<hidden-api-whitelisted-app package="android.ext.services" />
- <hidden-api-whitelisted-app package="android.ext.shared" />
+ <hidden-api-whitelisted-app package="com.android.apps.tag" />
<hidden-api-whitelisted-app package="com.android.backupconfirm" />
+ <hidden-api-whitelisted-app package="com.android.basicsmsreceiver" />
<hidden-api-whitelisted-app package="com.android.bluetooth" />
<hidden-api-whitelisted-app package="com.android.bluetoothdebug" />
<hidden-api-whitelisted-app package="com.android.bluetoothmidiservice" />
+ <hidden-api-whitelisted-app package="com.android.bookmarkprovider" />
<hidden-api-whitelisted-app package="com.android.calllogbackup" />
+ <hidden-api-whitelisted-app package="com.android.camera" />
<hidden-api-whitelisted-app package="com.android.captiveportallogin" />
<hidden-api-whitelisted-app package="com.android.car" />
+ <hidden-api-whitelisted-app package="com.android.car.dialer" />
<hidden-api-whitelisted-app package="com.android.car.hvac" />
<hidden-api-whitelisted-app package="com.android.car.mapsplaceholder" />
<hidden-api-whitelisted-app package="com.android.car.media" />
<hidden-api-whitelisted-app package="com.android.car.media.localmediaplayer" />
+ <hidden-api-whitelisted-app package="com.android.car.messenger" />
+ <hidden-api-whitelisted-app package="com.android.car.overview" />
<hidden-api-whitelisted-app package="com.android.car.radio" />
<hidden-api-whitelisted-app package="com.android.car.settings" />
+ <hidden-api-whitelisted-app package="com.android.car.stream" />
<hidden-api-whitelisted-app package="com.android.car.systemupdater" />
<hidden-api-whitelisted-app package="com.android.car.trust" />
<hidden-api-whitelisted-app package="com.android.carrierconfig" />
<hidden-api-whitelisted-app package="com.android.carrierdefaultapp" />
<hidden-api-whitelisted-app package="com.android.cellbroadcastreceiver" />
<hidden-api-whitelisted-app package="com.android.certinstaller" />
+ <hidden-api-whitelisted-app package="com.android.companiondevicemanager" />
<hidden-api-whitelisted-app package="com.android.customlocale2" />
<hidden-api-whitelisted-app package="com.android.defcontainer" />
<hidden-api-whitelisted-app package="com.android.documentsui" />
+ <hidden-api-whitelisted-app package="com.android.dreams.basic" />
<hidden-api-whitelisted-app package="com.android.egg" />
- <hidden-api-whitelisted-app package="com.android.email.policy" />
<hidden-api-whitelisted-app package="com.android.emergency" />
<hidden-api-whitelisted-app package="com.android.externalstorage" />
<hidden-api-whitelisted-app package="com.android.fakeoemfeatures" />
<hidden-api-whitelisted-app package="com.android.gallery" />
<hidden-api-whitelisted-app package="com.android.hotspot2" />
- <hidden-api-whitelisted-app package="com.android.inputdevices" />
<hidden-api-whitelisted-app package="com.android.keychain" />
<hidden-api-whitelisted-app package="com.android.location.fused" />
<hidden-api-whitelisted-app package="com.android.managedprovisioning" />
<hidden-api-whitelisted-app package="com.android.mms.service" />
<hidden-api-whitelisted-app package="com.android.mtp" />
+ <hidden-api-whitelisted-app package="com.android.musicfx" />
<hidden-api-whitelisted-app package="com.android.nfc" />
<hidden-api-whitelisted-app package="com.android.osu" />
<hidden-api-whitelisted-app package="com.android.packageinstaller" />
@@ -70,12 +78,14 @@
<hidden-api-whitelisted-app package="com.android.printservice.recommendation" />
<hidden-api-whitelisted-app package="com.android.printspooler" />
<hidden-api-whitelisted-app package="com.android.providers.blockednumber" />
+ <hidden-api-whitelisted-app package="com.android.providers.calendar" />
<hidden-api-whitelisted-app package="com.android.providers.contacts" />
<hidden-api-whitelisted-app package="com.android.providers.downloads" />
<hidden-api-whitelisted-app package="com.android.providers.downloads.ui" />
<hidden-api-whitelisted-app package="com.android.providers.media" />
<hidden-api-whitelisted-app package="com.android.providers.settings" />
<hidden-api-whitelisted-app package="com.android.providers.telephony" />
+ <hidden-api-whitelisted-app package="com.android.providers.tv" />
<hidden-api-whitelisted-app package="com.android.providers.userdictionary" />
<hidden-api-whitelisted-app package="com.android.provision" />
<hidden-api-whitelisted-app package="com.android.proxyhandler" />
@@ -87,10 +97,15 @@
<hidden-api-whitelisted-app package="com.android.settings" />
<hidden-api-whitelisted-app package="com.android.sharedstoragebackup" />
<hidden-api-whitelisted-app package="com.android.shell" />
+ <hidden-api-whitelisted-app package="com.android.smspush" />
+ <hidden-api-whitelisted-app package="com.android.spare_parts" />
+ <hidden-api-whitelisted-app package="com.android.statementservice" />
<hidden-api-whitelisted-app package="com.android.stk" />
+ <hidden-api-whitelisted-app package="com.android.storagemanager" />
<hidden-api-whitelisted-app package="com.android.support.car.lenspicker" />
<hidden-api-whitelisted-app package="com.android.systemui" />
- <hidden-api-whitelisted-app package="com.android.systemui.theme.dark" />
+ <hidden-api-whitelisted-app package="com.android.systemui.plugins" />
+ <hidden-api-whitelisted-app package="com.android.terminal" />
<hidden-api-whitelisted-app package="com.android.timezone.updater" />
<hidden-api-whitelisted-app package="com.android.traceur" />
<hidden-api-whitelisted-app package="com.android.tv.settings" />
@@ -99,5 +114,5 @@
<hidden-api-whitelisted-app package="com.android.wallpaperbackup" />
<hidden-api-whitelisted-app package="com.android.wallpapercropper" />
<hidden-api-whitelisted-app package="com.googlecode.android_scripting" />
+ <hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" />
</config>
-
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 428f0b8..b83b8e1 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -456,10 +456,10 @@
<string name="keep_screen_on">Stay awake</string>
<!-- setting Checkbox summary whether to keep the screen on when plugged in -->
<string name="keep_screen_on_summary">Screen will never sleep while charging</string>
- <!-- Setting Checkbox title whether to enable bluetooth HCI snoop log -->
+ <!-- Setting Checkbox title whether to enable Bluetooth HCI snoop log -->
<string name="bt_hci_snoop_log">Enable Bluetooth HCI snoop log</string>
- <!-- setting Checkbox summary whether to capture all bluetooth HCI packets in a file -->
- <string name="bt_hci_snoop_log_summary">Capture all bluetooth HCI packets in a file</string>
+ <!-- setting Checkbox summary whether to capture all Bluetooth HCI packets in a file -->
+ <string name="bt_hci_snoop_log_summary">Capture all Bluetooth HCI packets in a file (Toggle Bluetooth after changing this setting)</string>
<!-- setting Checkbox title whether to enable OEM unlock [CHAR_LIMIT=35] -->
<string name="oem_unlock_enable">OEM unlocking</string>
<!-- setting Checkbox summary whether to enable OEM unlock [CHAR_LIMIT=50] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 52b4c0a..9845c51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -174,6 +174,7 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ if (mController == null) return;
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index b22ce18..0adb439 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -64,6 +64,7 @@
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .setUids(null)
.build();
private static final int NO_NETWORK = -1;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 7ca9d73..f76de5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -19,11 +19,15 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -32,6 +36,9 @@
import android.content.pm.StringParceledListSlice;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.os.UserManager;
import android.security.IKeyChainService;
import android.support.test.runner.AndroidJUnit4;
@@ -61,6 +68,7 @@
private final UserManager mUserManager = mock(UserManager.class);
private SecurityControllerImpl mSecurityController;
private CountDownLatch mStateChangedLatch;
+ private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class);
// implementing SecurityControllerCallback
@Override
@@ -72,7 +80,7 @@
public void setUp() throws Exception {
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(Context.USER_SERVICE, mUserManager);
- mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mock(ConnectivityManager.class));
+ mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mConnectivityManager);
Intent intent = new Intent(IKeyChainService.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
@@ -176,4 +184,12 @@
//assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS));
//assertFalse(mSecurityController.hasCACertInCurrentUser());
}
+
+ @Test
+ public void testNetworkRequest() {
+ verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat(
+ (NetworkRequest request) -> request.networkCapabilities.getUids() == null
+ && request.networkCapabilities.getCapabilities().length == 0
+ ), any(NetworkCallback.class));
+ }
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 029dc7b..6494a81d 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -60,6 +60,7 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
+import android.util.StatsLog;
import com.android.internal.R;
import com.android.internal.util.DumpUtils;
@@ -632,23 +633,14 @@
if (DBG) {
Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
}
- if (isBleAppPresent()) {
- // Nothing to do, another app is here.
- return;
- }
- if (DBG) {
- Slog.d(TAG, "Disabling LE only mode after application crash");
- }
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
- mEnable = false;
- mBluetooth.onBrEdrDown();
+
+ for (Map.Entry<IBinder, ClientDeathRecipient> entry : mBleApps.entrySet()) {
+ IBinder token = entry.getKey();
+ ClientDeathRecipient deathRec = entry.getValue();
+ if (deathRec.equals(this)) {
+ updateBleAppCount(token, false, mPackageName);
+ break;
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBrEdrDown", e);
- } finally {
- mBluetoothLock.readLock().unlock();
}
}
@@ -2154,6 +2146,11 @@
mActiveLogs.add(
new ActiveLog(reason, packageName, enable, System.currentTimeMillis()));
}
+
+ int state = enable ? StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED :
+ StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED;
+ StatsLog.write_non_chained(StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED,
+ Binder.getCallingUid(), null, state, reason, packageName);
}
private void addCrashLog() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6c24e94..ae7ac8f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1356,6 +1356,12 @@
}
}
+ private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
+ if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(Binder.getCallingUid())) {
+ nc.addCapability(NET_CAPABILITY_FOREGROUND);
+ }
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
@@ -4365,15 +4371,13 @@
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
restrictRequestUidsForCaller(nc);
- if (!ConnectivityManager.checkChangePermission(mContext)) {
- // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
- // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
- // onLost and onAvailable callbacks when networks move in and out of the background.
- // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
- // can't request networks.
- nc.addCapability(NET_CAPABILITY_FOREGROUND);
- }
- ensureValidNetworkSpecifier(networkCapabilities);
+ // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
+ // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
+ // onLost and onAvailable callbacks when networks move in and out of the background.
+ // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
+ // can't request networks.
+ restrictBackgroundRequestForCaller(nc);
+ ensureValidNetworkSpecifier(nc);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -4531,17 +4535,17 @@
return nai.network.netId;
}
- private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
+ private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
if (VDBG) log("Got NetworkAgent Messenger");
- mNetworkAgentInfos.put(na.messenger, na);
+ mNetworkAgentInfos.put(nai.messenger, nai);
synchronized (mNetworkForNetId) {
- mNetworkForNetId.put(na.network.netId, na);
+ mNetworkForNetId.put(nai.network.netId, nai);
}
- na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
- NetworkInfo networkInfo = na.networkInfo;
- na.networkInfo = null;
- updateNetworkInfo(na, networkInfo);
- updateUids(na, null, na.networkCapabilities);
+ nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
+ NetworkInfo networkInfo = nai.networkInfo;
+ nai.networkInfo = null;
+ updateNetworkInfo(nai, networkInfo);
+ updateUids(nai, null, nai.networkCapabilities);
}
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
@@ -5268,7 +5272,6 @@
for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
final String stackedIface = stacked.getInterfaceName();
bs.noteNetworkInterfaceType(stackedIface, type);
- NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
}
} catch (RemoteException ignored) {
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 45a4dfb9..d09a161 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -36,6 +36,7 @@
import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
+import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkUtils;
import android.net.TrafficStats;
@@ -618,10 +619,8 @@
spi,
mConfig.getMarkValue(),
mConfig.getMarkMask());
- } catch (ServiceSpecificException e) {
- // FIXME: get the error code and throw is at an IOException from Errno Exception
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
}
getResourceTracker().give();
@@ -677,14 +676,14 @@
@Override
public void freeUnderlyingResources() {
try {
- mSrvConfig
- .getNetdInstance()
- .ipSecDeleteSecurityAssociation(
- mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
- } catch (ServiceSpecificException e) {
- // FIXME: get the error code and throw is at an IOException from Errno Exception
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
+ if (!mOwnedByTransform) {
+ mSrvConfig
+ .getNetdInstance()
+ .ipSecDeleteSecurityAssociation(
+ mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+ }
+ } catch (ServiceSpecificException | RemoteException e) {
+ Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
}
mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
@@ -829,15 +828,13 @@
0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff);
}
}
- } catch (ServiceSpecificException e) {
- // FIXME: get the error code and throw is at an IOException from Errno Exception
- } catch (RemoteException e) {
+ } catch (ServiceSpecificException | RemoteException e) {
Log.e(
TAG,
"Failed to delete VTI with interface name: "
+ mInterfaceName
+ " and id: "
- + mResourceId);
+ + mResourceId, e);
}
getResourceTracker().give();
@@ -1319,7 +1316,9 @@
* from multiple local IP addresses over the same tunnel.
*/
@Override
- public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) {
+ public synchronized void addAddressToTunnelInterface(
+ int tunnelResourceId, LinkAddress localAddr) {
+ enforceNetworkStackPermission();
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
@@ -1327,8 +1326,21 @@
TunnelInterfaceRecord tunnelInterfaceInfo =
userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
- // TODO: Add calls to netd:
- // Add address to TunnelInterface
+ try {
+ // We can assume general validity of the IP address, since we get them as a
+ // LinkAddress, which does some validation.
+ mSrvConfig
+ .getNetdInstance()
+ .interfaceAddAddress(
+ tunnelInterfaceInfo.mInterfaceName,
+ localAddr.getAddress().getHostAddress(),
+ localAddr.getPrefixLength());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
+ throw new IllegalArgumentException(e);
+ }
}
/**
@@ -1337,7 +1349,8 @@
*/
@Override
public synchronized void removeAddressFromTunnelInterface(
- int tunnelResourceId, String localAddr) {
+ int tunnelResourceId, LinkAddress localAddr) {
+ enforceNetworkStackPermission();
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
@@ -1345,8 +1358,21 @@
TunnelInterfaceRecord tunnelInterfaceInfo =
userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
- // TODO: Add calls to netd:
- // Remove address from TunnelInterface
+ try {
+ // We can assume general validity of the IP address, since we get them as a
+ // LinkAddress, which does some validation.
+ mSrvConfig
+ .getNetdInstance()
+ .interfaceDelAddress(
+ tunnelInterfaceInfo.mInterfaceName,
+ localAddr.getAddress().getHostAddress(),
+ localAddr.getPrefixLength());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
+ throw new IllegalArgumentException(e);
+ }
}
/**
@@ -1467,6 +1493,13 @@
IpSecAlgorithm crypt = c.getEncryption();
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
+ String cryptName;
+ if (crypt == null) {
+ cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : "";
+ } else {
+ cryptName = crypt.getName();
+ }
+
mSrvConfig
.getNetdInstance()
.ipSecAddSecurityAssociation(
@@ -1481,7 +1514,7 @@
(auth != null) ? auth.getName() : "",
(auth != null) ? auth.getKey() : new byte[] {},
(auth != null) ? auth.getTruncationLengthBits() : 0,
- (crypt != null) ? crypt.getName() : "",
+ cryptName,
(crypt != null) ? crypt.getKey() : new byte[] {},
(crypt != null) ? crypt.getTruncationLengthBits() : 0,
(authCrypt != null) ? authCrypt.getName() : "",
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 88ae224..5d719ad 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1867,10 +1867,10 @@
}
@Override
- public NetworkStats getNetworkStatsUidDetail(int uid) {
+ public NetworkStats getNetworkStatsUidDetail(int uid, String[] ifaces) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
+ return mStatsFactory.readNetworkStatsDetail(uid, ifaces, TAG_ALL, null);
} catch (IOException e) {
throw new IllegalStateException(e);
}
@@ -1942,13 +1942,13 @@
@Override
public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains,
- int[] params, boolean useTls, String tlsHostname) {
+ int[] params, String tlsHostname, String[] tlsServers) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
final String[] tlsFingerprints = new String[0];
try {
mNetdService.setResolverConfiguration(
- netId, servers, domains, params, useTls, tlsHostname, tlsFingerprints);
+ netId, servers, domains, params, tlsHostname, tlsServers, tlsFingerprints);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62e82a0..539c001 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -65,7 +65,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -90,6 +89,8 @@
private static final boolean VDBG = false; // STOPSHIP if true
private static class Record {
+ Context context;
+
String callingPackage;
IBinder binder;
@@ -108,8 +109,6 @@
int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
- boolean canReadPhoneState;
-
boolean matchPhoneStateListenerEvent(int events) {
return (callback != null) && ((events & this.events) != 0);
}
@@ -118,6 +117,15 @@
return (onSubscriptionsChangedListenerCallback != null);
}
+ boolean canReadPhoneState() {
+ try {
+ return TelephonyPermissions.checkReadPhoneState(
+ context, subId, callerPid, callerUid, callingPackage, "listen");
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
@Override
public String toString() {
return "{callingPackage=" + callingPackage + " binder=" + binder
@@ -125,8 +133,7 @@
+ " onSubscriptionsChangedListenererCallback="
+ onSubscriptionsChangedListenerCallback
+ " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
- + " events=" + Integer.toHexString(events)
- + " canReadPhoneState=" + canReadPhoneState + "}";
+ + " events=" + Integer.toHexString(events) + "}";
}
}
@@ -164,14 +171,9 @@
private int[] mDataActivity;
+ // Connection state of default APN type data (i.e. internet) of phones
private int[] mDataConnectionState;
- private ArrayList<String>[] mConnectedApns;
-
- private LinkProperties[] mDataConnectionLinkProperties;
-
- private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
-
private Bundle[] mCellLocation;
private int[] mDataConnectionNetworkType;
@@ -212,11 +214,6 @@
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
PhoneStateListener.LISTEN_VOLTE_STATE;
- static final int CHECK_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_CALL_STATE |
- PhoneStateListener.LISTEN_DATA_ACTIVITY |
- PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
-
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
@@ -323,9 +320,8 @@
mBatteryStats = BatteryStatsService.getService();
int numPhones = TelephonyManager.getDefault().getPhoneCount();
- if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones);
+ if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones);
mNumPhones = numPhones;
- mConnectedApns = new ArrayList[numPhones];
mCallState = new int[numPhones];
mDataActivity = new int[numPhones];
mDataConnectionState = new int[numPhones];
@@ -339,8 +335,6 @@
mMessageWaiting = new boolean[numPhones];
mCallForwarding = new boolean[numPhones];
mCellLocation = new Bundle[numPhones];
- mDataConnectionLinkProperties = new LinkProperties[numPhones];
- mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
mCellInfo = new ArrayList<List<CellInfo>>();
mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
for (int i = 0; i < numPhones; i++) {
@@ -358,7 +352,6 @@
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
mPhysicalChannelConfigs.add(i, null);
- mConnectedApns[i] = new ArrayList<String>();
}
// Note that location can be null for non-phone builds like
@@ -386,22 +379,13 @@
public void addOnSubscriptionsChangedListener(String callingPackage,
IOnSubscriptionsChangedListener callback) {
int callerUserId = UserHandle.getCallingUserId();
- mContext.getSystemService(AppOpsManager.class)
- .checkPackage(Binder.getCallingUid(), callingPackage);
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
+ " callerUserId=" + callerUserId + " callback=" + callback
+ " callback.asBinder=" + callback.asBinder());
}
- // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
- "addOnSubscriptionsChangedListener")) {
- return;
- }
-
-
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
@@ -411,12 +395,12 @@
return;
}
+ r.context = mContext;
r.onSubscriptionsChangedListenerCallback = callback;
r.callingPackage = callingPackage;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
r.events = 0;
- r.canReadPhoneState = true; // permission has been enforced above
if (DBG) {
log("listen oscl: Register r=" + r);
}
@@ -485,8 +469,7 @@
private void listen(String callingPackage, IPhoneStateListener callback, int events,
boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
- mContext.getSystemService(AppOpsManager.class)
- .checkPackage(Binder.getCallingUid(), callingPackage);
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -497,7 +480,7 @@
// Checks permission and throws SecurityException for disallowed operations. For pre-M
// apps whose runtime permission has been revoked, we return immediately to skip sending
// events to the app without crashing it.
- if (!checkListenerPermission(events, callingPackage, "listen")) {
+ if (!checkListenerPermission(events, subId, callingPackage, "listen")) {
return;
}
@@ -511,14 +494,11 @@
return;
}
+ r.context = mContext;
r.callback = callback;
r.callingPackage = callingPackage;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
- boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
- | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
- r.canReadPhoneState =
- isPhoneStateEvent && canReadPhoneState(callingPackage, "listen");
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -686,19 +666,9 @@
}
}
- private boolean canReadPhoneState(String callingPackage, String message) {
- try {
- // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
- return TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
- } catch (SecurityException e) {
- return false;
- }
- }
-
private String getCallIncomingNumber(Record record, int phoneId) {
- // Hide the number if record's process has no READ_PHONE_STATE permission
- return record.canReadPhoneState ? mCallIncomingNumber[phoneId] : "";
+ // Hide the number if record's process can't currently read phone state.
+ return record.canReadPhoneState() ? mCallIncomingNumber[phoneId] : "";
}
private Record add(IBinder binder) {
@@ -773,7 +743,7 @@
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
(r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
- String incomingNumberOrEmpty = r.canReadPhoneState ? incomingNumber : "";
+ String incomingNumberOrEmpty = r.canReadPhoneState() ? incomingNumber : "";
r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
@@ -1219,36 +1189,12 @@
int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- boolean modified = false;
- if (state == TelephonyManager.DATA_CONNECTED) {
- if (!mConnectedApns[phoneId].contains(apnType)) {
- mConnectedApns[phoneId].add(apnType);
- if (mDataConnectionState[phoneId] != state) {
- mDataConnectionState[phoneId] = state;
- modified = true;
- }
- }
- } else {
- if (mConnectedApns[phoneId].remove(apnType)) {
- if (mConnectedApns[phoneId].isEmpty()) {
- mDataConnectionState[phoneId] = state;
- modified = true;
- } else {
- // leave mDataConnectionState as is and
- // send out the new status for the APN in question.
- }
- }
- }
- mDataConnectionLinkProperties[phoneId] = linkProperties;
- mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
- if (mDataConnectionNetworkType[phoneId] != networkType) {
- mDataConnectionNetworkType[phoneId] = networkType;
- // need to tell registered listeners about the new network type
- modified = true;
- }
- if (modified) {
- String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
- + ", " + mDataConnectionNetworkType[phoneId] + ")";
+ // We only call the callback when the change is for default APN type.
+ if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)
+ && (mDataConnectionState[phoneId] != state
+ || mDataConnectionNetworkType[phoneId] != networkType)) {
+ String str = "onDataConnectionStateChanged(" + state
+ + ", " + networkType + ")";
log(str);
mLocalLog.log(str);
for (Record r : mRecords) {
@@ -1259,15 +1205,16 @@
if (DBG) {
log("Notify data connection state changed on sub: " + subId);
}
- r.callback.onDataConnectionStateChanged(
- mDataConnectionState[phoneId],
- mDataConnectionNetworkType[phoneId]);
+ r.callback.onDataConnectionStateChanged(state, networkType);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
+
+ mDataConnectionState[phoneId] = state;
+ mDataConnectionNetworkType[phoneId] = networkType;
}
mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
apnType, apn, reason, linkProperties, "");
@@ -1503,14 +1450,10 @@
pw.println("mCallForwarding=" + mCallForwarding[i]);
pw.println("mDataActivity=" + mDataActivity[i]);
pw.println("mDataConnectionState=" + mDataConnectionState[i]);
- pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
- pw.println("mDataConnectionNetworkCapabilities=" +
- mDataConnectionNetworkCapabilities[i]);
pw.println("mCellLocation=" + mCellLocation[i]);
pw.println("mCellInfo=" + mCellInfo.get(i));
pw.decreaseIndent();
}
- pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns));
pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
pw.println("mPreciseCallState=" + mPreciseCallState);
pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
@@ -1727,7 +1670,8 @@
== PackageManager.PERMISSION_GRANTED;
}
- private boolean checkListenerPermission(int events, String callingPackage, String message) {
+ private boolean checkListenerPermission(
+ int events, int subId, String callingPackage, String message) {
if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
@@ -1738,9 +1682,8 @@
}
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message)) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+ mContext, subId, callingPackage, message)) {
return false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6c60b74..c21af48 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -257,6 +257,7 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
@@ -2695,13 +2696,15 @@
}
/**
- * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
+ * Encapsulates the global setting "hidden_api_blacklist_exemptions", including tracking the
* latest value via a content observer.
*/
static class HiddenApiBlacklist extends ContentObserver {
private final Context mContext;
private boolean mBlacklistDisabled;
+ private String mExemptionsStr;
+ private List<String> mExemptions = Collections.emptyList();
public HiddenApiBlacklist(Handler handler, Context context) {
super(handler);
@@ -2717,8 +2720,22 @@
}
private void update() {
- mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
+ String exemptions = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+ if (!TextUtils.equals(exemptions, mExemptionsStr)) {
+ mExemptionsStr = exemptions;
+ if ("*".equals(exemptions)) {
+ mBlacklistDisabled = true;
+ mExemptions = Collections.emptyList();
+ } else {
+ mBlacklistDisabled = false;
+ mExemptions = TextUtils.isEmpty(exemptions)
+ ? Collections.emptyList()
+ : Arrays.asList(exemptions.split(":"));
+ }
+ zygoteProcess.setApiBlacklistExemptions(mExemptions);
+ }
+
}
boolean isDisabled() {
@@ -3944,12 +3961,14 @@
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
- if (!app.info.isAllowedToUseHiddenApi() &&
- !disableHiddenApiChecks &&
- !mHiddenApiBlacklist.isDisabled()) {
- // This app is not allowed to use undocumented and private APIs, or blacklisting is
- // enabled. Set up its runtime with the appropriate flag.
- runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS;
+ if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
+ @HiddenApiEnforcementPolicy int policy =
+ app.info.getHiddenApiEnforcementPolicy();
+ int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
+ if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
+ throw new IllegalStateException("Invalid API policy: " + policy);
+ }
+ runtimeFlags |= policyBits;
}
String invokeWith = null;
@@ -5678,15 +5697,16 @@
* since it's the system_server that creates trace files for most ANRs.
*/
private static void maybePruneOldTraces(File tracesDir) {
- final long now = System.currentTimeMillis();
- final File[] traceFiles = tracesDir.listFiles();
+ final File[] files = tracesDir.listFiles();
+ if (files == null) return;
- if (traceFiles != null) {
- for (File file : traceFiles) {
- if ((now - file.lastModified()) > DAY_IN_MILLIS) {
- if (!file.delete()) {
- Slog.w(TAG, "Unable to prune stale trace file: " + file);
- }
+ final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64);
+ final long now = System.currentTimeMillis();
+ Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
+ for (int i = 0; i < files.length; ++i) {
+ if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) {
+ if (!files[i].delete()) {
+ Slog.w(TAG, "Unable to prune stale trace file: " + files[i]);
}
}
}
@@ -7145,6 +7165,9 @@
if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup();
+ if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
+ clearProfilerLocked();
+ }
}
// We deprecated Build.SERIAL and it is not accessible to
@@ -7211,7 +7234,10 @@
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
-
+ if (profilerInfo != null) {
+ profilerInfo.closeFd();
+ profilerInfo = null;
+ }
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
@@ -23603,6 +23629,14 @@
} catch (IOException e) {
}
mProfilerInfo.profileFd = null;
+
+ if (proc.pid == MY_PID) {
+ // When profiling the system server itself, avoid closing the file
+ // descriptor, as profilerControl will not create a copy.
+ // Note: it is also not correct to just set profileFd to null, as the
+ // whole ProfilerInfo instance is passed down!
+ profilerInfo = null;
+ }
} else {
stopProfilerLocked(proc, profileType);
if (profilerInfo != null && profilerInfo.profileFd != null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9e37c78..5573cd9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -684,6 +684,14 @@
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
if (maxCallVolume != -1) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
+ }
+
+ int defaultCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_default", -1);
+ if (defaultCallVolume != -1 &&
+ defaultCallVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] &&
+ defaultCallVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
+ AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume;
+ } else {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
(maxCallVolume * 3) / 4;
}
@@ -695,7 +703,8 @@
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
if (defaultMusicVolume != -1 &&
- defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
+ defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
+ defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
} else {
if (isPlatformTelevision()) {
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 557828a..36f5a6c 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -192,6 +192,12 @@
public void setDnsConfigurationForNetwork(
int netId, LinkProperties lp, boolean isDefaultNetwork) {
+ final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
+ final String[] domainStrs = getDomainStrings(lp.getDomains());
+
+ updateParametersSettings();
+ final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
+
// We only use the PrivateDnsConfig data pushed to this class instance
// from ConnectivityService because it works in coordination with
// NetworkMonitor to decide which networks need validation and runs the
@@ -204,23 +210,20 @@
final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls;
final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode();
final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
-
- final String[] serverStrs = NetworkUtils.makeStrings(
- strictMode ? Arrays.stream(privateDnsCfg.ips)
- .filter((ip) -> lp.isReachable(ip))
- .collect(Collectors.toList())
- : lp.getDnsServers());
- final String[] domainStrs = getDomainStrings(lp.getDomains());
-
- updateParametersSettings();
- final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
+ final String[] tlsServers =
+ strictMode ? NetworkUtils.makeStrings(
+ Arrays.stream(privateDnsCfg.ips)
+ .filter((ip) -> lp.isReachable(ip))
+ .collect(Collectors.toList()))
+ : useTls ? assignedServers // Opportunistic
+ : new String[0]; // Off
Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
- netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs),
- Arrays.toString(params), useTls, tlsHostname));
+ netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
+ Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
try {
mNMS.setDnsConfigurationForNetwork(
- netId, serverStrs, domainStrs, params, useTls, tlsHostname);
+ netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
} catch (Exception e) {
Slog.e(TAG, "Error setting DNS configuration: " + e);
return;
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index e084ff8..d578e95 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -27,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,6 +41,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -150,7 +154,14 @@
update(mUsers, mApps, true);
}
- private boolean hasPermission(PackageInfo app, String permission) {
+ @VisibleForTesting
+ boolean isPreinstalledSystemApp(PackageInfo app) {
+ int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
+ return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
+ }
+
+ @VisibleForTesting
+ boolean hasPermission(PackageInfo app, String permission) {
if (app.requestedPermissions != null) {
for (String p : app.requestedPermissions) {
if (permission.equals(p)) {
@@ -166,14 +177,40 @@
}
private boolean hasRestrictedNetworkPermission(PackageInfo app) {
- int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
- if ((flags & FLAG_SYSTEM) != 0 || (flags & FLAG_UPDATED_SYSTEM_APP) != 0) {
- return true;
- }
+ if (isPreinstalledSystemApp(app)) return true;
return hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
+ private boolean hasUseBackgroundNetworksPermission(PackageInfo app) {
+ // This function defines what it means to hold the permission to use
+ // background networks.
+ return hasPermission(app, CHANGE_NETWORK_STATE)
+ || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
+ || hasPermission(app, CONNECTIVITY_INTERNAL)
+ || hasPermission(app, NETWORK_STACK)
+ // TODO : remove this check (b/31479477). Not all preinstalled apps should
+ // have access to background networks, they should just request the appropriate
+ // permission for their use case from the list above.
+ || isPreinstalledSystemApp(app);
+ }
+
+ public boolean hasUseBackgroundNetworksPermission(int uid) {
+ final String[] names = mPackageManager.getPackagesForUid(uid);
+ if (null == names || names.length == 0) return false;
+ try {
+ // Only using the first package name. There may be multiple names if multiple
+ // apps share the same UID, but in that case they also share permissions so
+ // querying with any of the names will return the same results.
+ final PackageInfo app = mPackageManager.getPackageInfo(names[0], GET_PERMISSIONS);
+ return hasUseBackgroundNetworksPermission(app);
+ } catch (NameNotFoundException e) {
+ // App not found.
+ loge("NameNotFoundException " + names[0], e);
+ return false;
+ }
+ }
+
private int[] toIntArray(List<Integer> list) {
int[] array = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
@@ -308,4 +345,8 @@
private static void loge(String s) {
Log.e(TAG, s);
}
+
+ private static void loge(String s, Throwable e) {
+ Log.e(TAG, s, e);
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index cffa834..9581308 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -181,6 +181,7 @@
private final VersionedBroadcastListener mCarrierConfigChange;
// TODO: Delete SimChangeListener; it's obsolete.
private final SimChangeListener mSimChange;
+ private final TetheringDependencies mDeps;
private volatile TetheringConfiguration mConfig;
private String mCurrentUpstreamIface;
@@ -202,12 +203,13 @@
mPolicyManager = policyManager;
mLooper = looper;
mSystemProperties = systemProperties;
+ mDeps = deps;
mPublicSync = new Object();
mTetherStates = new ArrayMap<>();
- mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
+ mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
mTetherMasterSM.start();
final Handler smHandler = mTetherMasterSM.getHandler();
@@ -215,8 +217,8 @@
deps.getOffloadHardwareInterface(smHandler, mLog),
mContext.getContentResolver(), mNMService,
mLog);
- mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
- mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+ mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
+ TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
IntentFilter filter = new IntentFilter();
@@ -1240,7 +1242,7 @@
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
- TetherMasterSM(String name, Looper looper) {
+ TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
super(name, looper);
mInitialState = new InitialState();
@@ -1260,7 +1262,7 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
+ mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
mOffload = new OffloadWrapper();
setInitialState(mInitialState);
@@ -1996,7 +1998,7 @@
final TetherState tetherState = new TetherState(
new TetherInterfaceStateMachine(
iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
- makeControlCallback(iface)));
+ makeControlCallback(iface), mDeps));
mTetherStates.put(iface, tetherState);
tetherState.stateMachine.start();
}
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 2224913..e4c7ca0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -117,6 +117,8 @@
private final int mInterfaceType;
private final LinkProperties mLinkProperties;
+ private final TetheringDependencies mDeps;
+
private int mLastError;
private int mServingMode;
private String mMyUpstreamIfaceName; // may change over time
@@ -134,18 +136,19 @@
public TetherInterfaceStateMachine(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController) {
+ IControlsTethering tetherController,
+ TetheringDependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNMService = nMService;
- // TODO: This should be passed in for testability.
- mNetd = NetdService.getInstance();
+ mNetd = deps.getNetdService();
mStatsService = statsService;
mTetherController = tetherController;
mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
mLinkProperties = new LinkProperties();
+ mDeps = deps;
resetLinkProperties();
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mServingMode = IControlsTethering.STATE_AVAILABLE;
@@ -246,16 +249,14 @@
}
private boolean startIPv6() {
- // TODO: Refactor for better testability. This is one of the things
- // that prohibits unittesting IPv6 tethering setup.
- mInterfaceParams = InterfaceParams.getByName(mIfaceName);
+ mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
if (mInterfaceParams == null) {
mLog.e("Failed to find InterfaceParams");
stopIPv6();
return false;
}
- mRaDaemon = new RouterAdvertisementDaemon(mInterfaceParams);
+ mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
if (!mRaDaemon.start()) {
stopIPv6();
return false;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index b8174b6..66afb0f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -16,9 +16,18 @@
package com.android.server.connectivity.tethering;
+import android.content.Context;
+import android.net.INetd;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.util.InterfaceParams;
+import android.net.util.NetdService;
import android.os.Handler;
import android.net.util.SharedLog;
+import com.android.internal.util.StateMachine;
+
+import java.util.ArrayList;
+
/**
* Capture tethering dependencies, for injection.
@@ -29,4 +38,26 @@
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
return new OffloadHardwareInterface(h, log);
}
+
+ public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
+ SharedLog log, int what) {
+ return new UpstreamNetworkMonitor(ctx, target, log, what);
+ }
+
+ public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+ ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+ return new IPv6TetheringCoordinator(notifyList, log);
+ }
+
+ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+ return new RouterAdvertisementDaemon(ifParams);
+ }
+
+ public InterfaceParams getInterfaceParams(String ifName) {
+ return InterfaceParams.getByName(ifName);
+ }
+
+ public INetd getNetdService() {
+ return NetdService.getInstance();
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8298127..e0a8643 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -27,6 +27,7 @@
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.SET_ALL;
@@ -34,6 +35,7 @@
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
@@ -128,6 +130,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -143,6 +146,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -726,7 +730,8 @@
final long token = Binder.clearCallingIdentity();
final NetworkStats networkLayer;
try {
- networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
+ networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid,
+ NetworkStats.INTERFACES_ALL);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -748,6 +753,18 @@
}
@Override
+ public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
+ try {
+ final String[] ifacesToQuery =
+ NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces);
+ return getNetworkStatsUidDetail(ifacesToQuery);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error compiling UID stats", e);
+ return new NetworkStats(0L, 0);
+ }
+ }
+
+ @Override
public String[] getMobileIfaces() {
return mMobileIfaces;
}
@@ -1109,6 +1126,8 @@
if (isMobile) {
mobileIfaces.add(stackedIface);
}
+
+ NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
}
}
}
@@ -1130,7 +1149,7 @@
private void recordSnapshotLocked(long currentTime) throws RemoteException {
// snapshot and record current counters; read UID stats first to
// avoid over counting dev stats.
- final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+ final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
final NetworkStats xtSnapshot = getNetworkStatsXt();
final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
@@ -1464,12 +1483,19 @@
* Return snapshot of current UID statistics, including any
* {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations}
* values.
+ *
+ * @param ifaces A list of interfaces the stats should be restricted to, or
+ * {@link NetworkStats#INTERFACES_ALL}.
*/
- private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
- final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
+ private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
+ throws RemoteException {
+
+ final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL,
+ ifaces);
// fold tethering stats and operations into uid snapshot
final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
+ tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
uidSnapshot.combineAllValues(tetherSnapshot);
final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -1478,10 +1504,14 @@
// fold video calling data usage stats into uid snapshot
final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
if (vtStats != null) {
+ vtStats.filter(UID_ALL, ifaces, TAG_ALL);
uidSnapshot.combineAllValues(vtStats);
}
+
uidSnapshot.combineAllValues(mUidOperations);
+ // TODO: apply tethering & VC 464xlat adjustments here
+
return uidSnapshot;
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5ea778b..ae48844 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -47,6 +47,8 @@
import dalvik.system.DexFile;
+import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_NONE;
+
import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
@@ -532,7 +534,10 @@
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
- int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
+ // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist
+ int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_NONE
+ ? 0
+ : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
// Avoid generating CompactDex for modes that are latency critical.
final int compilationReason = options.getCompilationReason();
boolean generateCompactDex = true;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2579e56..0971058 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -992,7 +992,7 @@
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
UserHandle.USER_ALL);
updateSettings();
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 73243d2..1c0e260 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -881,7 +881,7 @@
*/
@IntDef(prefix = { "HANDOVER_" },
value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED,
- HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERG_CALL,
+ HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL,
HANDOVER_FAILURE_UNKNOWN})
@Retention(RetentionPolicy.SOURCE)
public @interface HandoverFailureErrors {}
@@ -939,7 +939,7 @@
* For more information on call handovers, see
* {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
- public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4;
+ public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fa07777..cc3cd4d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1926,7 +1926,7 @@
sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
- sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
@@ -2209,7 +2209,9 @@
/**
* Gets the configuration values for a particular subscription, which is associated with a
* specific SIM card. If an invalid subId is used, the returned config will contain default
- * values.
+ * values. After using this method to get the configuration bundle,
+ * {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether
+ * any carrier specific configuration has been applied.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2236,7 +2238,9 @@
}
/**
- * Gets the configuration values for the default subscription.
+ * Gets the configuration values for the default subscription. After using this method to get
+ * the configuration bundle, {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be
+ * called to confirm whether any carrier specific configuration has been applied.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2265,6 +2269,9 @@
* <p>
* After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
* use this method to confirm whether any carrier specific configuration has been applied.
+ * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
+ * still needs to get the current configuration, it must use this method to verify whether the
+ * configuration is default or carrier overridden.
* </p>
*
* @param bundle the configuration bundle to be checked.
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 105ddb0..713ac00 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -181,6 +182,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -189,6 +191,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 52944a8..aae7929 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -191,6 +192,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -199,6 +201,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 37fb075..9b3ef56 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -201,6 +202,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -209,6 +211,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 992545d..7475c74 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -34,6 +35,10 @@
private final int mCid;
// 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
private final int mCpid;
+ // long alpha Operator Name String or Enhanced Operator Name String
+ private final String mAlphaLong;
+ // short alpha Operator Name String or Enhanced Operator Name String
+ private final String mAlphaShort;
/**
* @hide
@@ -43,6 +48,8 @@
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mCpid = Integer.MAX_VALUE;
+ mAlphaLong = null;
+ mAlphaShort = null;
}
/**
@@ -55,7 +62,7 @@
* @hide
*/
public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) {
- this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid);
+ this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, null, null);
}
/**
@@ -65,6 +72,7 @@
* @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
*
+ * FIXME: This is a temporary constructor to facilitate migration.
* @hide
*/
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
@@ -72,10 +80,34 @@
mLac = lac;
mCid = cid;
mCpid = cpid;
+ mAlphaLong = null;
+ mAlphaShort = null;
+ }
+
+ /**
+ * @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
+ * @param alphal long alpha Operator Name String or Enhanced Operator Name String
+ * @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ *
+ * @hide
+ */
+ public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
+ String alphal, String alphas) {
+ super(TAG, TYPE_TDSCDMA, mcc, mnc);
+ mLac = lac;
+ mCid = cid;
+ mCpid = cpid;
+ mAlphaLong = alphal;
+ mAlphaShort = alphas;
}
private CellIdentityTdscdma(CellIdentityTdscdma cid) {
- this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid);
+ this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid,
+ cid.mCpid, cid.mAlphaLong, cid.mAlphaShort);
}
CellIdentityTdscdma copy() {
@@ -119,9 +151,31 @@
return mCpid;
}
+ /**
+ * @return The long alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ *
+ * @hide
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaLong() {
+ return mAlphaLong;
+ }
+
+ /**
+ * @return The short alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ *
+ * @hide
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaShort() {
+ return mAlphaShort;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid);
+ return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort);
}
@Override
@@ -139,7 +193,9 @@
&& TextUtils.equals(mMncStr, o.mMncStr)
&& mLac == o.mLac
&& mCid == o.mCid
- && mCpid == o.mCpid;
+ && mCpid == o.mCpid
+ && mAlphaLong == o.mAlphaLong
+ && mAlphaShort == o.mAlphaShort;
}
@Override
@@ -150,6 +206,8 @@
.append(" mLac=").append(mLac)
.append(" mCid=").append(mCid)
.append(" mCpid=").append(mCpid)
+ .append(" mAlphaLong=").append(mAlphaLong)
+ .append(" mAlphaShort=").append(mAlphaShort)
.append("}").toString();
}
@@ -161,6 +219,8 @@
dest.writeInt(mLac);
dest.writeInt(mCid);
dest.writeInt(mCpid);
+ dest.writeString(mAlphaLong);
+ dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -169,6 +229,8 @@
mLac = in.readInt();
mCid = in.readInt();
mCpid = in.readInt();
+ mAlphaLong = in.readString();
+ mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index affa0c1..52fa54f 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -182,6 +183,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -190,6 +192,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index 81a966b..cdab521 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -31,11 +31,13 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.telephony.mbms.DownloadStateCallback;
+import android.telephony.mbms.DownloadProgressListener;
+import android.telephony.mbms.DownloadStatusListener;
import android.telephony.mbms.FileInfo;
import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.InternalDownloadProgressListener;
import android.telephony.mbms.InternalDownloadSessionCallback;
-import android.telephony.mbms.InternalDownloadStateCallback;
+import android.telephony.mbms.InternalDownloadStatusListener;
import android.telephony.mbms.MbmsDownloadSessionCallback;
import android.telephony.mbms.MbmsDownloadReceiver;
import android.telephony.mbms.MbmsErrors;
@@ -240,8 +242,10 @@
private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
private final InternalDownloadSessionCallback mInternalCallback;
- private final Map<DownloadStateCallback, InternalDownloadStateCallback>
- mInternalDownloadCallbacks = new HashMap<>();
+ private final Map<DownloadStatusListener, InternalDownloadStatusListener>
+ mInternalDownloadStatusListeners = new HashMap<>();
+ private final Map<DownloadProgressListener, InternalDownloadProgressListener>
+ mInternalDownloadProgressListeners = new HashMap<>();
private MbmsDownloadSession(Context context, Executor executor, int subscriptionId,
MbmsDownloadSessionCallback callback) {
@@ -569,34 +573,33 @@
}
/**
- * Registers a callback for a {@link DownloadRequest} previously requested via
+ * Registers a listener download status for a {@link DownloadRequest} previously requested via
* {@link #download(DownloadRequest)}. This callback will only be called as long as both this
* app and the middleware are both running -- if either one stops, no further calls on the
- * provided {@link DownloadStateCallback} will be enqueued.
+ * provided {@link DownloadStatusListener} will be enqueued.
*
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
* @param request The {@link DownloadRequest} that you want updates on.
- * @param executor The {@link Executor} on which calls to {@code callback} should be executed.
- * @param callback The callback that should be called when the middleware has information to
- * share on the download.
+ * @param executor The {@link Executor} on which calls to {@code listener } should be executed.
+ * @param listener The listener that should be called when the middleware has information to
+ * share on the status download.
* @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
* and some other error code otherwise.
*/
- public int registerStateCallback(@NonNull DownloadRequest request,
- @NonNull Executor executor, @NonNull DownloadStateCallback callback) {
+ public int addStatusListener(@NonNull DownloadRequest request,
+ @NonNull Executor executor, @NonNull DownloadStatusListener listener) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
}
- InternalDownloadStateCallback internalCallback =
- new InternalDownloadStateCallback(callback, executor);
+ InternalDownloadStatusListener internalListener =
+ new InternalDownloadStatusListener(listener, executor);
try {
- int result = downloadService.registerStateCallback(request, internalCallback,
- callback.getCallbackFilterFlags());
+ int result = downloadService.addStatusListener(request, internalListener);
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
@@ -608,40 +611,41 @@
sIsInitialized.set(false);
return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
- mInternalDownloadCallbacks.put(callback, internalCallback);
+ mInternalDownloadStatusListeners.put(listener, internalListener);
return MbmsErrors.SUCCESS;
+
}
/**
- * Un-register a callback previously registered via
- * {@link #registerStateCallback(DownloadRequest, Executor, DownloadStateCallback)}. After
- * this method is called, no further callbacks will be enqueued on the {@link Handler}
+ * Un-register a listener previously registered via
+ * {@link #addStatusListener(DownloadRequest, Executor, DownloadStatusListener)}. After
+ * this method is called, no further calls will be enqueued on the {@link Executor}
* provided upon registration, even if this method throws an exception.
*
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
* @param request The {@link DownloadRequest} provided during registration
- * @param callback The callback provided during registration.
+ * @param listener The listener provided during registration.
* @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
* and some other error code otherwise.
*/
- public int unregisterStateCallback(@NonNull DownloadRequest request,
- @NonNull DownloadStateCallback callback) {
+ public int removeStatusListener(@NonNull DownloadRequest request,
+ @NonNull DownloadStatusListener listener) {
try {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
}
- InternalDownloadStateCallback internalCallback =
- mInternalDownloadCallbacks.get(callback);
- if (internalCallback == null) {
- throw new IllegalArgumentException("Provided callback was never registered");
+ InternalDownloadStatusListener internalListener =
+ mInternalDownloadStatusListeners.get(listener);
+ if (internalListener == null) {
+ throw new IllegalArgumentException("Provided listener was never registered");
}
try {
- int result = downloadService.unregisterStateCallback(request, internalCallback);
+ int result = downloadService.removeStatusListener(request, internalListener);
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
@@ -654,8 +658,102 @@
return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
} finally {
- InternalDownloadStateCallback internalCallback =
- mInternalDownloadCallbacks.remove(callback);
+ InternalDownloadStatusListener internalCallback =
+ mInternalDownloadStatusListeners.remove(listener);
+ if (internalCallback != null) {
+ internalCallback.stop();
+ }
+ }
+ return MbmsErrors.SUCCESS;
+ }
+
+ /**
+ * Registers a listener for progress for a {@link DownloadRequest} previously requested via
+ * {@link #download(DownloadRequest)}. This listener will only be called as long as both this
+ * app and the middleware are both running -- if either one stops, no further calls on the
+ * provided {@link DownloadProgressListener} will be enqueued.
+ *
+ * If the middleware is not aware of the specified download request,
+ * this method will throw an {@link IllegalArgumentException}.
+ *
+ * @param request The {@link DownloadRequest} that you want updates on.
+ * @param executor The {@link Executor} on which calls to {@code listener} should be executed.
+ * @param listener The listener that should be called when the middleware has information to
+ * share on the progress of the download.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
+ */
+ public int addProgressListener(@NonNull DownloadRequest request,
+ @NonNull Executor executor, @NonNull DownloadProgressListener listener) {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new IllegalStateException("Middleware not yet bound");
+ }
+
+ InternalDownloadProgressListener internalListener =
+ new InternalDownloadProgressListener(listener, executor);
+
+ try {
+ int result = downloadService.addProgressListener(request, internalListener);
+ if (result != MbmsErrors.SUCCESS) {
+ if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
+ throw new IllegalArgumentException("Unknown download request.");
+ }
+ return result;
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ sIsInitialized.set(false);
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ }
+ mInternalDownloadProgressListeners.put(listener, internalListener);
+ return MbmsErrors.SUCCESS;
+ }
+
+ /**
+ * Un-register a listener previously registered via
+ * {@link #addProgressListener(DownloadRequest, Executor, DownloadProgressListener)}. After
+ * this method is called, no further callbacks will be enqueued on the {@link Handler}
+ * provided upon registration, even if this method throws an exception.
+ *
+ * If the middleware is not aware of the specified download request,
+ * this method will throw an {@link IllegalArgumentException}.
+ *
+ * @param request The {@link DownloadRequest} provided during registration
+ * @param listener The listener provided during registration.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
+ */
+ public int removeProgressListener(@NonNull DownloadRequest request,
+ @NonNull DownloadProgressListener listener) {
+ try {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new IllegalStateException("Middleware not yet bound");
+ }
+
+ InternalDownloadProgressListener internalListener =
+ mInternalDownloadProgressListeners.get(listener);
+ if (internalListener == null) {
+ throw new IllegalArgumentException("Provided listener was never registered");
+ }
+
+ try {
+ int result = downloadService.removeProgressListener(request, internalListener);
+ if (result != MbmsErrors.SUCCESS) {
+ if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
+ throw new IllegalArgumentException("Unknown download request.");
+ }
+ return result;
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ sIsInitialized.set(false);
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ }
+ } finally {
+ InternalDownloadProgressListener internalCallback =
+ mInternalDownloadProgressListeners.remove(listener);
if (internalCallback != null) {
internalCallback.stop();
}
@@ -700,9 +798,9 @@
* Requests information about the state of a file pending download.
*
* The state will be delivered as a callback via
- * {@link DownloadStateCallback#onStateUpdated(DownloadRequest, FileInfo, int)}. If no such
+ * {@link DownloadStatusListener#onStatusUpdated(DownloadRequest, FileInfo, int)}. If no such
* callback has been registered via
- * {@link #registerStateCallback(DownloadRequest, Executor, DownloadStateCallback)}, this
+ * {@link #addProgressListener(DownloadRequest, Executor, DownloadProgressListener)}, this
* method will be a no-op.
*
* If the middleware has no record of the
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 4ed6883..7db83f6 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -62,9 +62,6 @@
/**
* Listen for changes to the network signal strength (cellular).
* {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
- * <p>
*
* @see #onSignalStrengthChanged
*
@@ -77,7 +74,8 @@
* Listen for changes to the message-waiting indicator.
* {@more}
* Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
+ * READ_PHONE_STATE} or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
* <p>
* Example: The status bar uses this to determine when to display the
* voicemail icon.
@@ -90,7 +88,9 @@
* Listen for changes to the call-forwarding indicator.
* {@more}
* Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
+ * READ_PHONE_STATE} or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @see #onCallForwardingIndicatorChanged
*/
public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008;
@@ -439,8 +439,9 @@
*
* @param state call state
* @param phoneNumber call phone number. If application does not have
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission, an empty
- * string will be passed as an argument.
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission or carrier
+ * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
+ * passed as an argument.
*/
public void onCallStateChanged(@TelephonyManager.CallState int state, String phoneNumber) {
// default implementation empty
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index d2e7ae5..e971d08 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -17,8 +17,8 @@
package android.telephony;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -220,7 +220,7 @@
public static final int ROAMING_TYPE_INTERNATIONAL = 3;
/**
- * Unknown ID. Could be returned by {@link #getNetworkId()} or {@link #getSystemId()}
+ * Unknown ID. Could be returned by {@link #getCdmaNetworkId()} or {@link #getCdmaSystemId()}
*/
public static final int UNKNOWN_ID = -1;
@@ -495,9 +495,8 @@
*
* @return Current serving cell bandwidths
*/
- @Nullable
public int[] getCellBandwidths() {
- return mCellBandwidths;
+ return mCellBandwidths == null ? new int[0] : mCellBandwidths;
}
/**
@@ -1220,7 +1219,8 @@
}
/** @hide */
- public void setSystemAndNetworkId(int systemId, int networkId) {
+ @TestApi
+ public void setCdmaSystemAndNetworkId(int systemId, int networkId) {
this.mSystemId = systemId;
this.mNetworkId = networkId;
}
@@ -1386,7 +1386,7 @@
* 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() {
+ public int getCdmaNetworkId() {
return this.mNetworkId;
}
@@ -1395,7 +1395,7 @@
* system. (Defined in 3GPP2 C.S0023 3.4.8)
* @return The CDMA SID or {@link #UNKNOWN_ID} if not available.
*/
- public int getSystemId() {
+ public int getCdmaSystemId() {
return this.mSystemId;
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index b44f830..7506f4a 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.PendingIntent;
@@ -338,16 +339,17 @@
/**
* Send a text based SMS without writing it into the SMS Provider.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#SEND_SMS} and
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
- * privileges.
- * </p>
+ * <p>Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier
+ * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is
+ * the default IMS app (see
+ * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}).
*
* @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
* @hide
*/
@SystemApi
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(allOf = {
android.Manifest.permission.MODIFY_PHONE_STATE,
android.Manifest.permission.SEND_SMS
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index dac96a6..05b8b57 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -541,8 +541,6 @@
* @param listener an instance of {@link OnSubscriptionsChangedListener} with
* onSubscriptionsChanged overridden.
*/
- // TODO(b/70041899): Find a way to extend this to carrier-privileged apps.
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (DBG) {
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 4f78c4c..f1653ce 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -3165,8 +3165,8 @@
values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology());
values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology());
values.put(CSS_INDICATOR, state.getCssIndicator());
- values.put(NETWORK_ID, state.getNetworkId());
- values.put(SYSTEM_ID, state.getSystemId());
+ values.put(NETWORK_ID, state.getCdmaNetworkId());
+ values.put(SYSTEM_ID, state.getCdmaSystemId());
values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator());
values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator());
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
@@ -3296,13 +3296,13 @@
public static final String CSS_INDICATOR = "css_indicator";
/**
- * This is the same as {@link ServiceState#getNetworkId()}.
+ * This is the same as {@link ServiceState#getCdmaNetworkId()}.
* @hide
*/
public static final String NETWORK_ID = "network_id";
/**
- * This is the same as {@link ServiceState#getSystemId()}.
+ * This is the same as {@link ServiceState#getCdmaSystemId()}.
* @hide
*/
public static final String SYSTEM_ID = "system_id";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d59f19b..34e3bf4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -111,6 +111,13 @@
BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY;
/**
+ * The process name of the Phone app as well as many other apps that use this process name, such
+ * as settings and vendor components.
+ * @hide
+ */
+ public static final String PHONE_PROCESS_NAME = "com.android.phone";
+
+ /**
* The allowed states of Wi-Fi calling.
*
* @hide
@@ -1745,11 +1752,17 @@
* invalid subscription ID is pinned to the TelephonyManager, the returned config will contain
* default values.
*
+ * <p>This method may take several seconds to complete, so it should only be called from a
+ * worker thread.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @see CarrierConfigManager#getConfigForSubId(int)
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
*/
- // TODO(b/73136824, b/70041899): Permit carrier-privileged callers as well.
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@WorkerThread
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public PersistableBundle getCarrierConfig() {
@@ -5425,7 +5438,10 @@
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param request Contains all the RAT with bands/channels that need to be scanned.
- * @param executor The executor through which the callback should be invoked.
+ * @param executor The executor through which the callback should be invoked. Since the scan
+ * request may trigger multiple callbacks and they must be invoked in the same order as
+ * they are received by the platform, the user should provide an executor which executes
+ * tasks one at a time in serial order. For example AsyncTask.SERIAL_EXECUTOR.
* @param callback Returns network scan results or errors.
* @return A NetworkScan obj which contains a callback which can be used to stop the scan.
*/
@@ -5451,7 +5467,7 @@
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public NetworkScan requestNetworkScan(
NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
- return requestNetworkScan(request, AsyncTask.THREAD_POOL_EXECUTOR, callback);
+ return requestNetworkScan(request, AsyncTask.SERIAL_EXECUTOR, callback);
}
/**
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 99e2db8..96ff332 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -137,8 +137,10 @@
for (int i = 0; i < parcelables.length; i++) {
ci[i] = (CellInfo) parcelables[i];
}
- executor.execute(() ->
- callback.onResults((List<CellInfo>) Arrays.asList(ci)));
+ executor.execute(() ->{
+ Rlog.d(TAG, "onResults: " + ci.toString());
+ callback.onResults((List<CellInfo>) Arrays.asList(ci));
+ });
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onResults", e);
}
@@ -146,14 +148,20 @@
case CALLBACK_SCAN_ERROR:
try {
final int errorCode = message.arg1;
- executor.execute(() -> callback.onError(errorCode));
+ executor.execute(() -> {
+ Rlog.d(TAG, "onError: " + errorCode);
+ callback.onError(errorCode);
+ });
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onError", e);
}
break;
case CALLBACK_SCAN_COMPLETE:
try {
- executor.execute(() -> callback.onComplete());
+ executor.execute(() -> {
+ Rlog.d(TAG, "onComplete");
+ callback.onComplete();
+ });
mScanInfo.remove(message.arg2);
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onComplete", e);
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 0c17147..125161d 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -60,6 +60,7 @@
private final String mCardId;
private final @CardStateInfo int mCardStateInfo;
private final int mLogicalSlotIdx;
+ private final boolean mIsExtendedApduSupported;
public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
@Override
@@ -79,6 +80,7 @@
mCardId = in.readString();
mCardStateInfo = in.readInt();
mLogicalSlotIdx = in.readInt();
+ mIsExtendedApduSupported = in.readByte() != 0;
}
@Override
@@ -88,6 +90,7 @@
dest.writeString(mCardId);
dest.writeInt(mCardStateInfo);
dest.writeInt(mLogicalSlotIdx);
+ dest.writeByte((byte) (mIsExtendedApduSupported ? 1 : 0));
}
@Override
@@ -96,12 +99,13 @@
}
public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
- @CardStateInfo int cardStateInfo, int logicalSlotIdx) {
+ @CardStateInfo int cardStateInfo, int logicalSlotIdx, boolean isExtendedApduSupported) {
this.mIsActive = isActive;
this.mIsEuicc = isEuicc;
this.mCardId = cardId;
this.mCardStateInfo = cardStateInfo;
this.mLogicalSlotIdx = logicalSlotIdx;
+ this.mIsExtendedApduSupported = isExtendedApduSupported;
}
public boolean getIsActive() {
@@ -125,6 +129,13 @@
return mLogicalSlotIdx;
}
+ /**
+ * @return {@code true} if this slot supports extended APDU from ATR, {@code false} otherwise.
+ */
+ public boolean getIsExtendedApduSupported() {
+ return mIsExtendedApduSupported;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -139,7 +150,8 @@
&& (mIsEuicc == that.mIsEuicc)
&& (mCardId == that.mCardId)
&& (mCardStateInfo == that.mCardStateInfo)
- && (mLogicalSlotIdx == that.mLogicalSlotIdx);
+ && (mLogicalSlotIdx == that.mLogicalSlotIdx)
+ && (mIsExtendedApduSupported == that.mIsExtendedApduSupported);
}
@Override
@@ -150,6 +162,7 @@
result = 31 * result + Objects.hashCode(mCardId);
result = 31 * result + mCardStateInfo;
result = 31 * result + mLogicalSlotIdx;
+ result = 31 * result + (mIsExtendedApduSupported ? 1 : 0);
return result;
}
@@ -165,6 +178,8 @@
+ mCardStateInfo
+ ", phoneId="
+ mLogicalSlotIdx
+ + ", mIsExtendedApduSupported="
+ + mIsExtendedApduSupported
+ ")";
}
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 73a05af..145ed7e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -17,10 +17,10 @@
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.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony;
@@ -28,17 +28,15 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -46,25 +44,184 @@
*/
public class ApnSetting implements Parcelable {
- static final String LOG_TAG = "ApnSetting";
+ private static final String LOG_TAG = "ApnSetting";
private static final boolean VDBG = false;
+ private static final Map<String, Integer> APN_TYPE_STRING_MAP;
+ private static final Map<Integer, String> APN_TYPE_INT_MAP;
+ private static final Map<String, Integer> PROTOCOL_STRING_MAP;
+ private static final Map<Integer, String> PROTOCOL_INT_MAP;
+ private static final Map<String, Integer> MVNO_TYPE_STRING_MAP;
+ private static final Map<Integer, String> MVNO_TYPE_INT_MAP;
+ private static final int NOT_IN_MAP_INT = -1;
+ private static final int NO_PORT_SPECIFIED = -1;
+
+ /** All APN types except IA. */
+ private static final int TYPE_ALL_BUT_IA = ApnTypes.ALL & (~ApnTypes.IA);
+
+ /** APN type for default data traffic and HiPri traffic. */
+ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
+ /** APN type for MMS traffic. */
+ public static final int TYPE_MMS = ApnTypes.MMS;
+ /** APN type for SUPL assisted GPS. */
+ public static final int TYPE_SUPL = ApnTypes.SUPL;
+ /** APN type for DUN traffic. */
+ public static final int TYPE_DUN = ApnTypes.DUN;
+ /** APN type for HiPri traffic. */
+ public static final int TYPE_HIPRI = ApnTypes.HIPRI;
+ /** APN type for accessing the carrier's FOTA portal, used for over the air updates. */
+ public static final int TYPE_FOTA = ApnTypes.FOTA;
+ /** APN type for IMS. */
+ public static final int TYPE_IMS = ApnTypes.IMS;
+ /** APN type for CBS. */
+ public static final int TYPE_CBS = ApnTypes.CBS;
+ /** APN type for IA Initial Attach APN. */
+ public static final int TYPE_IA = ApnTypes.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 int TYPE_EMERGENCY = ApnTypes.EMERGENCY;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ 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 {}
+
+ // Possible values for authentication types.
+ /** No authentication type. */
+ public static final int AUTH_TYPE_NONE = 0;
+ /** Authentication type for PAP. */
+ public static final int AUTH_TYPE_PAP = 1;
+ /** Authentication type for CHAP. */
+ public static final int AUTH_TYPE_CHAP = 2;
+ /** Authentication type for PAP or CHAP. */
+ public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "AUTH_TYPE_" }, value = {
+ AUTH_TYPE_NONE,
+ AUTH_TYPE_PAP,
+ AUTH_TYPE_CHAP,
+ AUTH_TYPE_PAP_OR_CHAP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AuthType {}
+
+ // Possible values for protocol.
+ /** Protocol type for IP. */
+ public static final int PROTOCOL_IP = 0;
+ /** Protocol type for IPV6. */
+ public static final int PROTOCOL_IPV6 = 1;
+ /** Protocol type for IPV4V6. */
+ public static final int PROTOCOL_IPV4V6 = 2;
+ /** Protocol type for PPP. */
+ public static final int PROTOCOL_PPP = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "PROTOCOL_" }, value = {
+ PROTOCOL_IP,
+ PROTOCOL_IPV6,
+ PROTOCOL_IPV4V6,
+ PROTOCOL_PPP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProtocolType {}
+
+ // Possible values for MVNO type.
+ /** MVNO type for service provider name. */
+ public static final int MVNO_TYPE_SPN = 0;
+ /** MVNO type for IMSI. */
+ public static final int MVNO_TYPE_IMSI = 1;
+ /** MVNO type for group identifier level 1. */
+ public static final int MVNO_TYPE_GID = 2;
+ /** MVNO type for ICCID. */
+ public static final int MVNO_TYPE_ICCID = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "MVNO_TYPE_" }, value = {
+ MVNO_TYPE_SPN,
+ MVNO_TYPE_IMSI,
+ MVNO_TYPE_GID,
+ MVNO_TYPE_ICCID,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MvnoType {}
+
+ static {
+ APN_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
+ APN_TYPE_STRING_MAP.put("*", TYPE_ALL_BUT_IA);
+ APN_TYPE_STRING_MAP.put("default", TYPE_DEFAULT);
+ APN_TYPE_STRING_MAP.put("mms", TYPE_MMS);
+ APN_TYPE_STRING_MAP.put("supl", TYPE_SUPL);
+ APN_TYPE_STRING_MAP.put("dun", TYPE_DUN);
+ APN_TYPE_STRING_MAP.put("hipri", TYPE_HIPRI);
+ APN_TYPE_STRING_MAP.put("fota", TYPE_FOTA);
+ APN_TYPE_STRING_MAP.put("ims", TYPE_IMS);
+ APN_TYPE_STRING_MAP.put("cbs", TYPE_CBS);
+ APN_TYPE_STRING_MAP.put("ia", TYPE_IA);
+ APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY);
+ APN_TYPE_INT_MAP = new ArrayMap<Integer, String>();
+ APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default");
+ APN_TYPE_INT_MAP.put(TYPE_MMS, "mms");
+ APN_TYPE_INT_MAP.put(TYPE_SUPL, "supl");
+ APN_TYPE_INT_MAP.put(TYPE_DUN, "dun");
+ APN_TYPE_INT_MAP.put(TYPE_HIPRI, "hipri");
+ APN_TYPE_INT_MAP.put(TYPE_FOTA, "fota");
+ APN_TYPE_INT_MAP.put(TYPE_IMS, "ims");
+ APN_TYPE_INT_MAP.put(TYPE_CBS, "cbs");
+ APN_TYPE_INT_MAP.put(TYPE_IA, "ia");
+ APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency");
+
+ PROTOCOL_STRING_MAP = new ArrayMap<String, Integer>();
+ PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
+ PROTOCOL_STRING_MAP.put("IPV6", PROTOCOL_IPV6);
+ PROTOCOL_STRING_MAP.put("IPV4V6", PROTOCOL_IPV4V6);
+ PROTOCOL_STRING_MAP.put("PPP", PROTOCOL_PPP);
+ PROTOCOL_INT_MAP = new ArrayMap<Integer, String>();
+ PROTOCOL_INT_MAP.put(PROTOCOL_IP, "IP");
+ PROTOCOL_INT_MAP.put(PROTOCOL_IPV6, "IPV6");
+ PROTOCOL_INT_MAP.put(PROTOCOL_IPV4V6, "IPV4V6");
+ PROTOCOL_INT_MAP.put(PROTOCOL_PPP, "PPP");
+
+ MVNO_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
+ MVNO_TYPE_STRING_MAP.put("spn", MVNO_TYPE_SPN);
+ MVNO_TYPE_STRING_MAP.put("imsi", MVNO_TYPE_IMSI);
+ MVNO_TYPE_STRING_MAP.put("gid", MVNO_TYPE_GID);
+ MVNO_TYPE_STRING_MAP.put("iccid", MVNO_TYPE_ICCID);
+ MVNO_TYPE_INT_MAP = new ArrayMap<Integer, String>();
+ MVNO_TYPE_INT_MAP.put(MVNO_TYPE_SPN, "spn");
+ MVNO_TYPE_INT_MAP.put(MVNO_TYPE_IMSI, "imsi");
+ MVNO_TYPE_INT_MAP.put(MVNO_TYPE_GID, "gid");
+ MVNO_TYPE_INT_MAP.put(MVNO_TYPE_ICCID, "iccid");
+ }
+
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 InetAddress mProxyAddress;
+ private final int mProxyPort;
+ private final Uri mMmsc;
+ private final InetAddress mMmsProxyAddress;
+ private final int mMmsProxyPort;
private final String mUser;
private final String mPassword;
private final int mAuthType;
- private final List<String> mTypes;
- private final int mTypesBitmap;
+ private final int mApnTypeBitmask;
private final int mId;
private final String mOperatorNumeric;
- private final String mProtocol;
- private final String mRoamingProtocol;
+ private final int mProtocol;
+ private final int mRoamingProtocol;
private final int mMtu;
private final boolean mCarrierEnabled;
@@ -78,22 +235,12 @@
private final int mWaitTime;
private final int mMaxConnsTime;
- private final String mMvnoType;
+ private final int 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
@@ -211,8 +358,8 @@
*
* @return proxy address.
*/
- public InetAddress getProxy() {
- return mProxy;
+ public InetAddress getProxyAddress() {
+ return mProxyAddress;
}
/**
@@ -220,15 +367,15 @@
*
* @return proxy port
*/
- public int getPort() {
- return mPort;
+ public int getProxyPort() {
+ return mProxyPort;
}
/**
- * Returns the MMSC URL of the APN.
+ * Returns the MMSC Uri of the APN.
*
- * @return MMSC URL.
+ * @return MMSC Uri.
*/
- public URL getMmsc() {
+ public Uri getMmsc() {
return mMmsc;
}
@@ -237,8 +384,8 @@
*
* @return MMS proxy address.
*/
- public InetAddress getMmsProxy() {
- return mMmsProxy;
+ public InetAddress getMmsProxyAddress() {
+ return mMmsProxyAddress;
}
/**
@@ -246,8 +393,8 @@
*
* @return MMS proxy port
*/
- public int getMmsPort() {
- return mMmsPort;
+ public int getMmsProxyPort() {
+ return mMmsProxyPort;
}
/**
@@ -268,21 +415,9 @@
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
@@ -290,32 +425,20 @@
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.
+ * Returns the bitmask of APN types.
*
- * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+ * <p>Apn types 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.
*
- * @return the list of APN types
+ * <p>The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}.
+ *
+ * @see Builder#setApnTypeBitmask(int)
+ * @return a bitmask describing the types of the APN
*/
- @ApnType
- public List<String> getTypes() {
- return mTypes;
+ public @ApnType int getApnTypeBitmask() {
+ return mApnTypeBitmask;
}
/**
@@ -328,7 +451,7 @@
}
/**
- * Returns the numeric operator ID for the APN. Usually
+ * Returns the numeric operator ID for the APN. Numeric operator ID is defined as
* {@link android.provider.Telephony.Carriers#MCC} +
* {@link android.provider.Telephony.Carriers#MNC}.
*
@@ -338,37 +461,29 @@
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}.
+ * <p>Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
*
+ * @see Builder#setProtocol(int)
* @return the protocol
*/
@ProtocolType
- public String getProtocol() {
+ public int getProtocol() {
return mProtocol;
}
/**
- * Returns the protocol to use to connect to this APN when roaming.
+ * Returns the protocol to use to connect to this APN while the device is roaming.
*
- * The syntax is the same as {@link android.provider.Telephony.Carriers#PROTOCOL}.
+ * <p>Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
*
+ * @see Builder#setRoamingProtocol(int)
* @return the roaming protocol
*/
- public String getRoamingProtocol() {
+ @ProtocolType
+ public int getRoamingProtocol() {
return mRoamingProtocol;
}
@@ -398,41 +513,29 @@
return mNetworkTypeBitmask;
}
- /** @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}.
- *
+ * @see Builder#setMvnoType(int)
* @return the MVNO match type
*/
@MvnoType
- public String getMvnoType() {
+ public int getMvnoType() {
return mMvnoType;
}
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
- this.mProxy = builder.mProxy;
- this.mPort = builder.mPort;
+ this.mProxyAddress = builder.mProxyAddress;
+ this.mProxyPort = builder.mProxyPort;
this.mMmsc = builder.mMmsc;
- this.mMmsProxy = builder.mMmsProxy;
- this.mMmsPort = builder.mMmsPort;
+ this.mMmsProxyAddress = builder.mMmsProxyAddress;
+ this.mMmsProxyPort = builder.mMmsProxyPort;
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.mApnTypeBitmask = builder.mApnTypeBitmask;
this.mId = builder.mId;
this.mOperatorNumeric = builder.mOperatorNumeric;
this.mProtocol = builder.mProtocol;
@@ -451,25 +554,25 @@
/** @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,
+ String apnName, InetAddress proxy, int port, Uri mmsc, InetAddress mmsProxy,
+ int mmsPort, String user, String password, int authType, int mApnTypeBitmask,
+ int protocol, int roamingProtocol, boolean carrierEnabled,
int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
- int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
+ int waitTime, int maxConnsTime, int mtu, int mvnoType, String mvnoMatchData) {
return new Builder()
.setId(id)
.setOperatorNumeric(operatorNumeric)
.setEntryName(entryName)
.setApnName(apnName)
- .setProxy(proxy)
- .setPort(port)
+ .setProxyAddress(proxy)
+ .setProxyPort(port)
.setMmsc(mmsc)
- .setMmsProxy(mmsProxy)
- .setMmsPort(mmsPort)
+ .setMmsProxyAddress(mmsProxy)
+ .setMmsProxyPort(mmsPort)
.setUser(user)
.setPassword(password)
.setAuthType(authType)
- .setTypes(types)
+ .setApnTypeBitmask(mApnTypeBitmask)
.setProtocol(protocol)
.setRoamingProtocol(roamingProtocol)
.setCarrierEnabled(carrierEnabled)
@@ -487,7 +590,7 @@
/** @hide */
public static ApnSetting makeApnSetting(Cursor cursor) {
- String[] types = parseTypes(
+ final int apnTypesBitmask = parseTypes(
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
int networkTypeBitmask = cursor.getInt(
cursor.getColumnIndexOrThrow(Telephony.Carriers.NETWORK_TYPE_BITMASK));
@@ -507,7 +610,7 @@
cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
portFromString(cursor.getString(
cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
- URLFromString(cursor.getString(
+ UriFromString(cursor.getString(
cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
inetAddressFromString(cursor.getString(
cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
@@ -516,10 +619,12 @@
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)),
+ apnTypesBitmask,
+ nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))),
+ nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.ROAMING_PROTOCOL)))),
cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.CARRIER_ENABLED)) == 1,
networkTypeBitmask,
@@ -531,8 +636,9 @@
cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.MAX_CONNS_TIME)),
cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_TYPE)),
+ nullToNotInMapInt(MVNO_TYPE_STRING_MAP.get(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_TYPE)))),
cursor.getString(cursor.getColumnIndexOrThrow(
Telephony.Carriers.MVNO_MATCH_DATA)));
}
@@ -540,8 +646,8 @@
/** @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.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, apn.mMmsProxyPort, apn.mUser,
+ apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, apn.mProtocol, apn.mRoamingProtocol,
apn.mCarrierEnabled, apn.mNetworkTypeBitmask, apn.mProfileId,
apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu,
apn.mMvnoType, apn.mMvnoMatchData);
@@ -555,18 +661,14 @@
.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(inetAddressToString(mProxyAddress))
+ .append(", ").append(UriToString(mMmsc))
+ .append(", ").append(inetAddressToString(mMmsProxyAddress))
+ .append(", ").append(portToString(mMmsProxyPort))
+ .append(", ").append(portToString(mProxyPort))
.append(", ").append(mAuthType).append(", ");
- for (int i = 0; i < mTypes.size(); i++) {
- sb.append(mTypes.get(i));
- if (i < mTypes.size() - 1) {
- sb.append(" | ");
- }
- }
+ final String[] types = deParseTypes(mApnTypeBitmask).split(",");
+ sb.append(TextUtils.join(" | ", types)).append(", ");
sb.append(", ").append(mProtocol);
sb.append(", ").append(mRoamingProtocol);
sb.append(", ").append(mCarrierEnabled);
@@ -588,56 +690,37 @@
* @hide
*/
public boolean hasMvnoParams() {
- return !TextUtils.isEmpty(mMvnoType) && !TextUtils.isEmpty(mMvnoMatchData);
+ return (mMvnoType != NOT_IN_MAP_INT) && !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;
+ public boolean canHandleType(@ApnType int type) {
+ return mCarrierEnabled && ((mApnTypeBitmask & type) == type);
}
// 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(",");
- }
+ apnType1.append(deParseTypes(first.mApnTypeBitmask));
StringBuilder apnType2 = new StringBuilder(second.mApnName + ": ");
- for (int index1 = 0; index1 < second.mTypes.size(); index1++) {
- apnType2.append(second.mTypes.get(index1));
- apnType2.append(",");
- }
+ apnType2.append(deParseTypes(second.mApnTypeBitmask));
+
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 ((first.mApnTypeBitmask & second.mApnTypeBitmask) != 0) {
+ if (VDBG) {
+ Rlog.d(LOG_TAG, "typeSameAny: return true");
}
+ return true;
}
- if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false");
+ if (VDBG) {
+ Rlog.d(LOG_TAG, "typeSameAny: return false");
+ }
return false;
}
@@ -655,16 +738,15 @@
&& Objects.equals(mId, other.mId)
&& Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
&& Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxy, other.mProxy)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
&& Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxy, other.mMmsProxy)
- && Objects.equals(mMmsPort, other.mMmsPort)
- && Objects.equals(mPort,other.mPort)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort,other.mProxyPort)
&& 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(mApnTypeBitmask, other.mApnTypeBitmask)
&& Objects.equals(mProtocol, other.mProtocol)
&& Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -701,16 +783,15 @@
return mEntryName.equals(other.mEntryName)
&& Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
&& Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxy, other.mProxy)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
&& Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxy, other.mMmsProxy)
- && Objects.equals(mMmsPort, other.mMmsPort)
- && Objects.equals(mPort, other.mPort)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
&& 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(mApnTypeBitmask, other.mApnTypeBitmask)
&& (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
&& (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -736,17 +817,17 @@
&& !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.mProxyAddress, other.mProxyAddress)
+ && xorEqualsPort(this.mProxyPort, other.mProxyPort)
&& xorEquals(this.mProtocol, other.mProtocol)
&& xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
&& Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
&& 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))
+ && xorEquals(this.mMmsc, other.mMmsc)
+ && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+ && xorEqualsPort(this.mMmsProxyPort, other.mMmsProxyPort))
&& Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask);
}
@@ -757,42 +838,23 @@
|| 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) {
+ // Equal or one is not null.
+ private boolean xorEquals(Object first, Object 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);
+ return first == NO_PORT_SPECIFIED || second == NO_PORT_SPECIFIED
+ || 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;
+ private String deParseTypes(int apnTypeBitmask) {
+ List<String> types = new ArrayList<>();
+ for (Integer type : APN_TYPE_INT_MAP.keySet()) {
+ if ((apnTypeBitmask & type) == type) {
+ types.add(APN_TYPE_INT_MAP.get(type));
+ }
}
return TextUtils.join(",", types);
}
@@ -808,21 +870,25 @@
apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
- apnValue.put(Telephony.Carriers.PROXY, mProxy == null ? "" : inetAddressToString(mProxy));
- apnValue.put(Telephony.Carriers.PORT, portToString(mPort));
- apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : URLToString(mMmsc));
- apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort));
- apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxy == null
- ? "" : inetAddressToString(mMmsProxy));
+ apnValue.put(Telephony.Carriers.PROXY, mProxyAddress == null ? ""
+ : inetAddressToString(mProxyAddress));
+ apnValue.put(Telephony.Carriers.PORT, portToString(mProxyPort));
+ apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : UriToString(mMmsc));
+ apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsProxyPort));
+ apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxyAddress == null
+ ? "" : inetAddressToString(mMmsProxyAddress));
apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser));
apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword));
apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
- String apnType = deParseTypes(mTypes);
+ String apnType = deParseTypes(mApnTypeBitmask);
apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType));
- apnValue.put(Telephony.Carriers.PROTOCOL, nullToEmpty(mProtocol));
- apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, nullToEmpty(mRoamingProtocol));
+ apnValue.put(Telephony.Carriers.PROTOCOL,
+ nullToEmpty(PROTOCOL_INT_MAP.get(mProtocol)));
+ apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL,
+ nullToEmpty(PROTOCOL_INT_MAP.get(mRoamingProtocol)));
apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
- apnValue.put(Telephony.Carriers.MVNO_TYPE, nullToEmpty(mMvnoType));
+ apnValue.put(Telephony.Carriers.MVNO_TYPE,
+ nullToEmpty(MVNO_TYPE_INT_MAP.get(mMvnoType)));
apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
return apnValue;
@@ -830,32 +896,31 @@
/**
* @param types comma delimited list of APN types
- * @return array of APN types
+ * @return bitmask of APN types
* @hide
*/
- public static String[] parseTypes(String types) {
- String[] result;
- // If unset, set to DEFAULT.
+ public static int parseTypes(String types) {
+ // If unset, set to ALL.
if (TextUtils.isEmpty(types)) {
- result = new String[1];
- result[0] = TYPE_ALL;
+ return TYPE_ALL_BUT_IA;
} 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;
+ int result = 0;
+ for (String str : types.split(",")) {
+ Integer type = APN_TYPE_STRING_MAP.get(str);
+ if (type != null) {
+ result |= type;
+ }
+ }
+ return result;
}
}
- private static String URLToString(URL url) {
- return url == null ? "" : url.toString();
+ private static Uri UriFromString(String uri) {
+ return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
+ }
+
+ private static String UriToString(Uri uri) {
+ return uri == null ? "" : uri.toString();
}
private static InetAddress inetAddressFromString(String inetAddress) {
@@ -887,7 +952,7 @@
}
private static int portFromString(String strPort) {
- int port = -1;
+ int port = NO_PORT_SPECIFIED;
if (!TextUtils.isEmpty(strPort)) {
try {
port = Integer.parseInt(strPort);
@@ -899,7 +964,7 @@
}
private static String portToString(int port) {
- return port == -1 ? "" : Integer.toString(port);
+ return port == NO_PORT_SPECIFIED ? "" : Integer.toString(port);
}
// Implement Parcelable.
@@ -916,19 +981,19 @@
dest.writeString(mOperatorNumeric);
dest.writeString(mEntryName);
dest.writeString(mApnName);
- dest.writeValue(mProxy);
- dest.writeInt(mPort);
+ dest.writeValue(mProxyAddress);
+ dest.writeInt(mProxyPort);
dest.writeValue(mMmsc);
- dest.writeValue(mMmsProxy);
- dest.writeInt(mMmsPort);
+ dest.writeValue(mMmsProxyAddress);
+ dest.writeInt(mMmsProxyPort);
dest.writeString(mUser);
dest.writeString(mPassword);
dest.writeInt(mAuthType);
- dest.writeStringArray(mTypes.toArray(new String[0]));
- dest.writeString(mProtocol);
- dest.writeString(mRoamingProtocol);
+ dest.writeInt(mApnTypeBitmask);
+ dest.writeInt(mProtocol);
+ dest.writeInt(mRoamingProtocol);
dest.writeInt(mCarrierEnabled ? 1: 0);
- dest.writeString(mMvnoType);
+ dest.writeInt(mMvnoType);
dest.writeInt(mNetworkTypeBitmask);
}
@@ -939,23 +1004,23 @@
final String apnName = in.readString();
final InetAddress proxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
final int port = in.readInt();
- final URL mmsc = (URL)in.readValue(URL.class.getClassLoader());
+ final Uri mmsc = (Uri)in.readValue(Uri.class.getClassLoader());
final InetAddress mmsProxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
final int mmsPort = in.readInt();
final String user = in.readString();
final String password = in.readString();
final int authType = in.readInt();
- final List<String> types = Arrays.asList(in.readStringArray());
- final String protocol = in.readString();
- final String roamingProtocol = in.readString();
+ final int apnTypesBitmask = in.readInt();
+ final int protocol = in.readInt();
+ final int roamingProtocol = in.readInt();
final boolean carrierEnabled = in.readInt() > 0;
- final String mvnoType = in.readString();
+ final int mvnoType = in.readInt();
final int networkTypeBitmask = in.readInt();
return makeApnSetting(id, operatorNumeric, entryName, apnName,
- proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, types, protocol,
- roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
- 0, 0, 0, 0, mvnoType, null);
+ proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask,
+ protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
+ 0, 0, 0, 0, mvnoType, null);
}
public static final Parcelable.Creator<ApnSetting> CREATOR =
@@ -971,89 +1036,26 @@
}
};
- /**
- * 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";
+ private static int nullToNotInMapInt(Integer value) {
+ return value == null ? NOT_IN_MAP_INT : value;
+ }
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 InetAddress mProxyAddress;
+ private int mProxyPort = NO_PORT_SPECIFIED;
+ private Uri mMmsc;
+ private InetAddress mMmsProxyAddress;
+ private int mMmsProxyPort = NO_PORT_SPECIFIED;
private String mUser;
private String mPassword;
private int mAuthType;
- private List<String> mTypes;
- private int mTypesBitmap;
+ private int mApnTypeBitmask;
private int mId;
private String mOperatorNumeric;
- private String mProtocol;
- private String mRoamingProtocol;
+ private int mProtocol = NOT_IN_MAP_INT;
+ private int mRoamingProtocol = NOT_IN_MAP_INT;
private int mMtu;
private int mNetworkTypeBitmask;
private boolean mCarrierEnabled;
@@ -1062,7 +1064,7 @@
private int mMaxConns;
private int mWaitTime;
private int mMaxConnsTime;
- private String mMvnoType;
+ private int mMvnoType = NOT_IN_MAP_INT;
private String mMvnoMatchData;
/**
@@ -1182,8 +1184,8 @@
*
* @param proxy the proxy address to set for the APN
*/
- public Builder setProxy(InetAddress proxy) {
- this.mProxy = proxy;
+ public Builder setProxyAddress(InetAddress proxy) {
+ this.mProxyAddress = proxy;
return this;
}
@@ -1192,17 +1194,17 @@
*
* @param port the proxy port to set for the APN
*/
- public Builder setPort(int port) {
- this.mPort = port;
+ public Builder setProxyPort(int port) {
+ this.mProxyPort = port;
return this;
}
/**
- * Sets the MMSC URL of the APN.
+ * Sets the MMSC Uri of the APN.
*
- * @param mmsc the MMSC URL to set for the APN
+ * @param mmsc the MMSC Uri to set for the APN
*/
- public Builder setMmsc(URL mmsc) {
+ public Builder setMmsc(Uri mmsc) {
this.mMmsc = mmsc;
return this;
}
@@ -1212,8 +1214,8 @@
*
* @param mmsProxy the MMS proxy address to set for the APN
*/
- public Builder setMmsProxy(InetAddress mmsProxy) {
- this.mMmsProxy = mmsProxy;
+ public Builder setMmsProxyAddress(InetAddress mmsProxy) {
+ this.mMmsProxyAddress = mmsProxy;
return this;
}
@@ -1222,8 +1224,8 @@
*
* @param mmsPort the MMS proxy port to set for the APN
*/
- public Builder setMmsPort(int mmsPort) {
- this.mMmsPort = mmsPort;
+ public Builder setMmsProxyPort(int mmsPort) {
+ this.mMmsProxyPort = mmsPort;
return this;
}
@@ -1251,8 +1253,6 @@
/**
* 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) {
@@ -1261,25 +1261,25 @@
}
/**
- * Sets the list of APN types of the APN.
+ * Sets the bitmask of APN types.
*
- * Example of possible values: {@link #TYPE_DEFAULT}, {@link #TYPE_MMS}.
+ * <p>Apn types 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.
*
- * @param types the list of APN types to set for the APN
+ * <p>The bitmask of APN types is calculated from APN types defined in {@link ApnSetting}.
+ *
+ * @param apnTypeBitmask a bitmask describing the types of 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;
+ public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) {
+ this.mApnTypeBitmask = apnTypeBitmask;
return this;
}
/**
- * Set the numeric operator ID for the APN.
+ * Sets the numeric operator ID for the APN. Numeric operator ID is defined as
+ * {@link android.provider.Telephony.Carriers#MCC} +
+ * {@link android.provider.Telephony.Carriers#MNC}.
*
* @param operatorNumeric the numeric operator ID to set for this entry
*/
@@ -1291,22 +1291,23 @@
/**
* 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}.
+ * <p>Protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
*
* @param protocol the protocol to set to use to connect to this APN
*/
- public Builder setProtocol(@ProtocolType String protocol) {
+ public Builder setProtocol(@ProtocolType int protocol) {
this.mProtocol = protocol;
return this;
}
/**
- * Sets the protocol to use to connect to this APN when roaming.
+ * Sets the protocol to use to connect to this APN when the device is roaming.
+ *
+ * <p>Roaming protocol is one of the {@code PDP_type} values in TS 27.007 section 10.1.1.
*
* @param roamingProtocol the protocol to set to use to connect to this APN when roaming
*/
- public Builder setRoamingProtocol(String roamingProtocol) {
+ public Builder setRoamingProtocol(@ProtocolType int roamingProtocol) {
this.mRoamingProtocol = roamingProtocol;
return this;
}
@@ -1334,16 +1335,25 @@
/**
* 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) {
+ public Builder setMvnoType(@MvnoType int mvnoType) {
this.mMvnoType = mvnoType;
return this;
}
+ /**
+ * Builds {@link ApnSetting} from this builder.
+ *
+ * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
+ * is empty, or {@link #setApnTypeBitmask(int)} doesn't contain a valid bit,
+ * {@link ApnSetting} built from this builder otherwise.
+ */
public ApnSetting build() {
+ if ((mApnTypeBitmask & ApnTypes.ALL) == 0 || TextUtils.isEmpty(mApnName)
+ || TextUtils.isEmpty(mEntryName)) {
+ return null;
+ }
return new ApnSetting(this);
}
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 71ef5de..8279123 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -15,11 +15,12 @@
*/
package android.telephony.euicc;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
@@ -73,6 +74,7 @@
*/
@SystemApi
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public static final String ACTION_OTA_STATUS_CHANGED =
"android.telephony.euicc.action.OTA_STATUS_CHANGED";
@@ -301,6 +303,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public int getOtaStatus() {
if (!isEnabled()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
@@ -325,6 +328,7 @@
* @param switchAfterDownload if true, the profile will be activated upon successful download.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void downloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -387,6 +391,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
if (!isEnabled()) {
PendingIntent callbackIntent =
@@ -422,6 +427,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -452,6 +458,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -496,6 +503,7 @@
* @param subscriptionId the ID of the subscription to delete.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -523,6 +531,7 @@
* current profile without activating another profile to replace it.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -548,6 +557,7 @@
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
int subscriptionId, String nickname, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -566,12 +576,13 @@
* Erase all subscriptions and reset the eUICC.
*
* <p>Requires that the calling app has the
- * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
- * internal system use only.
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void eraseSubscriptions(PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index c073d1a..aaf1a1cf8 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -139,34 +139,44 @@
@Override
public int queryCapabilityStatus() throws RemoteException {
- return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+ synchronized (mLock) {
+ return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+ }
}
@Override
public void addCapabilityCallback(IImsCapabilityCallback c) {
+ // no need to lock, structure already handles multithreading.
MmTelFeature.this.addCapabilityCallback(c);
}
@Override
public void removeCapabilityCallback(IImsCapabilityCallback c) {
+ // no need to lock, structure already handles multithreading.
MmTelFeature.this.removeCapabilityCallback(c);
}
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
IImsCapabilityCallback c) throws RemoteException {
- MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+ synchronized (mLock) {
+ MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+ }
}
@Override
public void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c) {
- queryCapabilityConfigurationInternal(capability, radioTech, c);
+ synchronized (mLock) {
+ queryCapabilityConfigurationInternal(capability, radioTech, c);
+ }
}
@Override
public void setSmsListener(IImsSmsListener l) throws RemoteException {
- MmTelFeature.this.setSmsListener(l);
+ synchronized (mLock) {
+ MmTelFeature.this.setSmsListener(l);
+ }
}
@Override
diff --git a/telephony/java/android/telephony/mbms/DownloadProgressListener.java b/telephony/java/android/telephony/mbms/DownloadProgressListener.java
new file mode 100644
index 0000000..4301cb1
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadProgressListener.java
@@ -0,0 +1,48 @@
+/*
+ * 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.mbms;
+
+import android.telephony.MbmsDownloadSession;
+
+/**
+ * A optional listener class used by download clients to track progress. Apps should extend this
+ * class and pass an instance into
+ * {@link MbmsDownloadSession#download(DownloadRequest)}
+ *
+ * This is optionally specified when requesting a download and will only be called while the app
+ * is running.
+ */
+public class DownloadProgressListener {
+ /**
+ * Called when the middleware wants to report progress for a file in a {@link DownloadRequest}.
+ *
+ * @param request a {@link DownloadRequest}, indicating which download is being referenced.
+ * @param fileInfo a {@link FileInfo} specifying the file to report progress on. Note that
+ * the request may result in many files being downloaded and the client
+ * may not have been able to get a list of them in advance.
+ * @param currentDownloadSize is the current amount downloaded.
+ * @param fullDownloadSize is the total number of bytes that make up the downloaded content.
+ * This may be different from the decoded final size, but is useful in gauging download
+ * progress.
+ * @param currentDecodedSize is the number of bytes that have been decoded.
+ * @param fullDecodedSize is the total number of bytes that make up the final decoded content.
+ */
+ public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo,
+ int currentDownloadSize, int fullDownloadSize,
+ int currentDecodedSize, int fullDecodedSize) {
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/DownloadStateCallback.java b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
deleted file mode 100644
index 9f60cc3..0000000
--- a/telephony/java/android/telephony/mbms/DownloadStateCallback.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.mbms;
-
-import android.annotation.IntDef;
-import android.telephony.MbmsDownloadSession;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A optional listener class used by download clients to track progress. Apps should extend this
- * class and pass an instance into
- * {@link MbmsDownloadSession#download(DownloadRequest)}
- *
- * This is optionally specified when requesting a download and will only be called while the app
- * is running.
- */
-public class DownloadStateCallback {
-
- /**
- * Bitmask flags used for filtering out callback methods. Used when constructing the
- * DownloadStateCallback as an optional parameter.
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
- public @interface FilterFlag {}
-
- /**
- * Receive all callbacks.
- * Default value.
- */
- public static final int ALL_UPDATES = 0x00;
- /**
- * Receive callbacks for {@link #onProgressUpdated}.
- */
- public static final int PROGRESS_UPDATES = 0x01;
- /**
- * Receive callbacks for {@link #onStateUpdated}.
- */
- public static final int STATE_UPDATES = 0x02;
-
- private final int mCallbackFilterFlags;
-
- /**
- * Creates a DownloadStateCallback that will receive all callbacks.
- */
- public DownloadStateCallback() {
- mCallbackFilterFlags = ALL_UPDATES;
- }
-
- /**
- * Creates a DownloadStateCallback that will only receive callbacks for the methods specified
- * via the filterFlags parameter.
- * @param filterFlags A bitmask of filter flags that will specify which callback this instance
- * is interested in.
- */
- public DownloadStateCallback(int filterFlags) {
- mCallbackFilterFlags = filterFlags;
- }
-
- /**
- * Return the currently set filter flags.
- * @return An integer containing the bitmask of flags that this instance is interested in.
- * @hide
- */
- public int getCallbackFilterFlags() {
- return mCallbackFilterFlags;
- }
-
- /**
- * Returns true if a filter flag is set for a particular callback method. If the flag is set,
- * the callback will be delivered to the listening process.
- * @param flag A filter flag specifying whether or not a callback method is registered to
- * receive callbacks.
- * @return true if registered to receive callbacks in the listening process, false if not.
- */
- public final boolean isFilterFlagSet(@FilterFlag int flag) {
- if (mCallbackFilterFlags == ALL_UPDATES) {
- return true;
- }
- return (mCallbackFilterFlags & flag) > 0;
- }
-
- /**
- * Called when the middleware wants to report progress for a file in a {@link DownloadRequest}.
- *
- * @param request a {@link DownloadRequest}, indicating which download is being referenced.
- * @param fileInfo a {@link FileInfo} specifying the file to report progress on. Note that
- * the request may result in many files being downloaded and the client
- * may not have been able to get a list of them in advance.
- * @param currentDownloadSize is the current amount downloaded.
- * @param fullDownloadSize is the total number of bytes that make up the downloaded content.
- * This may be different from the decoded final size, but is useful in gauging download
- * progress.
- * @param currentDecodedSize is the number of bytes that have been decoded.
- * @param fullDecodedSize is the total number of bytes that make up the final decoded content.
- */
- public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo,
- int currentDownloadSize, int fullDownloadSize,
- int currentDecodedSize, int fullDecodedSize) {
- }
-
- /**
- * Gives download state callbacks for a file in a {@link DownloadRequest}.
- *
- * @param request a {@link DownloadRequest}, indicating which download is being referenced.
- * @param fileInfo a {@link FileInfo} specifying the file to report progress on. Note that
- * the request may result in many files being downloaded and the client
- * may not have been able to get a list of them in advance.
- * @param state The current state of the download.
- */
- public void onStateUpdated(DownloadRequest request, FileInfo fileInfo,
- @MbmsDownloadSession.DownloadStatus int state) {
- }
-}
diff --git a/telephony/java/android/telephony/mbms/DownloadStatusListener.java b/telephony/java/android/telephony/mbms/DownloadStatusListener.java
new file mode 100644
index 0000000..ca77932
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadStatusListener.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.telephony.MbmsDownloadSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A optional listener class used by download clients to track progress. Apps should extend this
+ * class and pass an instance into
+ * {@link MbmsDownloadSession#download(DownloadRequest)}
+ *
+ * This is optionally specified when requesting a download and will only be called while the app
+ * is running.
+ */
+public class DownloadStatusListener {
+ /**
+ * Gives download status callbacks for a file in a {@link DownloadRequest}.
+ *
+ * @param request a {@link DownloadRequest}, indicating which download is being referenced.
+ * @param fileInfo a {@link FileInfo} specifying the file to report progress on. Note that
+ * the request may result in many files being downloaded and the client
+ * may not have been able to get a list of them in advance.
+ * @param status The current status of the download.
+ */
+ public void onStatusUpdated(DownloadRequest request, FileInfo fileInfo,
+ @MbmsDownloadSession.DownloadStatus int status) {
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl b/telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl
similarity index 90%
rename from telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl
rename to telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl
index cebc70d..d0adcb5 100755
--- a/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl
@@ -23,7 +23,7 @@
* The optional interface used by download clients to track progress.
* @hide
*/
-interface IDownloadStateCallback
+interface IDownloadProgressListener
{
/**
* Gives progress callbacks for a given DownloadRequest. Includes a FileInfo
@@ -32,6 +32,4 @@
void onProgressUpdated(in DownloadRequest request, in FileInfo fileInfo,
int currentDownloadSize, int fullDownloadSize,
int currentDecodedSize, int fullDecodedSize);
-
- void onStateUpdated(in DownloadRequest request, in FileInfo fileInfo, int state);
}
diff --git a/telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl b/telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl
new file mode 100755
index 0000000..799290a
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl
@@ -0,0 +1,29 @@
+/*
+** 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.mbms;
+
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.FileInfo;
+
+/**
+ * The optional interface used by download clients to track download status.
+ * @hide
+ */
+interface IDownloadStatusListener
+{
+ void onStatusUpdated(in DownloadRequest request, in FileInfo fileInfo, int status);
+}
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
similarity index 62%
rename from telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java
rename to telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
index f30ae27..403f758 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -24,13 +24,14 @@
/**
* @hide
*/
-public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub {
+public class InternalDownloadProgressListener extends IDownloadProgressListener.Stub {
private final Executor mExecutor;
- private final DownloadStateCallback mAppCallback;
+ private final DownloadProgressListener mAppListener;
private volatile boolean mIsStopped = false;
- public InternalDownloadStateCallback(DownloadStateCallback appCallback, Executor executor) {
- mAppCallback = appCallback;
+ public InternalDownloadProgressListener(DownloadProgressListener appListener,
+ Executor executor) {
+ mAppListener = appListener;
mExecutor = executor;
}
@@ -47,7 +48,7 @@
public void run() {
long token = Binder.clearCallingIdentity();
try {
- mAppCallback.onProgressUpdated(request, fileInfo, currentDownloadSize,
+ mAppListener.onProgressUpdated(request, fileInfo, currentDownloadSize,
fullDownloadSize, currentDecodedSize, fullDecodedSize);
} finally {
Binder.restoreCallingIdentity(token);
@@ -56,26 +57,6 @@
});
}
- @Override
- public void onStateUpdated(final DownloadRequest request, final FileInfo fileInfo,
- final int state) throws RemoteException {
- if (mIsStopped) {
- return;
- }
-
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- long token = Binder.clearCallingIdentity();
- try {
- mAppCallback.onStateUpdated(request, fileInfo, state);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- });
- }
-
public void stop() {
mIsStopped = true;
}
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java b/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java
new file mode 100644
index 0000000..ad6bb54
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony.mbms;
+
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telephony.MbmsDownloadSession;
+
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class InternalDownloadStatusListener extends IDownloadStatusListener.Stub {
+ private final Executor mExecutor;
+ private final DownloadStatusListener mAppListener;
+ private volatile boolean mIsStopped = false;
+
+ public InternalDownloadStatusListener(DownloadStatusListener appCallback, Executor executor) {
+ mAppListener = appCallback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onStatusUpdated(final DownloadRequest request, final FileInfo fileInfo,
+ @MbmsDownloadSession.DownloadStatus final int status) throws RemoteException {
+ if (mIsStopped) {
+ return;
+ }
+
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppListener.onStatusUpdated(request, fileInfo, status);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+
+ public void stop() {
+ mIsStopped = true;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index 7d9845f..445087fb 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -20,8 +20,9 @@
import android.net.Uri;
import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.FileInfo;
+import android.telephony.mbms.IDownloadProgressListener;
+import android.telephony.mbms.IDownloadStatusListener;
import android.telephony.mbms.IMbmsDownloadSessionCallback;
-import android.telephony.mbms.IDownloadStateCallback;
/**
* @hide
@@ -36,11 +37,17 @@
int download(in DownloadRequest downloadRequest);
- int registerStateCallback(in DownloadRequest downloadRequest, IDownloadStateCallback listener,
- int flags);
+ int addStatusListener(in DownloadRequest downloadRequest,
+ IDownloadStatusListener listener);
- int unregisterStateCallback(in DownloadRequest downloadRequest,
- IDownloadStateCallback listener);
+ int removeStatusListener(in DownloadRequest downloadRequest,
+ IDownloadStatusListener listener);
+
+ int addProgressListener(in DownloadRequest downloadRequest,
+ IDownloadProgressListener listener);
+
+ int removeProgressListener(in DownloadRequest downloadRequest,
+ IDownloadProgressListener listener);
List<DownloadRequest> listPendingDownloads(int subscriptionId);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 86b1b7a..f9d7161 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -24,11 +24,13 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.MbmsDownloadSession;
+import android.telephony.mbms.DownloadProgressListener;
import android.telephony.mbms.DownloadRequest;
-import android.telephony.mbms.DownloadStateCallback;
+import android.telephony.mbms.DownloadStatusListener;
import android.telephony.mbms.FileInfo;
import android.telephony.mbms.FileServiceInfo;
-import android.telephony.mbms.IDownloadStateCallback;
+import android.telephony.mbms.IDownloadProgressListener;
+import android.telephony.mbms.IDownloadStatusListener;
import android.telephony.mbms.IMbmsDownloadSessionCallback;
import android.telephony.mbms.MbmsDownloadSessionCallback;
import android.telephony.mbms.MbmsErrors;
@@ -45,47 +47,50 @@
@SystemApi
@TestApi
public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
- private final Map<IBinder, DownloadStateCallback> mDownloadCallbackBinderMap = new HashMap<>();
+ private final Map<IBinder, DownloadStatusListener> mDownloadStatusListenerBinderMap =
+ new HashMap<>();
+ private final Map<IBinder, DownloadProgressListener> mDownloadProgressListenerBinderMap =
+ new HashMap<>();
private final Map<IBinder, DeathRecipient> mDownloadCallbackDeathRecipients = new HashMap<>();
+ private abstract static class VendorDownloadStatusListener extends DownloadStatusListener {
+ private final IDownloadStatusListener mListener;
+ public VendorDownloadStatusListener(IDownloadStatusListener listener) {
+ mListener = listener;
+ }
- // Filters the DownloadStateCallbacks by its configuration from the app.
- private abstract static class FilteredDownloadStateCallback extends DownloadStateCallback {
+ @Override
+ public void onStatusUpdated(DownloadRequest request, FileInfo fileInfo,
+ @MbmsDownloadSession.DownloadStatus int state) {
+ try {
+ mListener.onStatusUpdated(request, fileInfo, state);
+ } catch (RemoteException e) {
+ onRemoteException(e);
+ }
+ }
- private final IDownloadStateCallback mCallback;
- public FilteredDownloadStateCallback(IDownloadStateCallback callback, int callbackFlags) {
- super(callbackFlags);
- mCallback = callback;
+ protected abstract void onRemoteException(RemoteException e);
+ }
+
+ private abstract static class VendorDownloadProgressListener extends DownloadProgressListener {
+ private final IDownloadProgressListener mListener;
+
+ public VendorDownloadProgressListener(IDownloadProgressListener listener) {
+ mListener = listener;
}
@Override
public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo,
int currentDownloadSize, int fullDownloadSize, int currentDecodedSize,
int fullDecodedSize) {
- if (!isFilterFlagSet(PROGRESS_UPDATES)) {
- return;
- }
try {
- mCallback.onProgressUpdated(request, fileInfo, currentDownloadSize,
+ mListener.onProgressUpdated(request, fileInfo, currentDownloadSize,
fullDownloadSize, currentDecodedSize, fullDecodedSize);
} catch (RemoteException e) {
onRemoteException(e);
}
}
- @Override
- public void onStateUpdated(DownloadRequest request, FileInfo fileInfo,
- @MbmsDownloadSession.DownloadStatus int state) {
- if (!isFilterFlagSet(STATE_UPDATES)) {
- return;
- }
- try {
- mCallback.onStateUpdated(request, fileInfo, state);
- } catch (RemoteException e) {
- onRemoteException(e);
- }
- }
-
protected abstract void onRemoteException(RemoteException e);
}
@@ -223,71 +228,70 @@
}
/**
- * Registers a download state callbacks for the provided {@link DownloadRequest}.
+ * Registers a download status listener for the provided {@link DownloadRequest}.
*
- * This method is called by the app when it wants to request updates on the progress or
- * status of the download.
+ * This method is called by the app when it wants to request updates on the status of
+ * the download.
*
* If the middleware is not aware of a download having been requested with the provided
- *
* {@link DownloadRequest} in the past,
* {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}
* must be returned.
*
* @param downloadRequest The {@link DownloadRequest} that was used to initiate the download
* for which progress updates are being requested.
- * @param callback The callback object to use.
+ * @param listener The listener object to use.
*/
- public int registerStateCallback(DownloadRequest downloadRequest,
- DownloadStateCallback callback) throws RemoteException {
+ public int addStatusListener(DownloadRequest downloadRequest,
+ DownloadStatusListener listener) throws RemoteException {
return 0;
}
/**
- * Actual AIDL implementation -- hides the callback AIDL from the API.
+ * Actual AIDL implementation -- hides the listener AIDL from the API.
* @hide
*/
@Override
- public final int registerStateCallback(final DownloadRequest downloadRequest,
- final IDownloadStateCallback callback, int flags) throws RemoteException {
+ public final int addStatusListener(final DownloadRequest downloadRequest,
+ final IDownloadStatusListener listener) throws RemoteException {
final int uid = Binder.getCallingUid();
if (downloadRequest == null) {
throw new NullPointerException("Download request must not be null");
}
- if (callback == null) {
+ if (listener == null) {
throw new NullPointerException("Callback must not be null");
}
- DownloadStateCallback exposedCallback = new FilteredDownloadStateCallback(callback, flags) {
+ DownloadStatusListener exposedCallback = new VendorDownloadStatusListener(listener) {
@Override
protected void onRemoteException(RemoteException e) {
onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
}
};
- int result = registerStateCallback(downloadRequest, exposedCallback);
+ int result = addStatusListener(downloadRequest, exposedCallback);
if (result == MbmsErrors.SUCCESS) {
DeathRecipient deathRecipient = new DeathRecipient() {
@Override
public void binderDied() {
onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
- mDownloadCallbackBinderMap.remove(callback.asBinder());
- mDownloadCallbackDeathRecipients.remove(callback.asBinder());
+ mDownloadStatusListenerBinderMap.remove(listener.asBinder());
+ mDownloadCallbackDeathRecipients.remove(listener.asBinder());
}
};
- mDownloadCallbackDeathRecipients.put(callback.asBinder(), deathRecipient);
- callback.asBinder().linkToDeath(deathRecipient, 0);
- mDownloadCallbackBinderMap.put(callback.asBinder(), exposedCallback);
+ mDownloadCallbackDeathRecipients.put(listener.asBinder(), deathRecipient);
+ listener.asBinder().linkToDeath(deathRecipient, 0);
+ mDownloadStatusListenerBinderMap.put(listener.asBinder(), exposedCallback);
}
return result;
}
/**
- * Un-registers a download state callbacks for the provided {@link DownloadRequest}.
+ * Un-registers a download status listener for the provided {@link DownloadRequest}.
*
- * This method is called by the app when it no longer wants to request updates on the
+ * This method is called by the app when it no longer wants to request status updates on the
* download.
*
* If the middleware is not aware of a download having been requested with the provided
@@ -296,45 +300,157 @@
* must be returned.
*
* @param downloadRequest The {@link DownloadRequest} that was used to register the callback
- * @param callback The callback object that
- * {@link #registerStateCallback(DownloadRequest, DownloadStateCallback)}
+ * @param listener The callback object that
+ * {@link #addStatusListener(DownloadRequest, DownloadStatusListener)}
* was called with.
*/
- public int unregisterStateCallback(DownloadRequest downloadRequest,
- DownloadStateCallback callback) throws RemoteException {
+ public int removeStatusListener(DownloadRequest downloadRequest,
+ DownloadStatusListener listener) throws RemoteException {
return 0;
}
/**
- * Actual AIDL implementation -- hides the callback AIDL from the API.
+ * Actual AIDL implementation -- hides the listener AIDL from the API.
* @hide
*/
- @Override
- public final int unregisterStateCallback(
- final DownloadRequest downloadRequest, final IDownloadStateCallback callback)
+ public final int removeStatusListener(
+ final DownloadRequest downloadRequest, final IDownloadStatusListener listener)
throws RemoteException {
if (downloadRequest == null) {
throw new NullPointerException("Download request must not be null");
}
- if (callback == null) {
+ if (listener == null) {
throw new NullPointerException("Callback must not be null");
}
DeathRecipient deathRecipient =
- mDownloadCallbackDeathRecipients.remove(callback.asBinder());
+ mDownloadCallbackDeathRecipients.remove(listener.asBinder());
if (deathRecipient == null) {
- throw new IllegalArgumentException("Unknown callback");
+ throw new IllegalArgumentException("Unknown listener");
}
- callback.asBinder().unlinkToDeath(deathRecipient, 0);
+ listener.asBinder().unlinkToDeath(deathRecipient, 0);
- DownloadStateCallback exposedCallback =
- mDownloadCallbackBinderMap.remove(callback.asBinder());
+ DownloadStatusListener exposedCallback =
+ mDownloadStatusListenerBinderMap.remove(listener.asBinder());
if (exposedCallback == null) {
- throw new IllegalArgumentException("Unknown callback");
+ throw new IllegalArgumentException("Unknown listener");
}
- return unregisterStateCallback(downloadRequest, exposedCallback);
+ return removeStatusListener(downloadRequest, exposedCallback);
+ }
+
+ /**
+ * Registers a download progress listener for the provided {@link DownloadRequest}.
+ *
+ * This method is called by the app when it wants to request updates on the progress of
+ * the download.
+ *
+ * If the middleware is not aware of a download having been requested with the provided
+ * {@link DownloadRequest} in the past,
+ * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}
+ * must be returned.
+ *
+ * @param downloadRequest The {@link DownloadRequest} that was used to initiate the download
+ * for which progress updates are being requested.
+ * @param listener The listener object to use.
+ */
+ public int addProgressListener(DownloadRequest downloadRequest,
+ DownloadProgressListener listener) throws RemoteException {
+ return 0;
+ }
+
+ /**
+ * Actual AIDL implementation -- hides the listener AIDL from the API.
+ * @hide
+ */
+ @Override
+ public final int addProgressListener(final DownloadRequest downloadRequest,
+ final IDownloadProgressListener listener) throws RemoteException {
+ final int uid = Binder.getCallingUid();
+ if (downloadRequest == null) {
+ throw new NullPointerException("Download request must not be null");
+ }
+ if (listener == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
+ DownloadProgressListener exposedCallback = new VendorDownloadProgressListener(listener) {
+ @Override
+ protected void onRemoteException(RemoteException e) {
+ onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
+ }
+ };
+
+ int result = addProgressListener(downloadRequest, exposedCallback);
+
+ if (result == MbmsErrors.SUCCESS) {
+ DeathRecipient deathRecipient = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ onAppCallbackDied(uid, downloadRequest.getSubscriptionId());
+ mDownloadProgressListenerBinderMap.remove(listener.asBinder());
+ mDownloadCallbackDeathRecipients.remove(listener.asBinder());
+ }
+ };
+ mDownloadCallbackDeathRecipients.put(listener.asBinder(), deathRecipient);
+ listener.asBinder().linkToDeath(deathRecipient, 0);
+ mDownloadProgressListenerBinderMap.put(listener.asBinder(), exposedCallback);
+ }
+
+ return result;
+ }
+
+ /**
+ * Un-registers a download progress listener for the provided {@link DownloadRequest}.
+ *
+ * This method is called by the app when it no longer wants to request progress updates on the
+ * download.
+ *
+ * If the middleware is not aware of a download having been requested with the provided
+ * {@link DownloadRequest} in the past,
+ * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}
+ * must be returned.
+ *
+ * @param downloadRequest The {@link DownloadRequest} that was used to register the callback
+ * @param listener The callback object that
+ * {@link #addProgressListener(DownloadRequest, DownloadProgressListener)}
+ * was called with.
+ */
+ public int removeProgressListener(DownloadRequest downloadRequest,
+ DownloadProgressListener listener) throws RemoteException {
+ return 0;
+ }
+
+ /**
+ * Actual AIDL implementation -- hides the listener AIDL from the API.
+ * @hide
+ */
+ public final int removeProgressListener(
+ final DownloadRequest downloadRequest, final IDownloadProgressListener listener)
+ throws RemoteException {
+ if (downloadRequest == null) {
+ throw new NullPointerException("Download request must not be null");
+ }
+ if (listener == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
+ DeathRecipient deathRecipient =
+ mDownloadCallbackDeathRecipients.remove(listener.asBinder());
+ if (deathRecipient == null) {
+ throw new IllegalArgumentException("Unknown listener");
+ }
+
+ listener.asBinder().unlinkToDeath(deathRecipient, 0);
+
+ DownloadProgressListener exposedCallback =
+ mDownloadProgressListenerBinderMap.remove(listener.asBinder());
+ if (exposedCallback == null) {
+ throw new IllegalArgumentException("Unknown listener");
+ }
+
+ return removeProgressListener(downloadRequest, exposedCallback);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 14c5f4b..964a313 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -470,6 +470,9 @@
int bearerDataLength;
SmsEnvelope env = new SmsEnvelope();
CdmaSmsAddress addr = new CdmaSmsAddress();
+ // We currently do not parse subaddress in PDU, but it is required when determining
+ // fingerprint (see getIncomingSmsFingerprint()).
+ CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
try {
env.messageType = dis.readInt();
@@ -520,6 +523,7 @@
// link the filled objects to this SMS
mOriginatingAddress = addr;
env.origAddress = addr;
+ env.origSubaddress = subaddr;
mEnvelope = env;
mPdu = pdu;
@@ -1009,8 +1013,11 @@
output.write(mEnvelope.teleService);
output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
- output.write(mEnvelope.origSubaddress.origBytes, 0,
- mEnvelope.origSubaddress.origBytes.length);
+ // subaddress is not set when parsing some MT SMS.
+ if (mEnvelope.origSubaddress != null && mEnvelope.origSubaddress.origBytes != null) {
+ output.write(mEnvelope.origSubaddress.origBytes, 0,
+ mEnvelope.origSubaddress.origBytes.length);
+ }
return output.toByteArray();
}
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index cc3366f..0ca20de 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -50,13 +50,18 @@
private static final int TEST_UDP_ENCAP_PORT = 34567;
private static final int DROID_SPI = 0xD1201D;
+ private static final int DUMMY_RESOURCE_ID = 0x1234;
private static final InetAddress GOOGLE_DNS_4;
+ private static final String VTI_INTF_NAME = "ipsec_test";
+ private static final InetAddress VTI_LOCAL_ADDRESS;
+ private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
static {
try {
// Google Public DNS Addresses;
GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
+ VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
} catch (UnknownHostException e) {
throw new RuntimeException("Could not resolve DNS Addresses", e);
}
@@ -77,9 +82,8 @@
*/
@Test
public void testAllocSpi() throws Exception {
- int resourceId = 1;
IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
+ new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex(
eq(GOOGLE_DNS_4.getHostAddress()),
eq(DROID_SPI),
@@ -92,14 +96,13 @@
droidSpi.close();
- verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
+ verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
}
@Test
public void testAllocRandomSpi() throws Exception {
- int resourceId = 1;
IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
+ new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex(
eq(GOOGLE_DNS_4.getHostAddress()),
eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
@@ -113,7 +116,7 @@
randomSpi.close();
- verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
+ verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
}
/*
@@ -165,11 +168,10 @@
@Test
public void testOpenEncapsulationSocket() throws Exception {
- int resourceId = 1;
IpSecUdpEncapResponse udpEncapResp =
new IpSecUdpEncapResponse(
IpSecManager.Status.OK,
- resourceId,
+ DUMMY_RESOURCE_ID,
TEST_UDP_ENCAP_PORT,
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
@@ -182,16 +184,15 @@
encapSocket.close();
- verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
+ verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
}
@Test
public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
- int resourceId = 1;
IpSecUdpEncapResponse udpEncapResp =
new IpSecUdpEncapResponse(
IpSecManager.Status.OK,
- resourceId,
+ DUMMY_RESOURCE_ID,
TEST_UDP_ENCAP_PORT,
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
@@ -206,7 +207,7 @@
encapSocket.close();
- verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
+ verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
}
@Test
@@ -219,4 +220,45 @@
}
// TODO: add test when applicable transform builder interface is available
-}
+
+ private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
+ throws Exception {
+ IpSecTunnelInterfaceResponse dummyResponse =
+ new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
+ when(mMockIpSecService.createTunnelInterface(
+ eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
+ anyObject(), anyObject()))
+ .thenReturn(dummyResponse);
+
+ IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
+ VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
+
+ assertNotNull(tunnelIntf);
+ return tunnelIntf;
+ }
+
+ @Test
+ public void testCreateVti() throws Exception {
+ IpSecManager.IpSecTunnelInterface tunnelIntf =
+ createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
+
+ assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
+
+ tunnelIntf.close();
+ verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+ }
+
+ @Test
+ public void testAddRemoveAddressesFromVti() throws Exception {
+ IpSecManager.IpSecTunnelInterface tunnelIntf =
+ createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
+
+ tunnelIntf.addAddress(VTI_INNER_ADDRESS);
+ verify(mMockIpSecService)
+ .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+
+ tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
+ verify(mMockIpSecService)
+ .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 035a4cd7..0530a86 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -19,6 +19,7 @@
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
+import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
@@ -31,6 +32,7 @@
import static android.net.NetworkStats.SET_DBG_VPN_OUT;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static org.junit.Assert.assertEquals;
@@ -641,6 +643,136 @@
ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
}
+ @Test
+ public void testFilter_NoFilter() {
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry3 = new NetworkStats.Entry(
+ "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(entry1)
+ .addValues(entry2)
+ .addValues(entry3);
+
+ stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
+ assertEquals(3, stats.size());
+ assertEquals(entry1, stats.getValues(0, null));
+ assertEquals(entry2, stats.getValues(1, null));
+ assertEquals(entry3, stats.getValues(2, null));
+ }
+
+ @Test
+ public void testFilter_UidFilter() {
+ final int testUid = 10101;
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry3 = new NetworkStats.Entry(
+ "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(entry1)
+ .addValues(entry2)
+ .addValues(entry3);
+
+ stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
+ assertEquals(2, stats.size());
+ assertEquals(entry2, stats.getValues(0, null));
+ assertEquals(entry3, stats.getValues(1, null));
+ }
+
+ @Test
+ public void testFilter_InterfaceFilter() {
+ final String testIf1 = "testif1";
+ final String testIf2 = "testif2";
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry3 = new NetworkStats.Entry(
+ testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry4 = new NetworkStats.Entry(
+ testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 4)
+ .addValues(entry1)
+ .addValues(entry2)
+ .addValues(entry3)
+ .addValues(entry4);
+
+ stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
+ assertEquals(3, stats.size());
+ assertEquals(entry1, stats.getValues(0, null));
+ assertEquals(entry3, stats.getValues(1, null));
+ assertEquals(entry4, stats.getValues(2, null));
+ }
+
+ @Test
+ public void testFilter_EmptyInterfaceFilter() {
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(entry1)
+ .addValues(entry2);
+
+ stats.filter(UID_ALL, new String[] { }, TAG_ALL);
+ assertEquals(0, stats.size());
+ }
+
+ @Test
+ public void testFilter_TagFilter() {
+ final int testTag = 123;
+ final int otherTag = 456;
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats.Entry entry3 = new NetworkStats.Entry(
+ "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(entry1)
+ .addValues(entry2)
+ .addValues(entry3);
+
+ stats.filter(UID_ALL, INTERFACES_ALL, testTag);
+ assertEquals(2, stats.size());
+ assertEquals(entry1, stats.getValues(0, null));
+ assertEquals(entry2, stats.getValues(1, null));
+ }
+
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index b14f550..fc46b9c 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -184,7 +184,7 @@
assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
- NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
+ NetworkStatsFactory.clearStackedIfaces();
}
@Test
@@ -212,7 +212,7 @@
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L);
- NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
+ NetworkStatsFactory.clearStackedIfaces();
}
/**
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5ea21ea..82b7bec 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -63,6 +63,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -133,6 +134,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.DefaultNetworkMetrics;
+import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
@@ -749,6 +751,7 @@
// NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
private class WrappedNetworkMonitor extends NetworkMonitor {
+ public Handler connectivityHandler;
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
public int gen204ProbeResult = 500;
public String gen204ProbeRedirectUrl = null;
@@ -758,6 +761,7 @@
IpConnectivityLog log) {
super(context, handler, networkAgentInfo, defaultRequest, log,
NetworkMonitor.NetworkMonitorSettings.DEFAULT);
+ connectivityHandler = handler;
}
@Override
@@ -3664,18 +3668,29 @@
@Test
public void testBasicDnsConfigurationPushed() throws Exception {
+ final String IFNAME = "test_rmnet_data0";
+ final String[] EMPTY_TLS_SERVERS = new String[0];
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
waitForIdle();
verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
- anyInt(), any(), any(), any(), anyBoolean(), anyString());
+ anyInt(), any(), any(), any(), anyString(), eq(EMPTY_TLS_SERVERS));
final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("test_rmnet_data0");
+ cellLp.setInterfaceName(IFNAME);
+ // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
+ // "is-reachable" testing in order to not program netd with unreachable
+ // nameservers that it might try repeated to validate.
+ cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
+ cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"), IFNAME));
+ cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
+ cellLp.addRoute(
+ new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
- anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+ anyInt(), mStringArrayCaptor.capture(), any(), any(),
+ anyString(), eq(EMPTY_TLS_SERVERS));
// CS tells netd about the empty DNS config for this network.
assertEmpty(mStringArrayCaptor.getValue());
reset(mNetworkManagementService);
@@ -3684,7 +3699,8 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
- anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+ anyInt(), mStringArrayCaptor.capture(), any(), any(),
+ anyString(), eq(EMPTY_TLS_SERVERS));
assertEquals(1, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
reset(mNetworkManagementService);
@@ -3693,7 +3709,26 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
- anyInt(), mStringArrayCaptor.capture(), any(), any(), anyBoolean(), anyString());
+ anyInt(), mStringArrayCaptor.capture(), any(), any(),
+ anyString(), eq(EMPTY_TLS_SERVERS));
+ assertEquals(2, mStringArrayCaptor.getValue().length);
+ assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+ new String[]{"2001:db8::1", "192.0.2.1"}));
+ reset(mNetworkManagementService);
+
+ final String TLS_SPECIFIER = "tls.example.com";
+ final String TLS_SERVER6 = "2001:db8:53::53";
+ final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
+ final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
+ final Handler h = mCellNetworkAgent.getWrappedNetworkMonitor().connectivityHandler;
+ h.sendMessage(h.obtainMessage(
+ NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0,
+ mCellNetworkAgent.getNetwork().netId,
+ new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
+ waitForIdle();
+ verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+ anyInt(), mStringArrayCaptor.capture(), any(), any(),
+ eq(TLS_SPECIFIER), eq(TLS_SERVERS));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 3e1ff6d..410f754 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -17,11 +17,13 @@
package com.android.server;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +34,9 @@
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecTransformResponse;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
+import android.net.Network;
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
@@ -56,10 +61,15 @@
private final String mDestinationAddr;
private final String mSourceAddr;
+ private final LinkAddress mLocalInnerAddress;
@Parameterized.Parameters
public static Collection ipSecConfigs() {
- return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}});
+ return Arrays.asList(
+ new Object[][] {
+ {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
+ {"2601::2", "2601::10", "2001:db8::1/64"}
+ });
}
private static final byte[] AEAD_KEY = {
@@ -86,6 +96,7 @@
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
+ Network fakeNetwork = new Network(0xAB);
private static final IpSecAlgorithm AUTH_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
@@ -94,9 +105,11 @@
private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) {
+ public IpSecServiceParameterizedTest(
+ String sourceAddr, String destAddr, String localInnerAddr) {
mSourceAddr = sourceAddr;
mDestinationAddr = destAddr;
+ mLocalInnerAddress = new LinkAddress(localInnerAddr);
}
@Before
@@ -308,6 +321,30 @@
}
@Test
+ public void testReleaseOwnedSpi() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder());
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ verify(mMockNetd, times(0))
+ .ipSecDeleteSecurityAssociation(
+ eq(createTransformResp.resourceId),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI),
+ anyInt(),
+ anyInt());
+ // quota is not released until the SPI is released by the Transform
+ assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+ }
+
+ @Test
public void testDeleteTransform() throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -317,7 +354,7 @@
mIpSecService.createTransform(ipSecConfig, new Binder());
mIpSecService.deleteTransform(createTransformResp.resourceId);
- verify(mMockNetd)
+ verify(mMockNetd, times(1))
.ipSecDeleteSecurityAssociation(
eq(createTransformResp.resourceId),
anyString(),
@@ -330,6 +367,21 @@
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
+ assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+
+ mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+ // Verify that ipSecDeleteSa was not called when the SPI was released because the
+ // ownedByTransform property should prevent it; (note, the called count is cumulative).
+ verify(mMockNetd, times(1))
+ .ipSecDeleteSecurityAssociation(
+ anyInt(),
+ anyString(),
+ anyString(),
+ anyInt(),
+ anyInt(),
+ anyInt());
+ assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
+
try {
userRecord.mTransformRecords.getRefcountedResourceOrThrow(
createTransformResp.resourceId);
@@ -406,4 +458,103 @@
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
}
+
+ private IpSecTunnelInterfaceResponse createAndValidateTunnel(
+ String localAddr, String remoteAddr) {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ mIpSecService.createTunnelInterface(
+ mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+
+ assertNotNull(createTunnelResp);
+ assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
+ return createTunnelResp;
+ }
+
+ @Test
+ public void testCreateTunnelInterface() throws Exception {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+ // Check that we have stored the tracking object, and retrieve it
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ IpSecService.RefcountedResource refcountedRecord =
+ userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+ createTunnelResp.resourceId);
+
+ assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
+ verify(mMockNetd)
+ .addVirtualTunnelInterface(
+ eq(createTunnelResp.interfaceName),
+ eq(mSourceAddr),
+ eq(mDestinationAddr),
+ anyInt(),
+ anyInt());
+ }
+
+ @Test
+ public void testDeleteTunnelInterface() throws Exception {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+
+ // Verify quota and RefcountedResource objects cleaned up
+ assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
+ verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+ try {
+ userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+ createTunnelResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testTunnelInterfaceBinderDeath() throws Exception {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+ IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+ IpSecService.RefcountedResource refcountedRecord =
+ userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+ createTunnelResp.resourceId);
+
+ refcountedRecord.binderDied();
+
+ // Verify quota and RefcountedResource objects cleaned up
+ assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
+ verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+ try {
+ userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+ createTunnelResp.resourceId);
+ fail("Expected IllegalArgumentException on attempt to access deleted resource");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testAddRemoveAddressFromTunnelInterface() throws Exception {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+ mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
+ verify(mMockNetd)
+ .interfaceAddAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+
+ mIpSecService.removeAddressFromTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress);
+ verify(mMockNetd)
+ .interfaceDelAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
new file mode 100644
index 0000000..4a83d1b
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.Manifest.permission.CHANGE_NETWORK_STATE;
+import static android.Manifest.permission.CHANGE_WIFI_STATE;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PermissionMonitorTest {
+ private static final int MOCK_UID = 10001;
+ private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" };
+
+ @Mock private Context mContext;
+ @Mock private PackageManager mPackageManager;
+
+ private PermissionMonitor mPermissionMonitor;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getPackagesForUid(MOCK_UID)).thenReturn(MOCK_PACKAGE_NAMES);
+ mPermissionMonitor = new PermissionMonitor(mContext, null);
+ }
+
+ private void expectPermission(String[] permissions, boolean preinstalled) throws Exception {
+ final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled);
+ when(mPackageManager.getPackageInfo(MOCK_PACKAGE_NAMES[0], GET_PERMISSIONS))
+ .thenReturn(packageInfo);
+ }
+
+ private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) {
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.requestedPermissions = permissions;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.flags = preinstalled ? FLAG_SYSTEM : 0;
+ return packageInfo;
+ }
+
+ @Test
+ public void testHasPermission() {
+ PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = packageInfoWithPermissions(new String[] {
+ CHANGE_NETWORK_STATE, NETWORK_STACK
+ }, false);
+ assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = packageInfoWithPermissions(new String[] {
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
+ }, false);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+ }
+
+ @Test
+ public void testIsPreinstalledSystemApp() {
+ PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
+ assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app));
+
+ app = packageInfoWithPermissions(new String[] {}, true);
+ assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app));
+ }
+
+ @Test
+ public void testHasUseBackgroundNetworksPermission() throws Exception {
+ expectPermission(new String[] { CHANGE_NETWORK_STATE }, false);
+ assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+ expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, false);
+ assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+ // TODO : make this false when b/31479477 is fixed
+ expectPermission(new String[] {}, true);
+ assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+ expectPermission(new String[] { CHANGE_WIFI_STATE }, true);
+ assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+ expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, true);
+ assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+ expectPermission(new String[] {}, false);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+ expectPermission(new String[] { CHANGE_WIFI_STATE }, false);
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 099cfd4..c727bd2 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -27,8 +27,12 @@
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
@@ -36,6 +40,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -45,18 +50,29 @@
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
+import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
-import android.net.NetworkRequest;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.MacAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
+import android.net.NetworkUtils;
+import android.net.RouteInfo;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.util.InterfaceParams;
+import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -74,10 +90,16 @@
import android.telephony.CarrierConfigManager;
import android.test.mock.MockContentResolver;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.tethering.IControlsTethering;
+import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadHardwareInterface;
+import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringDependencies;
+import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
import org.junit.After;
import org.junit.Before;
@@ -86,13 +108,21 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.Vector;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TetheringTest {
+ private static final int IFINDEX_OFFSET = 100;
+
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+ private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
+ private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
+ private static final String TEST_USB_IFNAME = "test_rndis0";
+ private static final String TEST_WLAN_IFNAME = "test_wlan0";
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@@ -103,16 +133,21 @@
@Mock private MockableSystemProperties mSystemProperties;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
- @Mock private TetheringDependencies mTetheringDependencies;
@Mock private UsbManager mUsbManager;
@Mock private WifiManager mWifiManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
+ @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+ @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+ @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+ @Mock private INetd mNetd;
+
+ private final MockTetheringDependencies mTetheringDependencies =
+ new MockTetheringDependencies();
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle();
private final TestLooper mLooper = new TestLooper();
- private final String mTestIfname = "test_wlan0";
private Vector<Intent> mIntents;
private BroadcastInterceptingContext mServiceContext;
@@ -146,23 +181,104 @@
}
}
+ public class MockTetheringDependencies extends TetheringDependencies {
+ private StateMachine upstreamNetworkMonitorMasterSM;
+ private ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+
+ @Override
+ public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+ return mOffloadHardwareInterface;
+ }
+
+ @Override
+ public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
+ StateMachine target, SharedLog log, int what) {
+ upstreamNetworkMonitorMasterSM = target;
+ return mUpstreamNetworkMonitor;
+ }
+
+ @Override
+ public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+ ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+ ipv6CoordinatorNotifyList = notifyList;
+ return mIPv6TetheringCoordinator;
+ }
+
+ @Override
+ public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+ return mRouterAdvertisementDaemon;
+ }
+
+ @Override
+ public INetd getNetdService() {
+ return mNetd;
+ }
+
+ @Override
+ public InterfaceParams getInterfaceParams(String ifName) {
+ final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
+ TEST_MOBILE_IFNAME };
+ final int index = ArrayUtils.indexOf(ifaces, ifName);
+ assertTrue("Non-mocked interface: " + ifName, index >= 0);
+ return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+ MacAddress.ALL_ZEROS_ADDRESS);
+ }
+ }
+
+ private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6) {
+ final NetworkInfo info = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, null, null);
+ info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(TEST_MOBILE_IFNAME);
+
+ if (withIPv4) {
+ prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+ NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME));
+ }
+
+ if (withIPv6) {
+ prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2"));
+ prop.addLinkAddress(
+ new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"),
+ NetworkConstants.RFC7421_PREFIX_LENGTH));
+ prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
+ NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
+ }
+
+
+ final NetworkCapabilities capabilities = new NetworkCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
+ return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
+ }
+
+ private static NetworkState buildMobileIPv4UpstreamState() {
+ return buildMobileUpstreamState(true, false);
+ }
+
+ private static NetworkState buildMobileDualStackUpstreamState() {
+ return buildMobileUpstreamState(true, true);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
- .thenReturn(new String[0]);
+ .thenReturn(new String[] { "test_rndis\\d" });
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
+ .thenReturn(new String[]{ "test_wlan\\d" });
when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
.thenReturn(new int[0]);
when(mNMService.listInterfaces())
- .thenReturn(new String[]{ "test_rmnet_data0", mTestIfname });
+ .thenReturn(new String[] {
+ TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
when(mNMService.getInterfaceConfig(anyString()))
.thenReturn(new InterfaceConfiguration());
+ when(mRouterAdvertisementDaemon.start())
+ .thenReturn(true);
mServiceContext = new MockContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
@@ -176,8 +292,6 @@
};
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
- when(mTetheringDependencies.getOffloadHardwareInterface(
- any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
@@ -264,10 +378,10 @@
}
private void verifyInterfaceServingModeStarted() throws Exception {
- verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
+ verify(mNMService, times(1)).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, times(1))
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(mTestIfname);
+ .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
}
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
@@ -287,7 +401,7 @@
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
if (emulateInterfaceStatusChanged) {
- mTethering.interfaceStatusChanged(mTestIfname, true);
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
}
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
@@ -297,27 +411,31 @@
// broadcast indicating that the interface is "available".
if (emulateInterfaceStatusChanged) {
verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
}
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
- @Test
- public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+ private void prepareUsbTethering(NetworkState upstreamState) {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+ when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+ .thenReturn(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
mTethering.startTethering(TETHERING_USB, null, false);
mLooper.dispatchAll();
verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
- // Pretend we receive a USB connected broadcast. Here we also pretend
- // that the RNDIS function is somehow enabled, so that we see if we
- // might trip ourselves up.
- sendUsbBroadcast(true, false, true);
- mLooper.dispatchAll();
+ mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
+ }
+
+ @Test
+ public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+ NetworkState upstreamState = buildMobileIPv4UpstreamState();
+ prepareUsbTethering(upstreamState);
+
// This should produce no activity of any kind.
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
@@ -328,6 +446,10 @@
// Now we should see the start of tethering mechanics (in this case:
// tetherMatchingInterfaces() which starts by fetching all interfaces).
verify(mNMService, times(1)).listInterfaces();
+
+ // UpstreamNetworkMonitor should receive selected upstream
+ verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+ verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
}
@Test
@@ -348,26 +470,21 @@
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
if (emulateInterfaceStatusChanged) {
- mTethering.interfaceStatusChanged(mTestIfname, true);
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
}
- sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
+ sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
- mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
- // UpstreamNetworkMonitor will be started, and will register two callbacks:
- // a "listen all" and a "track default".
- verify(mConnectivityManager, times(1)).registerNetworkCallback(
- any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
- verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
- any(NetworkCallback.class), any(Handler.class));
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
+ verify(mUpstreamNetworkMonitor, times(1)).start();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
verifyNoMoreInteractions(mConnectivityManager);
@@ -375,14 +492,14 @@
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
- mTethering.interfaceRemoved(mTestIfname);
+ mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(mTestIfname);
+ verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
// TODO: Why is {g,s}etInterfaceConfig() called more than once?
- verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
+ verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, atLeastOnce())
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+ .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
@@ -390,9 +507,62 @@
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(mTestIfname));
+ mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
+ /**
+ * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+ */
+ private void sendIPv6TetherUpdates(NetworkState upstreamState) {
+ // IPv6TetheringCoordinator must have been notified of downstream
+ verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
+ argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
+ eq(IControlsTethering.STATE_TETHERED));
+
+ for (TetherInterfaceStateMachine tism :
+ mTetheringDependencies.ipv6CoordinatorNotifyList) {
+ NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true);
+ tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+ upstreamState.linkProperties.isIPv6Provisioned()
+ ? ipv6OnlyState.linkProperties
+ : null);
+ }
+ mLooper.dispatchAll();
+ }
+
+ private void runUsbTethering(NetworkState upstreamState) {
+ prepareUsbTethering(upstreamState);
+ sendUsbBroadcast(true, true, true);
+ mLooper.dispatchAll();
+ }
+
+ @Test
+ public void workingMobileUsbTethering_IPv4() throws Exception {
+ NetworkState upstreamState = buildMobileIPv4UpstreamState();
+ runUsbTethering(upstreamState);
+
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+ sendIPv6TetherUpdates(upstreamState);
+ verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
+ }
+
+ @Test
+ public void workingMobileUsbTethering_DualStack() throws Exception {
+ NetworkState upstreamState = buildMobileDualStackUpstreamState();
+ runUsbTethering(upstreamState);
+
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mRouterAdvertisementDaemon, times(1)).start();
+
+ sendIPv6TetherUpdates(upstreamState);
+ verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ }
+
+
@Test
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
workingLocalOnlyHotspotEnrichedApBroadcast(true);
@@ -420,12 +590,12 @@
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// tethering mode is to be started.
- mTethering.interfaceStatusChanged(mTestIfname, true);
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
@@ -448,30 +618,23 @@
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// tethering mode is to be started.
- mTethering.interfaceStatusChanged(mTestIfname, true);
- sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+ sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
- mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
- // UpstreamNetworkMonitor will be started, and will register two callbacks:
- // a "listen all" and a "track default".
- verify(mConnectivityManager, times(1)).registerNetworkCallback(
- any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
- verify(mConnectivityManager, times(1)).registerDefaultNetworkCallback(
- any(NetworkCallback.class), any(Handler.class));
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ verify(mUpstreamNetworkMonitor, times(1)).start();
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
- verify(mConnectivityManager, times(1)).requestNetwork(
- any(NetworkRequest.class), any(NetworkCallback.class), eq(0), anyInt(),
- any(Handler.class));
+ verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
verifyNoMoreInteractions(mConnectivityManager);
@@ -494,14 +657,14 @@
// Emulate externally-visible WifiManager effects, when tethering mode
// is being torn down.
sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
- mTethering.interfaceRemoved(mTestIfname);
+ mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(mTestIfname);
+ verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
// TODO: Why is {g,s}etInterfaceConfig() called more than once?
- verify(mNMService, atLeastOnce()).getInterfaceConfig(mTestIfname);
+ verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, atLeastOnce())
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+ .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
@@ -509,7 +672,7 @@
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(mTestIfname));
+ mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
// TODO: Test with and without interfaceStatusChanged().
@@ -530,21 +693,21 @@
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// tethering mode is to be started.
- mTethering.interfaceStatusChanged(mTestIfname, true);
- sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_TETHERED);
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+ sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
// We verify get/set called twice here: once for setup and once during
// teardown because all events happen over the course of the single
// dispatchAll() above.
- verify(mNMService, times(2)).getInterfaceConfig(mTestIfname);
+ verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, times(2))
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(mTestIfname);
+ .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
- mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
verify(mNMService, times(1)).setIpForwardingEnabled(true);
// This never gets called because of the exception thrown above.
@@ -552,9 +715,9 @@
// When the master state machine transitions to an error state it tells
// downstream interfaces, which causes us to tell Wi-Fi about the error
// so it can take down AP mode.
- verify(mNMService, times(1)).untetherInterface(mTestIfname);
+ verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
- mTestIfname, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mConnectivityManager);
@@ -596,7 +759,7 @@
@Test
public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
- final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+ final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
final boolean currDisallow = false;
final boolean nextDisallow = true;
final int expectedInteractionsWithShowNotification = 1;
@@ -618,7 +781,7 @@
@Test
public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
- final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+ final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
final boolean currDisallow = true;
final boolean nextDisallow = false;
final int expectedInteractionsWithShowNotification = 0;
@@ -629,7 +792,7 @@
@Test
public void testDisallowTetheringUnchanged() throws Exception {
- final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
+ final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
final int expectedInteractionsWithShowNotification = 0;
boolean currDisallow = true;
boolean nextDisallow = true;
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index db5373a..5f3fc54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -31,7 +31,6 @@
import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
@@ -39,7 +38,6 @@
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
-import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
@@ -75,6 +73,7 @@
@Mock private IControlsTethering mTetherHelper;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private SharedLog mSharedLog;
+ @Mock private TetheringDependencies mTetheringDependencies;
private final TestLooper mLooper = new TestLooper();
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
@@ -84,7 +83,7 @@
private void initStateMachine(int interfaceType) throws Exception {
mTestedSm = new TetherInterfaceStateMachine(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
- mNMService, mStatsService, mTetherHelper);
+ mNMService, mStatsService, mTetherHelper, mTetheringDependencies);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state.
@@ -111,7 +110,8 @@
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper);
+ TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
+ mTetheringDependencies);
mTestedSm.start();
mLooper.dispatchAll();
verify(mTetherHelper).updateInterfaceState(
@@ -346,7 +346,7 @@
* Send a command to the state machine under test, and run the event loop to idle.
*
* @param command One of the TetherInterfaceStateMachine.CMD_* constants.
- * @param obj An additional argument to pass.
+ * @param arg1 An additional argument to pass.
*/
private void dispatchCommand(int command, int arg1) {
mTestedSm.sendMessage(command, arg1);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index c3b9def..9661dc2 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -147,6 +147,16 @@
}
@Test
+ public void testCallbacksRegistered() {
+ mUNM.start();
+ verify(mCM, times(1)).registerNetworkCallback(any(), any(), any());
+ verify(mCM, times(1)).registerDefaultNetworkCallback(any(), any());
+
+ mUNM.stop();
+ verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
+ }
+
+ @Test
public void testRequestsMobileNetwork() throws Exception {
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 47c3455..17ca651 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -25,6 +25,7 @@
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
@@ -58,6 +59,9 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -95,6 +99,7 @@
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -668,6 +673,94 @@
}
@Test
+ public void testDetailedUidStats() throws Exception {
+ // pretend that network comes online
+ expectDefaultSettings();
+ expectNetworkState(buildWifiState());
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
+
+ NetworkStats.Entry entry1 = new NetworkStats.Entry(
+ TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
+ NetworkStats.Entry entry2 = new NetworkStats.Entry(
+ TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
+ NetworkStats.Entry entry3 = new NetworkStats.Entry(
+ TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
+
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ .addValues(entry1)
+ .addValues(entry2)
+ .addValues(entry3));
+ mService.incrementOperationCount(UID_RED, 0xF00D, 1);
+
+ NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
+
+ assertEquals(3, stats.size());
+ entry1.operations = 1;
+ assertEquals(entry1, stats.getValues(0, null));
+ entry2.operations = 1;
+ assertEquals(entry2, stats.getValues(1, null));
+ assertEquals(entry3, stats.getValues(2, null));
+ }
+
+ @Test
+ public void testDetailedUidStats_Filtered() throws Exception {
+ // pretend that network comes online
+ expectDefaultSettings();
+
+ final String stackedIface = "stacked-test0";
+ final LinkProperties stackedProp = new LinkProperties();
+ stackedProp.setInterfaceName(stackedIface);
+ final NetworkState wifiState = buildWifiState();
+ wifiState.linkProperties.addStackedLink(stackedProp);
+ expectNetworkState(wifiState);
+
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
+
+ NetworkStats.Entry uidStats = new NetworkStats.Entry(
+ TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+ // Stacked on matching interface
+ NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
+ stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+ // Different interface
+ NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
+ "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+
+ final String[] ifaceFilter = new String[] { TEST_IFACE };
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any()))
+ .thenReturn(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(uidStats));
+ when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
+ .thenReturn(new NetworkStats(getElapsedRealtime(), 2)
+ .addValues(tetheredStats1)
+ .addValues(tetheredStats2));
+
+ NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
+
+ verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces ->
+ ifaces != null && ifaces.length == 2
+ && ArrayUtils.contains(ifaces, TEST_IFACE)
+ && ArrayUtils.contains(ifaces, stackedIface)));
+
+ assertEquals(2, stats.size());
+ assertEquals(uidStats, stats.getValues(0, null));
+ assertEquals(tetheredStats1, stats.getValues(1, null));
+ }
+
+ @Test
public void testForegroundBackground() throws Exception {
// pretend that network comes online
expectCurrentTime();
@@ -1056,7 +1149,7 @@
private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
throws Exception {
- when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
+ when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail);
// also include tethering details, since they are folded into UID
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index c6ad4c2..dcb90e4 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -13,6 +13,7 @@
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'be': 'Cyrl',
'bg': 'Cyrl',
'bn': 'Beng',
'cu': 'Cyrl',
@@ -33,6 +34,7 @@
'ja': 'Jpan',
'kn': 'Knda',
'ko': 'Kore',
+ 'la': 'Latn',
'ml': 'Mlym',
'mn': 'Cyrl',
'mr': 'Deva',