Merge "Add carrier config variable to hide manage IMS conference call button"
diff --git a/Android.bp b/Android.bp
index 7d75f62..1f4c59a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -102,3 +102,29 @@
dxflags: ["--core-library"],
installable: false,
}
+
+python_defaults {
+ name: "base_default",
+ version: {
+ py2: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ py3: {
+ enabled: false,
+ embedded_launcher: false,
+ },
+ },
+}
+
+python_binary_host {
+ name: "fontchain_linter",
+ defaults: ["base_default"],
+ main: "tools/fonts/fontchain_linter.py",
+ srcs: [
+ "tools/fonts/fontchain_linter.py",
+ ],
+ libs: [
+ "fontTools",
+ ],
+}
diff --git a/Android.mk b/Android.mk
index dd53793..c61227f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -519,10 +519,12 @@
telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
+ telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl \
telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
+ telephony/java/com/android/ims/internal/IImsRcsFeature.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
telephony/java/com/android/ims/internal/IImsServiceController.aidl \
- telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl \
+ telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl \
telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
telephony/java/com/android/ims/internal/IImsUt.aidl \
telephony/java/com/android/ims/internal/IImsUtListener.aidl \
@@ -655,6 +657,7 @@
frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \
frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
+ frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \
frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \
frameworks/base/location/java/android/location/Location.aidl \
diff --git a/api/current.txt b/api/current.txt
index 4dbbfaa..2b9e372 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25529,7 +25529,6 @@
method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
@@ -38687,6 +38686,7 @@
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -38731,6 +38731,8 @@
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -38739,6 +38741,10 @@
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
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_DEST_INVALID_PERM = 3; // 0x3
+ field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+ field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
}
public static class Call.Details {
@@ -39072,8 +39078,11 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39196,6 +39205,9 @@
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39356,6 +39368,7 @@
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9bce265..1620e65 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27725,7 +27725,6 @@
method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
@@ -41920,6 +41919,7 @@
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -41966,6 +41966,8 @@
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -41974,6 +41976,10 @@
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
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_DEST_INVALID_PERM = 3; // 0x3
+ field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+ field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
}
public static class Call.Details {
@@ -42318,8 +42324,11 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -42567,6 +42576,9 @@
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -42768,6 +42780,7 @@
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -43891,6 +43904,39 @@
}
+package android.telephony.data {
+
+ public final class DataProfile implements android.os.Parcelable {
+ ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
+ ctor public DataProfile(android.os.Parcel);
+ method public int describeContents();
+ method public java.lang.String getApn();
+ method public int getAuthType();
+ method public int getBearerBitmap();
+ method public int getMaxConns();
+ method public int getMaxConnsTime();
+ method public int getMtu();
+ method public java.lang.String getMvnoMatchData();
+ method public java.lang.String getMvnoType();
+ method public java.lang.String getPassword();
+ method public int getProfileId();
+ method public java.lang.String getProtocol();
+ method public java.lang.String getRoamingProtocol();
+ method public int getSupportedApnTypesBitmap();
+ method public int getType();
+ method public java.lang.String getUserName();
+ method public int getWaitTime();
+ method public boolean isEnabled();
+ method public boolean isModemCognitive();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+ field public static final int TYPE_3GPP = 1; // 0x1
+ field public static final int TYPE_3GPP2 = 2; // 0x2
+ field public static final int TYPE_COMMON = 0; // 0x0
+ }
+
+}
+
package android.telephony.gsm {
public class GsmCellLocation extends android.telephony.CellLocation {
diff --git a/api/test-current.txt b/api/test-current.txt
index 7534e9f..33d96a7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38894,6 +38894,7 @@
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -38938,6 +38939,8 @@
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -38946,6 +38949,10 @@
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
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_DEST_INVALID_PERM = 3; // 0x3
+ field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+ field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
}
public static class Call.Details {
@@ -39296,8 +39303,11 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39420,6 +39430,9 @@
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39580,6 +39593,7 @@
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
diff --git a/cmds/webview_zygote/Android.mk b/cmds/webview_zygote/Android.mk
index 66e762c..955e58e 100644
--- a/cmds/webview_zygote/Android.mk
+++ b/cmds/webview_zygote/Android.mk
@@ -21,6 +21,8 @@
LOCAL_SRC_FILES := webview_zygote.cpp
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libbinder \
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 17156e8..384540a 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -5194,7 +5194,7 @@
com.android.ims.internal.IImsService
com.android.ims.internal.IImsService$Stub
com.android.ims.internal.IImsServiceController
-com.android.ims.internal.IImsServiceFeatureListener
+com.android.ims.internal.IImsServiceFeatureCallback
com.android.ims.internal.IImsUt
com.android.ims.internal.IImsUt$Stub
com.android.ims.internal.IImsUtListener
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8c78ccb..0d89c6f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4344,7 +4344,7 @@
throw new IllegalArgumentException("requestCode should be >= 0");
}
if (mHasCurrentPermissionsRequest) {
- Log.w(TAG, "Can reqeust only one set of permissions at a time");
+ Log.w(TAG, "Can request only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]);
return;
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 063ad24..aab7d77 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -23,16 +23,19 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
+import android.system.StructTimespec;
import android.util.Log;
-import com.google.android.collect.Maps;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ExponentiallyBucketedHistogram;
import com.android.internal.util.XmlUtils;
import dalvik.system.BlockGuard;
+import libcore.io.IoUtils;
+
+import com.google.android.collect.Maps;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedInputStream;
@@ -50,8 +53,6 @@
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
-import libcore.io.IoUtils;
-
final class SharedPreferencesImpl implements SharedPreferences {
private static final String TAG = "SharedPreferencesImpl";
private static final boolean DEBUG = false;
@@ -80,7 +81,7 @@
private boolean mLoaded = false;
@GuardedBy("mLock")
- private long mStatTimestamp;
+ private StructTimespec mStatTimestamp;
@GuardedBy("mLock")
private long mStatSize;
@@ -162,7 +163,7 @@
mLoaded = true;
if (map != null) {
mMap = map;
- mStatTimestamp = stat.st_mtime;
+ mStatTimestamp = stat.st_mtim;
mStatSize = stat.st_size;
} else {
mMap = new HashMap<>();
@@ -209,7 +210,7 @@
}
synchronized (mLock) {
- return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size;
+ return !stat.st_mtim.equals(mStatTimestamp) || mStatSize != stat.st_size;
}
}
@@ -744,7 +745,7 @@
try {
final StructStat stat = Os.stat(mFile.getPath());
synchronized (mLock) {
- mStatTimestamp = stat.st_mtime;
+ mStatTimestamp = stat.st_mtim;
mStatSize = stat.st_size;
}
} catch (ErrnoException e) {
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index e3d763a..6692e13 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -350,13 +350,22 @@
* application can be registered at time. When no longer used, application
* should be unregistered using
* {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+ * 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.
*
* @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
+ * The HID Device SDP record is required.
* @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
+ * The Incoming QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
* @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.
- * @return
+ * The BluetoothHidDeviceCallback object is required.
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
@@ -394,12 +403,15 @@
* {@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.
*
* @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
* BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
* BluetoothHidDeviceAppConfiguration,
* boolean)}
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
Log.v(TAG, "unregisterApp()");
@@ -426,7 +438,7 @@
* @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
* descriptor.
* @param data Report data, not including Report Id.
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false;
@@ -452,7 +464,7 @@
* @param type Report Type, as in request.
* @param id Report Id, as in request.
* @param data Report data, not including Report Id.
- * @return
+ * @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);
@@ -478,7 +490,7 @@
* from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
*
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
- * @return
+ * @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);
@@ -524,10 +536,13 @@
}
/**
- * Initiates connection to host which currently has Virtual Cable
- * established with device.
+ * 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.
*
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean connect(BluetoothDevice device) {
Log.v(TAG, "connect(): device=" + device);
@@ -550,8 +565,11 @@
/**
* 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.
*
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean disconnect(BluetoothDevice device) {
Log.v(TAG, "disconnect(): device=" + device);
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index ccc3ef4..881ae98 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -45,6 +45,21 @@
public static final int MAX = (int) 0xffffffff;
+ /**
+ * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
+ * The QoS Settings is optional.
+ * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
+ * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
+ * https://www.bluetooth.com/specifications/profiles-overview
+ * </a>
+ * Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+ * @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
+ */
public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
int peakBandwidth, int latency, int delayVariation) {
this.serviceType = serviceType;
@@ -59,7 +74,12 @@
public boolean equals(Object o) {
if (o instanceof BluetoothHidDeviceAppQosSettings) {
BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
- return false;
+ 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;
}
@@ -106,4 +126,85 @@
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);
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index f01c493..4669637 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,6 +19,8 @@
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.
@@ -39,6 +41,18 @@
public final byte subclass;
public final byte[] descriptors;
+ /**
+ * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+ * @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
+ * @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
+ * @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
+ * @param subclass Subclass of this Bluetooth HID device.
+ * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
+ * @param descriptors Descriptors of this Bluetooth HID device.
+ * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
+ */
public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
byte subclass, byte[] descriptors) {
this.name = name;
@@ -52,7 +66,11 @@
public boolean equals(Object o) {
if (o instanceof BluetoothHidDeviceAppSdpSettings) {
BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
- return false;
+ 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;
}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 64f8f39..d6e62cf 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -15,6 +15,7 @@
*/
package android.net;
+import android.annotation.NonNull;
import android.annotation.StringDef;
import android.os.Build;
import android.os.Parcel;
@@ -27,8 +28,10 @@
import java.util.Arrays;
/**
- * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
- * RFC 4301.
+ * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
*/
public final class IpSecAlgorithm implements Parcelable {
/**
@@ -39,16 +42,16 @@
public static final String CRYPT_AES_CBC = "cbc(aes)";
/**
- * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
- * applications and is provided for legacy compatibility with 3gpp infrastructure.
+ * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
*/
public static final String AUTH_HMAC_MD5 = "hmac(md5)";
/**
- * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
- * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+ * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
*/
@@ -69,7 +72,7 @@
public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
/**
- * SHA512 HMAC Authentication/Integrity Algorithm
+ * SHA512 HMAC Authentication/Integrity Algorithm.
*
* <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
*/
@@ -80,9 +83,9 @@
*
* <p>Valid lengths for keying material are {160, 224, 288}.
*
- * <p>As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key
- * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per
- * invocation with the same key.
+ * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
+ * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
+ * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
*
* <p>Valid ICV (truncation) lengths are {64, 96, 128}.
*/
@@ -105,48 +108,47 @@
private final int mTruncLenBits;
/**
- * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
- * algorithm
+ * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+ * defined as constants in this class.
*
- * @param algorithm type for IpSec.
- * @param key non-null Key padded to a multiple of 8 bits.
+ * @param algorithm name of the algorithm.
+ * @param key key padded to a multiple of 8 bits.
*/
- public IpSecAlgorithm(String algorithm, byte[] key) {
+ public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
this(algorithm, key, key.length * 8);
}
/**
- * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
- * algorithm
+ * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+ * defined as constants in this class.
*
- * @param algoName precise name of the algorithm to be used.
- * @param key non-null Key padded to a multiple of 8 bits.
- * @param truncLenBits the number of bits of output hash to use; only meaningful for
- * Authentication or Authenticated Encryption (equivalent to ICV length).
+ * <p>This constructor only supports algorithms that use a truncation length. i.e.
+ * Authentication and Authenticated Encryption algorithms.
+ *
+ * @param algorithm name of the algorithm.
+ * @param key key padded to a multiple of 8 bits.
+ * @param truncLenBits number of bits of output hash to use.
*/
- public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
- if (!isTruncationLengthValid(algoName, truncLenBits)) {
+ public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+ if (!isTruncationLengthValid(algorithm, truncLenBits)) {
throw new IllegalArgumentException("Unknown algorithm or invalid length");
}
- mName = algoName;
+ mName = algorithm;
mKey = key.clone();
mTruncLenBits = Math.min(truncLenBits, key.length * 8);
}
- /** Retrieve the algorithm name */
+ /** Get the algorithm name */
public String getName() {
return mName;
}
- /** Retrieve the key for this algorithm */
+ /** Get the key for this algorithm */
public byte[] getKey() {
return mKey.clone();
}
- /**
- * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
- * the length in bits of the key.
- */
+ /** Get the truncation length of this algorithm, in bits */
public int getTruncationLengthBits() {
return mTruncLenBits;
}
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 61b13a9..e6cd3fc 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -20,7 +20,12 @@
import com.android.internal.annotations.VisibleForTesting;
-/** @hide */
+/**
+ * This class encapsulates all the configuration parameters needed to create IPsec transforms and
+ * policies.
+ *
+ * @hide
+ */
public final class IpSecConfig implements Parcelable {
private static final String TAG = "IpSecConfig";
@@ -38,6 +43,9 @@
// for outbound packets. It may also be used to select packets.
private Network mNetwork;
+ /**
+ * This class captures the parameters that specifically apply to inbound or outbound traffic.
+ */
public static class Flow {
// Minimum requirements for identifying a transform
// SPI identifying the IPsec flow in packet processing
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index eccd5f4..a9e60ec 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
@@ -37,22 +38,28 @@
import java.net.Socket;
/**
- * This class contains methods for managing IPsec sessions, which will perform kernel-space
- * encryption and decryption of socket or Network traffic.
+ * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
+ * confidentiality (encryption) and integrity (authentication) to IP traffic.
*
- * <p>An IpSecManager may be obtained by calling {@link
- * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
- * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
+ * transport mode security associations and apply them to individual sockets. Applications looking
+ * to create a VPN should use {@link VpnService}.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
*/
@SystemService(Context.IPSEC_SERVICE)
public final class IpSecManager {
private static final String TAG = "IpSecManager";
/**
- * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
*
* <p>No IPsec packet may contain an SPI of 0.
+ *
+ * @hide
*/
+ @TestApi
public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
/** @hide */
@@ -66,10 +73,12 @@
public static final int INVALID_RESOURCE_ID = 0;
/**
- * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
- * request. If encountered, selection of a new SPI is required before a transform may be
- * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
- * or reserved using reserveSecurityParameterIndex.
+ * Thrown to indicate that a requested SPI is in use.
+ *
+ * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
+ * one device. If this error is encountered, a new SPI is required before a transform may be
+ * created. This error can be avoided by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex}.
*/
public static final class SpiUnavailableException extends AndroidException {
private final int mSpi;
@@ -78,24 +87,26 @@
* Construct an exception indicating that a transform with the given SPI is already in use
* or otherwise unavailable.
*
- * @param msg Description indicating the colliding SPI
+ * @param msg description indicating the colliding SPI
* @param spi the SPI that could not be used due to a collision
*/
SpiUnavailableException(String msg, int spi) {
- super(msg + "(spi: " + spi + ")");
+ super(msg + " (spi: " + spi + ")");
mSpi = spi;
}
- /** Retrieve the SPI that caused a collision */
+ /** Get the SPI that caused a collision. */
public int getSpi() {
return mSpi;
}
}
/**
- * Indicates that the requested system resource for IPsec, such as a socket or other system
- * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
- * type requested.
+ * Thrown to indicate that an IPsec resource is unavailable.
+ *
+ * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
+ * IpSecTransform}, or other system resources. If this exception is thrown, users should release
+ * allocated objects of the type requested.
*/
public static final class ResourceUnavailableException extends AndroidException {
@@ -106,6 +117,13 @@
private final IIpSecService mService;
+ /**
+ * This class represents a reserved SPI.
+ *
+ * <p>Objects of this type are used to track reserved security parameter indices. They can be
+ * obtained by calling {@link IpSecManager#reserveSecurityParameterIndex} and must be released
+ * by calling {@link #close()} when they are no longer needed.
+ */
public static final class SecurityParameterIndex implements AutoCloseable {
private final IIpSecService mService;
private final InetAddress mRemoteAddress;
@@ -113,7 +131,7 @@
private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
private int mResourceId;
- /** Return the underlying SPI held by this object */
+ /** Get the underlying SPI held by this object. */
public int getSpi() {
return mSpi;
}
@@ -135,6 +153,7 @@
mCloseGuard.close();
}
+ /** Check that the SPI was closed properly. */
@Override
protected void finalize() throws Throwable {
if (mCloseGuard != null) {
@@ -197,13 +216,13 @@
}
/**
- * Reserve an SPI for traffic bound towards the specified remote address.
+ * Reserve a random SPI for traffic bound to or from the specified remote address.
*
* <p>If successful, this SPI is guaranteed available until released by a call to {@link
* SecurityParameterIndex#close()}.
*
* @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
- * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
+ * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
* @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
* for this user
@@ -223,17 +242,18 @@
}
/**
- * Reserve an SPI for traffic bound towards the specified remote address.
+ * Reserve the requested SPI for traffic bound to or from the specified remote address.
*
* <p>If successful, this SPI is guaranteed available until released by a call to {@link
* SecurityParameterIndex#close()}.
*
* @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
- * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
- * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI
* @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
* for this user
+ * @throws SpiUnavailableException indicating that the requested SPI could not be reserved
*/
public SecurityParameterIndex reserveSecurityParameterIndex(
int direction, InetAddress remoteAddress, int requestedSpi)
@@ -245,16 +265,28 @@
}
/**
- * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
- * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
- * transform. For security reasons, attempts to send traffic to any IP address other than the
- * address associated with that transform will throw an IOException. In addition, if the
- * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
- * send() or receive() until the transform is removed from the socket by calling {@link
- * #removeTransportModeTransform(Socket, IpSecTransform)};
+ * Apply an IPsec transform to a stream socket.
+ *
+ * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+ * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+ * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+ * unprotected traffic can resume on that socket.
+ *
+ * <p>For security reasons, the destination address of any traffic on the socket must match the
+ * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+ * other IP address will result in an IOException. In addition, reads and writes on the socket
+ * will throw IOException if the user deactivates the transform (by calling {@link
+ * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+ *
+ * <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.
*
* @param socket a stream socket
- * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ * @param transform a transport mode {@code IpSecTransform}
+ * @throws IOException indicating that the transform could not be applied
* @hide
*/
public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -265,16 +297,28 @@
}
/**
- * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
- * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
- * transform. For security reasons, attempts to send traffic to any IP address other than the
- * address associated with that transform will throw an IOException. In addition, if the
- * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
- * send() or receive() until the transform is removed from the socket by calling {@link
- * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
+ * Apply an IPsec transform to a datagram socket.
+ *
+ * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+ * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+ * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+ * unprotected traffic can resume on that socket.
+ *
+ * <p>For security reasons, the destination address of any traffic on the socket must match the
+ * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+ * other IP address will result in an IOException. In addition, reads and writes on the socket
+ * will throw IOException if the user deactivates the transform (by calling {@link
+ * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+ *
+ * <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.
*
* @param socket a datagram socket
- * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ * @param transform a transport mode {@code IpSecTransform}
+ * @throws IOException indicating that the transform could not be applied
* @hide
*/
public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -285,16 +329,28 @@
}
/**
- * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
- * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
- * transform. For security reasons, attempts to send traffic to any IP address other than the
- * address associated with that transform will throw an IOException. In addition, if the
- * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
- * send() or receive() until the transform is removed from the socket by calling {@link
- * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
+ * Apply an IPsec transform to a socket.
+ *
+ * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+ * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+ * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+ * unprotected traffic can resume on that socket.
+ *
+ * <p>For security reasons, the destination address of any traffic on the socket must match the
+ * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+ * other IP address will result in an IOException. In addition, reads and writes on the socket
+ * will throw IOException if the user deactivates the transform (by calling {@link
+ * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+ *
+ * <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.
*
* @param socket a socket file descriptor
- * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ * @param transform a transport mode {@code IpSecTransform}
+ * @throws IOException indicating that the transform could not be applied
*/
public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
throws IOException {
@@ -323,6 +379,7 @@
* Applications should probably not use this API directly. Instead, they should use {@link
* VpnService} to provide VPN capability in a more generic fashion.
*
+ * 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
@@ -330,14 +387,19 @@
public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
/**
- * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
- * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
- * communication in the clear in the event socket reuse is desired. This operation will succeed
- * regardless of the underlying state of a transform. If a transform is removed, communication
- * on all sockets to which that transform was applied will fail until this method is called.
+ * Remove an IPsec transform from a stream socket.
*
- * @param socket a socket that previously had a transform applied to it.
+ * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+ * regardless of the state of the transform. Removing a transform from a socket allows the
+ * socket to be reused for communication in the clear.
+ *
+ * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+ * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+ * is called.
+ *
+ * @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket
+ * @throws IOException indicating that the transform could not be removed from the socket
* @hide
*/
public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -348,14 +410,19 @@
}
/**
- * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
- * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
- * communication in the clear in the event socket reuse is desired. This operation will succeed
- * regardless of the underlying state of a transform. If a transform is removed, communication
- * on all sockets to which that transform was applied will fail until this method is called.
+ * Remove an IPsec transform from a datagram socket.
*
- * @param socket a socket that previously had a transform applied to it.
+ * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+ * regardless of the state of the transform. Removing a transform from a socket allows the
+ * socket to be reused for communication in the clear.
+ *
+ * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+ * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+ * is called.
+ *
+ * @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket
+ * @throws IOException indicating that the transform could not be removed from the socket
* @hide
*/
public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -366,14 +433,19 @@
}
/**
- * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
- * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
- * communication in the clear in the event socket reuse is desired. This operation will succeed
- * regardless of the underlying state of a transform. If a transform is removed, communication
- * on all sockets to which that transform was applied will fail until this method is called.
+ * Remove an IPsec transform from a socket.
*
- * @param socket a socket file descriptor that previously had a transform applied to it.
+ * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+ * regardless of the state of the transform. Removing a transform from a socket allows the
+ * socket to be reused for communication in the clear.
+ *
+ * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+ * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+ * is called.
+ *
+ * @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket
+ * @throws IOException indicating that the transform could not be removed from the socket
*/
public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
throws IOException {
@@ -382,7 +454,7 @@
}
}
- /* Call down to activate a transform */
+ /* Call down to remove a transform */
private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
try {
mService.removeTransportModeTransform(pfd, transform.getResourceId());
@@ -397,6 +469,7 @@
* all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
* lost, all traffic will drop.
*
+ * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
* @param net a network that currently has transform applied to it.
* @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
* network
@@ -405,11 +478,18 @@
public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
/**
- * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
- * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+ * This class provides access to a UDP encapsulation Socket.
*
- * <p>The socket provided by this class cannot be re-bound or closed via the inner
- * FileDescriptor. Instead, disposing of this socket requires a call to close().
+ * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
+ * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
+ * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
+ * caller. The caller should not close the {@code FileDescriptor} returned by {@link
+ * #getSocket}, but should use {@link #close} instead.
+ *
+ * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
+ * of the next user who binds to that port. To prevent this scenario, these sockets are held
+ * open by the system so that they may only be closed by calling {@link #close} or when the user
+ * process exits.
*/
public static final class UdpEncapsulationSocket implements AutoCloseable {
private final ParcelFileDescriptor mPfd;
@@ -443,7 +523,7 @@
mCloseGuard.open("constructor");
}
- /** Access the inner UDP Encapsulation Socket */
+ /** Get the wrapped socket. */
public FileDescriptor getSocket() {
if (mPfd == null) {
return null;
@@ -451,22 +531,19 @@
return mPfd.getFileDescriptor();
}
- /** Retrieve the port number of the inner encapsulation socket */
+ /** Get the bound port of the wrapped socket. */
public int getPort() {
return mPort;
}
- @Override
/**
- * Release the resources that have been reserved for this Socket.
+ * Close this socket.
*
- * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
- * system. This must be done as part of cleanup following use of a socket. Failure to do so
- * will cause the socket to count against a total allocation limit for IpSec and eventually
- * fail due to resource limits.
- *
- * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+ * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
+ * resource limits, and forgetting to close them eventually will result in {@link
+ * ResourceUnavailableException} being thrown.
*/
+ @Override
public void close() throws IOException {
try {
mService.closeUdpEncapsulationSocket(mResourceId);
@@ -483,6 +560,7 @@
mCloseGuard.close();
}
+ /** Check that the socket was closed properly. */
@Override
protected void finalize() throws Throwable {
if (mCloseGuard != null) {
@@ -499,21 +577,14 @@
};
/**
- * Open a socket that is bound to a free UDP port on the system.
+ * Open a socket for UDP encapsulation and bind to the given port.
*
- * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
- * the caller. This provides safe access to a socket on a port that can later be used as a UDP
- * Encapsulation port.
+ * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
*
- * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
- * socket port. Explicitly opening this port is only necessary if communication is desired on
- * that port.
- *
- * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
- * method will bind to the specified port or fail. To retrieve the port number, call {@link
- * android.system.Os#getsockname(FileDescriptor)}.
- * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
- * of the object.
+ * @param port a local UDP port
+ * @return a socket that is bound to the given port
+ * @throws IOException indicating that the socket could not be opened or bound
+ * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
*/
// Returning a socket in this fashion that has been created and bound by the system
// is the only safe way to ensure that a socket is both accessible to the user and
@@ -533,17 +604,16 @@
}
/**
- * Open a socket that is bound to a port selected by the system.
+ * Open a socket for UDP encapsulation.
*
- * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
- * the caller. This provides safe access to a socket on a port that can later be used as a UDP
- * Encapsulation port.
+ * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
*
- * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
- * socket port. Explicitly opening this port is only necessary if communication is desired on
- * that port.
+ * <p>The local port of the returned socket can be obtained by calling {@link
+ * UdpEncapsulationSocket#getPort()}.
*
- * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+ * @return a socket that is bound to a local port
+ * @throws IOException indicating that the socket could not be opened or bound
+ * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
*/
// Returning a socket in this fashion that has been created and bound by the system
// is the only safe way to ensure that a socket is both accessible to the user and
@@ -556,7 +626,7 @@
}
/**
- * Retrieve an instance of an IpSecManager within you application context
+ * Construct an instance of IpSecManager within an application context.
*
* @param context the application context for this manager
* @hide
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 48b5bd5..cda4ec7 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -38,27 +38,29 @@
import java.net.InetAddress;
/**
- * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ * This class represents an IPsec transform, which comprises security associations in one or both
+ * directions.
*
- * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
- * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
- * transform may be disabled automatically, with likely undesirable results.
+ * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
+ * object encapsulates the properties and state of an inbound and outbound IPsec security
+ * association. That includes, but is not limited to, algorithm choice, key material, and allocated
+ * system resources.
*
- * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
- * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
*/
public final class IpSecTransform implements AutoCloseable {
private static final String TAG = "IpSecTransform";
/**
- * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
- * to traffic towards the host.
+ * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
+ * applies to traffic towards the host.
*/
public static final int DIRECTION_IN = 0;
/**
- * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
- * to traffic from the host.
+ * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
+ * applies to traffic from the host.
*/
public static final int DIRECTION_OUT = 1;
@@ -77,16 +79,16 @@
public static final int ENCAP_NONE = 0;
/**
- * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
- * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+ * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
+ * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
*
* @hide
*/
public static final int ENCAP_ESPINUDP_NON_IKE = 1;
/**
- * IpSec traffic will be encapsulated within UDP as per <a
- * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+ * IPsec traffic will be encapsulated within UDP as per
+ * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
*
* @hide
*/
@@ -165,13 +167,14 @@
}
/**
- * Deactivate an IpSecTransform and free all resources for that transform that are managed by
- * the system for this Transform.
+ * Deactivate this {@code IpSecTransform} and free allocated resources.
*
- * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
- * refusing to send or receive data. This method will silently succeed if the specified
- * transform has already been removed; thus, it is always safe to attempt cleanup when a
- * transform is no longer needed.
+ * <p>Deactivating a transform while it is still applied to a socket will result in errors on
+ * that socket. Make sure to remove transforms by calling {@link
+ * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a
+ * socket will not deactivate it (because one transform may be applied to multiple sockets).
+ *
+ * <p>It is safe to call this method on a transform that has already been deactivated.
*/
public void close() {
Log.d(TAG, "Removing Transform with Id " + mResourceId);
@@ -197,6 +200,7 @@
}
}
+ /** Check that the transform was closed properly. */
@Override
protected void finalize() throws Throwable {
if (mCloseGuard != null) {
@@ -264,65 +268,63 @@
}
/**
- * Builder object to facilitate the creation of IpSecTransform objects.
- *
- * <p>Apply additional properties to the transform and then call a build() method to return an
- * IpSecTransform object.
- *
- * @see Builder#buildTransportModeTransform(InetAddress)
+ * This class is used to build {@link IpSecTransform} objects.
*/
public static class Builder {
private Context mContext;
private IpSecConfig mConfig;
/**
- * Add an encryption algorithm to the transform for the given direction.
+ * Set the encryption algorithm for the given direction.
*
- * <p>If encryption is set for a given direction without also providing an SPI for that
- * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ * <p>If encryption is set for a direction without also providing an SPI for that direction,
+ * creation of an {@code IpSecTransform} will fail when attempting to build the transform.
*
- * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+ * <p>Encryption is mutually exclusive with authenticated encryption.
*
- * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
*/
public IpSecTransform.Builder setEncryption(
@TransformDirection int direction, IpSecAlgorithm algo) {
+ // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
mConfig.setEncryption(direction, algo);
return this;
}
/**
- * Add an authentication/integrity algorithm to the transform.
+ * Set the authentication (integrity) algorithm for the given direction.
*
- * <p>If authentication is set for a given direction without also providing an SPI for that
- * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ * <p>If authentication is set for a direction without also providing an SPI for that
+ * direction, creation of an {@code IpSecTransform} will fail when attempting to build the
+ * transform.
*
- * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+ * <p>Authentication is mutually exclusive with authenticated encryption.
*
- * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
*/
public IpSecTransform.Builder setAuthentication(
@TransformDirection int direction, IpSecAlgorithm algo) {
+ // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
mConfig.setAuthentication(direction, algo);
return this;
}
/**
- * Add an authenticated encryption algorithm to the transform for the given direction.
+ * Set the authenticated encryption algorithm for the given direction.
*
* <p>If an authenticated encryption algorithm is set for a given direction without also
- * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling
- * a build() method.
+ * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when
+ * attempting to build the transform.
*
* <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated
* Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as
- * referred to in RFC 4301)
+ * referred to in <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
*
* <p>Authenticated encryption is mutually exclusive with encryption and authentication.
*
- * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
* be applied.
*/
@@ -333,19 +335,16 @@
}
/**
- * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
- * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
- * given destination address.
+ * Set the SPI for the given direction.
*
- * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
- * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int,
- * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being
- * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}.
+ * <p>Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies
+ * packets to a given destination address. To prevent SPI collisions, values should be
+ * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}.
*
- * <p>Unless an SPI is set for a given direction, traffic in that direction will be
- * sent/received without any IPsec applied.
+ * <p>If the SPI and algorithms are omitted for one direction, traffic in that direction
+ * will not be encrypted or authenticated.
*
- * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
* traffic
*/
@@ -356,11 +355,10 @@
}
/**
- * Specify the network on which this transform will emit its traffic; (otherwise it will
- * emit on the default network).
+ * Set the {@link Network} which will carry tunneled traffic.
*
- * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
- * tunnel mode.
+ * <p>Restricts the transformed traffic to a particular {@link Network}. This is required
+ * for tunnel mode, otherwise tunneled traffic would be sent on the default network.
*
* @hide
*/
@@ -371,15 +369,18 @@
}
/**
- * Add UDP encapsulation to an IPv4 transform
+ * Add UDP encapsulation to an IPv4 transform.
*
- * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
- * details on how UDP should be applied to IPsec.
+ * <p>This allows IPsec traffic to pass through a NAT.
*
- * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
- * receiving encapsulating traffic.
- * @param remotePort the UDP port number of the remote that will send and receive
- * encapsulated traffic. In the case of IKE, this is likely port 4500.
+ * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
+ * ESP Packets</a>
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
+ * NAT Traversal of IKEv2</a>
+ *
+ * @param localSocket a socket for sending and receiving encapsulated traffic
+ * @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.
*/
public IpSecTransform.Builder setIpv4Encapsulation(
IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
@@ -393,12 +394,15 @@
// TODO: Probably a better exception to throw for NATTKeepalive failure
// TODO: Specify the needed NATT keepalive permission.
/**
- * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
- * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
- * be activated, then the transform will fail to activate and throw an IOException.
+ * Set NAT-T keepalives to be sent with a given interval.
*
- * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
- * than 20s and no more than 3600s.
+ * <p>This will set power-efficient keepalive packets to be sent by the system. If NAT-T
+ * keepalive is requested but cannot be activated, then creation of an {@link
+ * IpSecTransform} will fail when calling the build method.
+ *
+ * @param intervalSeconds the maximum number of seconds between keepalive packets. Must be
+ * between 20s and 3600s.
+ *
* @hide
*/
@SystemApi
@@ -408,36 +412,29 @@
}
/**
- * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
- * Some parameters have interdependencies that are checked at build time. If a well-formed
- * transform cannot be created from the supplied parameters, this method will throw an
- * Exception.
+ * Build a transport mode {@link IpSecTransform}.
*
- * <p>Upon a successful return from this call, the provided IpSecTransform will be active
- * and may be applied to sockets. If too many IpSecTransform objects are active for a given
- * user this operation will fail and throw ResourceUnavailableException. To avoid these
- * exceptions, unused Transform objects must be cleaned up by calling {@link
- * IpSecTransform#close()} when they are no longer needed.
+ * <p>This builds and activates a transport mode transform. Note that an active transform
+ * will not affect any network traffic until it has been applied to one or more sockets.
*
- * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
- * socket will cause the transform to be applied.
- * <p>Note that an active transform will not impact any network traffic until it has
- * been applied to one or more Sockets. Calling this method is a necessary precondition
- * for applying it to a socket, but is not sufficient to actually apply IPsec.
+ * @see IpSecManager#applyTransportModeTransform
+ *
+ * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use
+ * this transform
* @throws IllegalArgumentException indicating that a particular combination of transform
- * properties is invalid.
- * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
- * may be allocated
- * @throws SpiUnavailableException if the SPI collides with an existing transform
- * (unlikely).
- * @throws ResourceUnavailableException if the current user currently has exceeded the
- * number of allowed active transforms.
+ * properties is invalid
+ * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are
+ * active
+ * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
+ * collides with an existing transform
+ * @throws IOException indicating other errors
*/
public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
mConfig.setMode(MODE_TRANSPORT);
mConfig.setRemoteAddress(remoteAddress.getHostAddress());
+ // FIXME: modifying a builder after calling build can change the built transform.
return new IpSecTransform(mContext, mConfig).activate();
}
@@ -465,9 +462,9 @@
}
/**
- * Create a new IpSecTransform.Builder to construct an IpSecTransform
+ * Create a new IpSecTransform.Builder.
*
- * @param context current Context
+ * @param context current context
*/
public Builder(@NonNull Context context) {
Preconditions.checkNotNull(context);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ee75fd4..f468e5d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -31,16 +31,10 @@
import java.util.StringJoiner;
/**
- * Representation of the capabilities of a network. This object serves two
- * purposes:
- * <ul>
- * <li>An expression of the current capabilities of an active network, typically
- * expressed through
+ * Representation of the capabilities of an active network. Instances are
+ * typically obtained through
* {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
* or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
- * <li>An expression of the future capabilities of a desired network, typically
- * expressed through {@link NetworkRequest}.
- * </ul>
* <p>
* This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
* network selection. Rather than indicate a need for Wi-Fi because an
@@ -79,7 +73,7 @@
*/
public void clearAll() {
mNetworkCapabilities = mTransportTypes = 0;
- mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
+ mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
}
@@ -359,6 +353,7 @@
/**
* Sets all the capabilities set on this {@code NetworkCapability} instance.
+ * This overwrites any existing capabilities.
*
* @hide
*/
@@ -582,6 +577,7 @@
/**
* Sets all the transports set on this {@code NetworkCapability} instance.
+ * This overwrites any existing transports.
*
* @hide
*/
@@ -780,7 +776,7 @@
* Signal strength. This is a signed integer, and higher values indicate better signal.
* The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
*/
- private int mSignalStrength;
+ private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
/**
* Sets the signal strength. This is a signed integer, with higher values indicating a stronger
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 25b1705..97ded2d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -32,7 +33,7 @@
* The {@link NetworkCapabilities} that define this request.
* @hide
*/
- public final NetworkCapabilities networkCapabilities;
+ public final @NonNull NetworkCapabilities networkCapabilities;
/**
* Identifies the request. NetworkRequests should only be constructed by
@@ -307,7 +308,7 @@
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(networkCapabilities, flags);
+ networkCapabilities.writeToParcel(dest, flags);
dest.writeInt(legacyType);
dest.writeInt(requestId);
dest.writeString(type.name());
@@ -315,7 +316,7 @@
public static final Creator<NetworkRequest> CREATOR =
new Creator<NetworkRequest>() {
public NetworkRequest createFromParcel(Parcel in) {
- NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
+ NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
int legacyType = in.readInt();
int requestId = in.readInt();
Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid.
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 95e3802..b00cb48 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Slog;
/**
* Snapshot of network state.
@@ -43,6 +44,16 @@
this.network = network;
this.subscriberId = subscriberId;
this.networkId = networkId;
+
+ // This object is an atomic view of a network, so the various components
+ // should always agree on roaming state.
+ if (networkInfo != null && networkCapabilities != null) {
+ if (networkInfo.isRoaming() == networkCapabilities
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
+ Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ + " and " + networkCapabilities);
+ }
+ }
}
public NetworkState(Parcel in) {
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
index 8f1a5c4..af9a73c 100644
--- a/core/java/android/net/metrics/WakeupEvent.java
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -29,7 +29,7 @@
public String iface;
public int uid;
public int ethertype;
- public byte[] dstHwAddr;
+ public MacAddress dstHwAddr;
public String srcIp;
public String dstIp;
public int ipNextHeader;
@@ -44,7 +44,7 @@
j.add(iface);
j.add("uid: " + Integer.toString(uid));
j.add("eth=0x" + Integer.toHexString(ethertype));
- j.add("dstHw=" + MacAddress.stringAddrFromByteAddr(dstHwAddr));
+ j.add("dstHw=" + dstHwAddr);
if (ipNextHeader > 0) {
j.add("ipNxtHdr=" + ipNextHeader);
j.add("srcIp=" + srcIp);
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index 1ba9777..23c1f20 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -16,7 +16,6 @@
package android.net.metrics;
-import android.net.MacAddress;
import android.os.Process;
import android.os.SystemClock;
import android.util.SparseIntArray;
@@ -80,7 +79,7 @@
break;
}
- switch (MacAddress.macAddressType(ev.dstHwAddr)) {
+ switch (ev.dstHwAddr.addressType()) {
case UNICAST:
l2UnicastCount++;
break;
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 3544ea1..a080c8d 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -179,4 +179,9 @@
}
return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
}
+
+ /**
+ * Return PID of process if sharable to clients.
+ */
+ public static native int getPidIfSharable();
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index e426356..6746120 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,10 @@
* DO NOT MOVE - UserManager.h depends on the ordering of this function.
*/
int getCredentialOwnerProfile(int userHandle);
+ int getProfileParentId(int userHandle);
+ /*
+ * END OF DO NOT MOVE
+ */
UserInfo createUser(in String name, int flags);
UserInfo createProfileForUser(in String name, int flags, int userHandle,
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b5d62e5..0874d93 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -151,6 +151,9 @@
*/
public static final int OTA_UPDATE_UID = 1061;
+ /** {@hide} */
+ public static final int NOBODY_UID = 9999;
+
/**
* Defines the start of a range of UIDs (and GIDs), going from this
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 2281fb6..b9b9a18 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -19,6 +19,7 @@
import android.util.ArrayMap;
import android.util.Slog;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -399,6 +400,13 @@
}
}
+ /** @hide */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
+ pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
+ pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
+ }
+
private void logExcessiveCallbacks() {
final long size = mCallbacks.size();
final long TOO_MANY = 3000;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d230d2d..6560a8f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -194,6 +194,24 @@
"android.settings.AIRPLANE_MODE_SETTINGS";
/**
+ * Activity Action: Show mobile data usage list.
+ * <p>
+ * Input: {@link EXTRA_NETWORK_TEMPLATE} and {@link EXTRA_SUB_ID} should be included to specify
+ * how and what mobile data statistics should be collected.
+ * <p>
+ * Output: Nothing
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MOBILE_DATA_USAGE =
+ "android.settings.MOBILE_DATA_USAGE";
+
+ /** @hide */
+ public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+ /** @hide */
+ public static final String EXTRA_SUB_ID = "sub_id";
+
+ /**
* Activity Action: Modify Airplane mode settings using a voice command.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
@@ -9206,6 +9224,9 @@
/** {@hide} */
public static final String
BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
+ /** {@hide} */
+ public static final String
+ BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
/**
* Activity manager specific settings.
@@ -9527,6 +9548,14 @@
}
/**
+ * Get the key that retrieves a bluetooth hearing aid priority.
+ * @hide
+ */
+ public static final String getBluetoothHearingAidPriorityKey(String address) {
+ return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+ }
+
+ /**
* Get the key that retrieves a bluetooth map priority.
* @hide
*/
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index af26a88..21b72f3 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -530,7 +530,7 @@
* axis distances. Warning: this fudge factor is finely tuned, be sure to
* run all focus tests if you dare tweak it.
*/
- int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
+ long getWeightedDistanceFor(long majorAxisDistance, long minorAxisDistance) {
return 13 * majorAxisDistance * majorAxisDistance
+ minorAxisDistance * minorAxisDistance;
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c123a80..15c18ac 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -51,6 +51,9 @@
import java.util.List;
import java.util.Objects;
+// TODO: use java.lang.ref.Cleaner once Android supports Java 9
+import sun.misc.Cleaner;
+
/**
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
* Autofill Framework lifecycle.
@@ -225,6 +228,9 @@
private IAutoFillManagerClient mServiceClient;
@GuardedBy("mLock")
+ private Cleaner mServiceClientCleaner;
+
+ @GuardedBy("mLock")
private AutofillCallback mCallback;
private final Context mContext;
@@ -958,10 +964,19 @@
if (mServiceClient == null) {
mServiceClient = new AutofillManagerClient(this);
try {
- final int flags = mService.addClient(mServiceClient, mContext.getUserId());
+ final int userId = mContext.getUserId();
+ final int flags = mService.addClient(mServiceClient, userId);
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
+ final IAutoFillManager service = mService;
+ final IAutoFillManagerClient serviceClient = mServiceClient;
+ mServiceClientCleaner = Cleaner.create(this, () -> {
+ try {
+ service.removeClient(serviceClient, userId);
+ } catch (RemoteException e) {
+ }
+ });
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1068,6 +1083,10 @@
if (resetClient) {
// Reset connection to system
mServiceClient = null;
+ if (mServiceClientCleaner != null) {
+ mServiceClientCleaner.clean();
+ mServiceClientCleaner = null;
+ }
}
}
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 627afa7..7f2c080 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,6 +32,7 @@
interface IAutoFillManager {
// Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
int addClient(in IAutoFillManagerClient client, int userId);
+ void removeClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
String packageName);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index bc86ddd..ec51659 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -77,6 +77,7 @@
"android_text_StaticLayout.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
+ "android_os_HidlSupport.cpp",
"android_os_HwBinder.cpp",
"android_os_HwBlob.cpp",
"android_os_HwParcel.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8b6fc59..6bc6f63 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -154,6 +154,7 @@
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_os_Debug(JNIEnv* env);
extern int register_android_os_GraphicsEnvironment(JNIEnv* env);
+extern int register_android_os_HidlSupport(JNIEnv* env);
extern int register_android_os_HwBinder(JNIEnv *env);
extern int register_android_os_HwBlob(JNIEnv *env);
extern int register_android_os_HwParcel(JNIEnv *env);
@@ -1325,6 +1326,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
REG_JNI(register_android_os_HwBlob),
REG_JNI(register_android_os_HwParcel),
diff --git a/core/jni/android_os_HidlSupport.cpp b/core/jni/android_os_HidlSupport.cpp
new file mode 100644
index 0000000..e3602d8
--- /dev/null
+++ b/core/jni/android_os_HidlSupport.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hidl/HidlTransportSupport.h>
+#include <nativehelper/JNIHelp.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+static jint android_os_HidlSupport_getPidIfSharable(JNIEnv*, jclass) {
+ return android::hardware::details::getPidIfSharable();
+}
+
+static const JNINativeMethod gHidlSupportMethods[] = {
+ {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable},
+};
+
+const char* const kHidlSupportPathName = "android/os/HidlSupport";
+
+int register_android_os_HidlSupport(JNIEnv* env)
+{
+ return RegisterMethodsOrDie(env, kHidlSupportPathName, gHidlSupportMethods, NELEM(gHidlSupportMethods));
+}
+
+} // namespace android
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index fa645f4..ef6eb09 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -254,6 +254,7 @@
SettingProto bluetooth_pbap_client_priority_prefix = 209;
SettingProto bluetooth_sap_priority_prefix = 210;
SettingProto bluetooth_pan_priority_prefix = 211;
+ SettingProto bluetooth_hearing_aid_priority_prefix = 345;
SettingProto device_idle_constants = 212;
SettingProto device_idle_constants_watch = 213;
SettingProto app_idle_constants = 214;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a979ac8..9edaffe 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -121,6 +121,7 @@
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+ Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
Settings.Global.BOOT_COUNT,
Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 92b6aa3..a79376c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -147,6 +147,7 @@
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 7b2fa76..76eb4e6 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -112,14 +112,29 @@
# Run sanity tests on fonts on checkbuild
checkbuild: fontchain_lint
-FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+FONTCHAIN_LINTER := $(HOST_OUT_EXECUTABLES)/fontchain_linter
ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
CHECK_EMOJI := false
else
CHECK_EMOJI := true
endif
+fontchain_lint_timestamp := $(call intermediates-dir-for,PACKAGING,fontchain_lint)/stamp
+
.PHONY: fontchain_lint
-fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img
- PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
- python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
+fontchain_lint: $(fontchain_lint_timestamp)
+
+fontchain_lint_deps := \
+ external/unicode/DerivedAge.txt \
+ external/unicode/emoji-data.txt \
+ external/unicode/emoji-sequences.txt \
+ external/unicode/emoji-variation-sequences.txt \
+ external/unicode/emoji-zwj-sequences.txt \
+ external/unicode/additions/emoji-data.txt \
+ external/unicode/additions/emoji-sequences.txt \
+ external/unicode/additions/emoji-zwj-sequences.txt \
+
+$(fontchain_lint_timestamp): $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img $(fontchain_lint_deps)
+ @echo Running fontchain lint
+ $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
+ touch $@
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index bdc0fda..31eb948 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -34,6 +34,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
+import java.util.Objects;
/**
* Contains metadata about an item, such as the title, artist, etc.
@@ -616,6 +617,71 @@
};
/**
+ * Compares the contents of this object to another MediaMetadata object. It
+ * does not compare Bitmaps and Ratings as the media player can choose to
+ * forgo these fields depending on how you retrieve the MediaMetadata.
+ *
+ * @param o The Metadata object to compare this object against
+ * @return Whether or not the two objects have matching fields (excluding
+ * Bitmaps and Ratings)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof MediaMetadata)) {
+ return false;
+ }
+
+ final MediaMetadata m = (MediaMetadata) o;
+
+ for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+ String key = METADATA_KEYS_TYPE.keyAt(i);
+ switch (METADATA_KEYS_TYPE.valueAt(i)) {
+ case METADATA_TYPE_TEXT:
+ if (!Objects.equals(getString(key), m.getString(key))) {
+ return false;
+ }
+ break;
+ case METADATA_TYPE_LONG:
+ if (getLong(key) != m.getLong(key)) {
+ return false;
+ }
+ break;
+ default:
+ // Ignore ratings and bitmaps when comparing
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 17;
+
+ for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+ String key = METADATA_KEYS_TYPE.keyAt(i);
+ switch (METADATA_KEYS_TYPE.valueAt(i)) {
+ case METADATA_TYPE_TEXT:
+ hashCode = 31 * hashCode + Objects.hash(getString(key));
+ break;
+ case METADATA_TYPE_LONG:
+ hashCode = 31 * hashCode + Long.hashCode(getLong(key));
+ break;
+ default:
+ // Ignore ratings and bitmaps when comparing
+ break;
+ }
+ }
+
+ return hashCode;
+ }
+
+ /**
* Use to build MediaMetadata objects. The system defined metadata keys must
* use the appropriate data type.
*/
diff --git a/packages/SettingsLib/res/drawable/ic_expand_more.xml b/packages/SettingsLib/res/drawable/ic_expand_more.xml
new file mode 100644
index 0000000..a8ff539
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_expand_more.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z"/>
+
+</vector>
diff --git a/packages/SettingsLib/res/layout/preference_category_divider.xml b/packages/SettingsLib/res/layout/preference_category_divider.xml
new file mode 100644
index 0000000..6644eec
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_category_divider.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/two_target_divider"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal">
+ <View
+ android:layout_height="1dp"
+ android:layout_width="match_parent"
+ android:background="?android:attr/dividerHorizontal" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml b/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
new file mode 100644
index 0000000..70d0898
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<!-- Similar to preference_category_material_settings.xml, except that this always adds
+ a divider above category. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/preference_category_divider"/>
+ <include layout="@layout/preference_category_material_settings"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 819ee3e..d256b12 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -720,6 +720,9 @@
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
dumpSetting(s, p,
+ Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
+ GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX);
+ dumpSetting(s, p,
Settings.Global.DEVICE_IDLE_CONSTANTS,
GlobalSettingsProto.DEVICE_IDLE_CONSTANTS);
dumpSetting(s, p,
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index a4849fc..0e2c46b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4221,6 +4221,16 @@
// ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
+ // ACTION: Settings > Network & Internet > Mobile network > Mobile data
+ // CATEGORY: SETTINGS
+ // OS: O MR
+ ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE = 1081;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Data usage
+ // CATEGORY: SETTINGS
+ // OS: O MR
+ ACTION_MOBILE_NETWORK_DATA_USAGE = 1082;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index cb91f93..e37347a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -499,6 +499,16 @@
}
@Override
+ public void removeClient(IAutoFillManagerClient client, int userId) {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.removeClientLocked(client);
+ }
+ }
+ }
+
+ @Override
public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
int userId) {
synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 751c054..5c63b90 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -261,6 +261,12 @@
return isEnabled();
}
+ void removeClientLocked(IAutoFillManagerClient client) {
+ if (mClients != null) {
+ mClients.unregister(client);
+ }
+ }
+
void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
if (!isEnabled()) {
return;
@@ -478,6 +484,10 @@
}
sendStateToClients(true);
+ if (mClients != null) {
+ mClients.kill();
+ mClients = null;
+ }
}
CharSequence getServiceLabel() {
@@ -605,6 +615,9 @@
}
}
+ pw.print(prefix); pw.println("Clients");
+ mClients.dump(pw, prefix2);
+
if (mEventHistory == null || mEventHistory.getEvents() == null
|| mEventHistory.getEvents().size() == 0) {
pw.print(prefix); pw.println("No event on last fill response");
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 75206e4..c34c30c 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -195,6 +195,7 @@
private LinkedList<ActiveLog> mActiveLogs;
private LinkedList<Long> mCrashTimestamps;
private int mCrashes;
+ private long mLastEnabledTime;
// configuration from external IBinder call which is used to
// synchronize with broadcast receiver.
@@ -2021,6 +2022,7 @@
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
quietMode ? 1 : 0, 0));
addActiveLog(packageName, true);
+ mLastEnabledTime = SystemClock.elapsedRealtime();
}
private void addActiveLog(String packageName, boolean enable) {
@@ -2142,7 +2144,7 @@
writer.println(" address: " + mAddress);
writer.println(" name: " + mName);
if (mEnable) {
- long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime();
+ long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
String onDurationString = String.format("%02d:%02d:%02d.%03d",
(int)(onDuration / (1000 * 60 * 60)),
(int)((onDuration / (1000 * 60)) % 60),
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 664c2ab..ce19a1c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5605,7 +5605,8 @@
}
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
- mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
+ int[] transports = nai.networkCapabilities.getTransportTypes();
+ mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
}
private static boolean toBool(int encodedBoolean) {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 4bdbbe3..6f2d77f 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetdEventCallback;
+import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.metrics.ConnectStats;
@@ -242,7 +243,7 @@
event.timestampMs = timestampMs;
event.uid = uid;
event.ethertype = ethertype;
- event.dstHwAddr = dstHw;
+ event.dstHwAddr = new MacAddress(dstHw);
event.srcIp = srcIp;
event.dstIp = dstIp;
event.ipNextHeader = ipNextHeader;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 401eb62..bf1c4c3 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -154,7 +154,13 @@
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
final List<String> paths = pkg.getAllCodePaths();
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+ int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ if (sharedGid == -1) {
+ Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
+ + pkg.applicationInfo.uid, new Throwable());
+ sharedGid = android.os.Process.NOBODY_UID;
+ }
// Get the class loader context dependencies.
// For each code path in the package, this array contains the class loader context that
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8853aa0..93d8894 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3463,7 +3463,7 @@
final int N = list.size();
for (int i = 0; i < N; i++) {
ResolveInfo info = list.get(i);
- if (packageName.equals(info.activityInfo.packageName)) {
+ if (info.priority >= 0 && packageName.equals(info.activityInfo.packageName)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 10ceba4..0ec61df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -476,11 +476,17 @@
}
List<String> failedPackages = new ArrayList<>();
+ int index = 0;
for (String packageName : packageNames) {
if (clearProfileData) {
mInterface.clearApplicationProfileData(packageName);
}
+ if (allPackages) {
+ pw.println(++index + "/" + packageNames.size() + ": " + packageName);
+ pw.flush();
+ }
+
boolean result = secondaryDex
? mInterface.performDexOptSecondary(packageName,
targetCompilerFilter, forceCompilation)
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 132b845..62f4a30 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -714,6 +714,19 @@
}
}
+ @Override
+ public int getProfileParentId(int userHandle) {
+ checkManageUsersPermission("get the profile parent");
+ synchronized (mUsersLock) {
+ UserInfo profileParent = getProfileParentLU(userHandle);
+ if (profileParent == null) {
+ return userHandle;
+ }
+
+ return profileParent.id;
+ }
+ }
+
private UserInfo getProfileParentLU(int userHandle) {
UserInfo profile = getUserInfoLU(userHandle);
if (profile == null) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e8e0680..f81c89a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -856,6 +856,39 @@
*/
public static abstract class Callback {
/**
+ * @hide
+ */
+ @IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
+ HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HandoverFailureErrors {}
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
+ * to handover the call rejects handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there is
+ * an error associated with unsupported handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+ * are some permission errors associated with APIs doing handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when user
+ * rejects handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+
+
+ /**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
*
* @param call The {@code Call} invoking this method.
@@ -990,6 +1023,21 @@
* {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
public void onRttInitiationFailure(Call call, int reason) {}
+
+ /**
+ * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+ * has completed successfully.
+ * @param call The call which had initiated handover.
+ */
+ public void onHandoverComplete(Call call) {}
+
+ /**
+ * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+ * has failed.
+ * @param call The call which had initiated handover.
+ * @param failureReason Error reason for failure
+ */
+ public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
}
/**
@@ -1366,6 +1414,24 @@
}
/**
+ * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+ * by {@code toHandle}. The videoState specified indicates the desired video state after the
+ * handover.
+ * <p>
+ * A handover request is initiated by the user from one app to indicate a desire
+ * to handover a call to another.
+ *
+ * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
+ * this call to.
+ * @param videoState Indicates the video state desired after the handover.
+ * @param extras Bundle containing extra information to be passed to the
+ * {@link ConnectionService}
+ */
+ public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
+ mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
+ }
+
+ /**
* Terminate the RTT session on this call. The resulting state change will be notified via
* the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 35804f6..da8ac5e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2033,6 +2033,43 @@
}
/**
+ * Called by Telecom on the initiating side of the handover to create an instance of a
+ * handover connection.
+ * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+ * ConnectionService which needs to handover the call.
+ * @param request Details about the call which needs to be handover.
+ * @return Connection object corresponding to the handover call.
+ */
+ public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+ ConnectionRequest request) {
+ return null;
+ }
+
+ /**
+ * Called by Telecom on the receiving side of the handover to request the
+ * {@link ConnectionService} to create an instance of a handover connection.
+ * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+ * ConnectionService which needs to handover the call.
+ * @param request Details about the call which needs to be handover.
+ * @return {@link Connection} object corresponding to the handover call.
+ */
+ public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+ ConnectionRequest request) {
+ return null;
+ }
+
+ /**
+ * Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
+ * invocation which failed.
+ * @param request Details about the call which needs to be handover.
+ * @param error Reason for handover failure as defined in
+ * {@link android.telecom.Call.Callback#HANDOVER_FAILURE_DEST_INVALID_PERM}
+ */
+ public void onHandoverFailed(ConnectionRequest request, int error) {
+ return;
+ }
+
+ /**
* Create a {@code Connection} for a new unknown call. An unknown call is a call originating
* from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming
* call created using
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 9bf0467..4bc2a9b 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -435,4 +435,21 @@
} catch (RemoteException ignored) {
}
}
+
+
+ /**
+ * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+ * by destAcct.
+ * @param callId The callId of the Call which calls this function.
+ * @param destAcct ConnectionService to which the call should be handed over.
+ * @param videoState The video state desired after the handover.
+ * @param extras Extra information to be passed to ConnectionService
+ */
+ public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
+ Bundle extras) {
+ try {
+ mAdapter.handoverTo(callId, destAcct, videoState, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 691e7cf..74b9465 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -86,13 +86,11 @@
/**
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
- * connection (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) to this
- * {@link PhoneAccount} from a {@link PhoneAccount} specifying
- * {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
+ * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from
+ * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
* <p>
* A handover request is initiated by the user from the default dialer app to indicate a desire
* to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
- * @hide
*/
public static final String EXTRA_SUPPORTS_HANDOVER_TO =
"android.telecom.extra.SUPPORTS_HANDOVER_TO";
@@ -113,12 +111,11 @@
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
* connection from this {@link PhoneAccount} to another {@link PhoneAccount}.
- * (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) which specifies
+ * (see {@code android.telecom.Call#handoverTo()}) which specifies
* {@link #EXTRA_SUPPORTS_HANDOVER_TO}.
* <p>
* A handover request is initiated by the user from the default dialer app to indicate a desire
* to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
- * @hide
*/
public static final String EXTRA_SUPPORTS_HANDOVER_FROM =
"android.telecom.extra.SUPPORTS_HANDOVER_FROM";
@@ -132,7 +129,6 @@
* <p>
* By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log.
* Setting this extra to {@code true} provides a means for them to log their calls.
- * @hide
*/
public static final String EXTRA_LOG_SELF_MANAGED_CALLS =
"android.telecom.extra.LOG_SELF_MANAGED_CALLS";
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f30d7bd..05480dc 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1065,7 +1065,7 @@
*
* @param state The audio state of this {@code RemoteConnection}.
* @hide
- * @deprecated Use {@link #setCallAudioState(CallAudioState) instead.
+ * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead.
*/
@SystemApi
@Deprecated
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index aa2323d..4d2cb04 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1749,6 +1749,41 @@
return false;
}
+ /**
+ * Called from the recipient side of a handover to indicate a desire to accept the handover
+ * of an ongoing call to another {@link ConnectionService} identified by
+ * {@link PhoneAccountHandle} destAcct. For managed {@link ConnectionService}s, the specified
+ * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+ * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
+ * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+ * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to handover a call to it.
+ * <p>
+ * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+ * associated with the {@link PhoneAccountHandle} destAcct and call
+ * (See {@link ConnectionService#onCreateIncomingHandoverConnection}).
+ * <p>
+ * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+ * the {@link PhoneAccountHandle} destAcct does not correspond to a registered
+ * {@link PhoneAccount} or the associated {@link PhoneAccount} is not currently enabled by the
+ * user.
+ * <p>
+ * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
+ * the calling app does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
+ *
+ * @param srcAddr The {@link android.net.Uri} of the ongoing call to handover to the caller’s
+ * {@link ConnectionService}.
+ * @param videoState Video state after the handover.
+ * @param destAcct The {@link PhoneAccountHandle} registered to the calling package.
+ */
+ public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
+ try {
+ if (isServiceConnected()) {
+ getTelecomService().acceptHandover(srcAddr, videoState, destAcct);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException acceptHandover: " + e);
+ }
+ }
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index bce3392..23ac940 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -77,4 +77,7 @@
void stopRtt(String callId);
void setRttMode(String callId, int mode);
+
+ void handoverTo(String callId, in PhoneAccountHandle destAcct, int videoState,
+ in Bundle extras);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 8ebac2c..3460754 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -274,4 +274,9 @@
* @see TelecomServiceImpl#waitOnHandler
*/
void waitOnHandlers();
+
+ /**
+ * @see TelecomServiceImpl#acceptHandover
+ */
+ void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
}
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 4d7c71f..c968406 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -101,9 +101,6 @@
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
*
- * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
- * not a 2 or 3-digit code.
- *
* @hide
*/
public CellIdentityGsm (int lac, int cid, int arfcn, int bsic, String mccStr,
@@ -122,7 +119,10 @@
// If the mccStr is empty or unknown, set it as null.
mMccStr = null;
} else {
- throw new IllegalArgumentException("invalid MCC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+ // after the bug got fixed.
+ mMccStr = null;
+ log("invalid MCC format: " + mccStr);
}
if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -131,7 +131,10 @@
// If the mncStr is empty or unknown, set it as null.
mMncStr = null;
} else {
- throw new IllegalArgumentException("invalid MNC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+ // after the bug got fixed.
+ mMncStr = null;
+ log("invalid MNC format: " + mncStr);
}
mAlphaLong = alphal;
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index fd837fc..825dcc3 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -102,9 +102,6 @@
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
*
- * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
- * not a 2 or 3-digit code.
- *
* @hide
*/
public CellIdentityLte (int ci, int pci, int tac, int earfcn, String mccStr,
@@ -121,7 +118,10 @@
// If the mccStr is empty or unknown, set it as null.
mMccStr = null;
} else {
- throw new IllegalArgumentException("invalid MCC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+ // after the bug got fixed.
+ mMccStr = null;
+ log("invalid MCC format: " + mccStr);
}
if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -130,7 +130,10 @@
// If the mncStr is empty or unknown, set it as null.
mMncStr = null;
} else {
- throw new IllegalArgumentException("invalid MNC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+ // after the bug got fixed.
+ mMncStr = null;
+ log("invalid MNC format: " + mncStr);
}
mAlphaLong = alphal;
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 1597245..e74b570 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -102,9 +102,6 @@
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
*
- * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
- * not a 2 or 3-digit code.
- *
* @hide
*/
public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
@@ -121,7 +118,10 @@
// If the mccStr is empty or unknown, set it as null.
mMccStr = null;
} else {
- throw new IllegalArgumentException("invalid MCC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+ // after the bug got fixed.
+ mMccStr = null;
+ log("invalid MCC format: " + mccStr);
}
if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -130,13 +130,16 @@
// If the mncStr is empty or unknown, set it as null.
mMncStr = null;
} else {
- throw new IllegalArgumentException("invalid MNC format");
+ // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+ // after the bug got fixed.
+ mMncStr = null;
+ log("invalid MNC format: " + mncStr);
}
mAlphaLong = alphal;
mAlphaShort = alphas;
}
-
+
private CellIdentityWcdma(CellIdentityWcdma cid) {
this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0d1764b..d2fd097 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -26,6 +26,7 @@
import android.content.res.Resources;
import android.net.Uri;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -408,7 +409,15 @@
* for #onSubscriptionsChanged to be invoked.
*/
public static class OnSubscriptionsChangedListener {
- private final Handler mHandler = new Handler() {
+ private class OnSubscriptionsChangedListenerHandler extends Handler {
+ OnSubscriptionsChangedListenerHandler() {
+ super();
+ }
+
+ OnSubscriptionsChangedListenerHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
if (DBG) {
@@ -416,7 +425,22 @@
}
OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
}
- };
+ }
+
+ private final Handler mHandler;
+
+ public OnSubscriptionsChangedListener() {
+ mHandler = new OnSubscriptionsChangedListenerHandler();
+ }
+
+ /**
+ * Allow a listener to be created with a custom looper
+ * @param looper the looper that the underlining handler should run on
+ * @hide
+ */
+ public OnSubscriptionsChangedListener(Looper looper) {
+ mHandler = new OnSubscriptionsChangedListenerHandler(looper);
+ }
/**
* Callback invoked when there is any change to any SubscriptionInfo. Typically
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f461910..6b26dbb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -52,8 +52,9 @@
import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
@@ -407,9 +408,12 @@
* Open the voicemail settings activity to make changes to voicemail configuration.
*
* <p>
+ * The {@link #EXTRA_PHONE_ACCOUNT_HANDLE} extra indicates which {@link PhoneAccountHandle} to
+ * configure voicemail.
* The {@link #EXTRA_HIDE_PUBLIC_SETTINGS} hides settings the dialer will modify through public
* API if set.
*
+ * @see #EXTRA_PHONE_ACCOUNT_HANDLE
* @see #EXTRA_HIDE_PUBLIC_SETTINGS
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -771,8 +775,9 @@
"android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
/**
- * The extra used with an {@link #ACTION_SHOW_VOICEMAIL_NOTIFICATION} {@code Intent} to specify
- * the {@link PhoneAccountHandle} the notification is for.
+ * The extra used with an {@link #ACTION_CONFIGURE_VOICEMAIL} and
+ * {@link #ACTION_SHOW_VOICEMAIL_NOTIFICATION} {@code Intent} to specify the
+ * {@link PhoneAccountHandle} the configuration or notification is for.
* <p class="note">
* Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
*/
@@ -4584,27 +4589,78 @@
public @interface Feature {}
/**
- * Returns the {@link IImsServiceController} that corresponds to the given slot Id and IMS
- * feature or {@link null} if the service is not available. If an ImsServiceController is
- * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
- * feature updates.
- * @param slotIndex The SIM slot that we are requesting the {@link IImsServiceController} for.
- * @param feature The IMS Feature we are requesting, corresponding to {@link ImsFeature}.
+ * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id and MMTel
+ * feature or {@link null} if the service is not available. If an MMTelFeature is available, the
+ * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
+ * @param slotIndex The SIM slot that we are requesting the {@link IImsMMTelFeature} for.
* @param callback Listener that will send updates to ImsManager when there are updates to
* ImsServiceController.
- * @return {@link IImsServiceController} interface for the feature specified or {@link null} if
+ * @return {@link IImsMMTelFeature} interface for the feature specified or {@code null} if
* it is unavailable.
* @hide
*/
- public IImsServiceController getImsServiceControllerAndListen(int slotIndex, @Feature int feature,
- IImsServiceFeatureListener callback) {
+ public @Nullable IImsMMTelFeature getImsMMTelFeatureAndListen(int slotIndex,
+ IImsServiceFeatureCallback callback) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getImsServiceControllerAndListen(slotIndex, feature, callback);
+ return telephony.getMMTelFeatureAndListen(slotIndex, callback);
}
} catch (RemoteException e) {
- Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage());
+ Rlog.e(TAG, "getImsMMTelFeatureAndListen, RemoteException: "
+ + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id and MMTel
+ * feature for emergency calling or {@link null} if the service is not available. If an
+ * MMTelFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+ * listener for feature updates.
+ * @param slotIndex The SIM slot that we are requesting the {@link IImsMMTelFeature} for.
+ * @param callback Listener that will send updates to ImsManager when there are updates to
+ * ImsServiceController.
+ * @return {@link IImsMMTelFeature} interface for the feature specified or {@code null} if
+ * it is unavailable.
+ * @hide
+ */
+ public @Nullable IImsMMTelFeature getImsEmergencyMMTelFeatureAndListen(int slotIndex,
+ IImsServiceFeatureCallback callback) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getEmergencyMMTelFeatureAndListen(slotIndex, callback);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "getImsEmergencyMMTelFeatureAndListen, RemoteException: "
+ + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id and RCS
+ * feature for emergency calling or {@link null} if the service is not available. If an
+ * RcsFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+ * listener for feature updates.
+ * @param slotIndex The SIM slot that we are requesting the {@link IImsRcsFeature} for.
+ * @param callback Listener that will send updates to ImsManager when there are updates to
+ * ImsServiceController.
+ * @return {@link IImsRcsFeature} interface for the feature specified or {@code null} if
+ * it is unavailable.
+ * @hide
+ */
+ public @Nullable IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex,
+ IImsServiceFeatureCallback callback) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getRcsFeatureAndListen(slotIndex, callback);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "getImsRcsFeatureAndListen, RemoteException: "
+ + e.getMessage());
}
return null;
}
diff --git a/telephony/java/android/telephony/data/DataProfile.aidl b/telephony/java/android/telephony/data/DataProfile.aidl
new file mode 100644
index 0000000..65fdf91
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataProfile.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable DataProfile;
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
new file mode 100644
index 0000000..41c1430
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * Description of a mobile data profile used for establishing
+ * data connections.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DataProfile implements Parcelable {
+
+ // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network.
+ public static final int TYPE_COMMON = 0;
+ public static final int TYPE_3GPP = 1;
+ public static final int TYPE_3GPP2 = 2;
+
+ private final int mProfileId;
+
+ private final String mApn;
+
+ private final String mProtocol;
+
+ private final int mAuthType;
+
+ private final String mUserName;
+
+ private final String mPassword;
+
+ private final int mType;
+
+ private final int mMaxConnsTime;
+
+ private final int mMaxConns;
+
+ private final int mWaitTime;
+
+ private final boolean mEnabled;
+
+ private final int mSupportedApnTypesBitmap;
+
+ private final String mRoamingProtocol;
+
+ private final int mBearerBitmap;
+
+ private final int mMtu;
+
+ private final String mMvnoType;
+
+ private final String mMvnoMatchData;
+
+ private final boolean mModemCognitive;
+
+ public DataProfile(int profileId, String apn, String protocol, int authType,
+ String userName, String password, int type, int maxConnsTime, int maxConns,
+ int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+ int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
+ boolean modemCognitive) {
+
+ this.mProfileId = profileId;
+ this.mApn = apn;
+ this.mProtocol = protocol;
+ if (authType == -1) {
+ authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
+ : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
+ }
+ this.mAuthType = authType;
+ this.mUserName = userName;
+ this.mPassword = password;
+ this.mType = type;
+ this.mMaxConnsTime = maxConnsTime;
+ this.mMaxConns = maxConns;
+ this.mWaitTime = waitTime;
+ this.mEnabled = enabled;
+
+ this.mSupportedApnTypesBitmap = supportedApnTypesBitmap;
+ this.mRoamingProtocol = roamingProtocol;
+ this.mBearerBitmap = bearerBitmap;
+ this.mMtu = mtu;
+ this.mMvnoType = mvnoType;
+ this.mMvnoMatchData = mvnoMatchData;
+ this.mModemCognitive = modemCognitive;
+ }
+
+ public DataProfile(Parcel source) {
+ mProfileId = source.readInt();
+ mApn = source.readString();
+ mProtocol = source.readString();
+ mAuthType = source.readInt();
+ mUserName = source.readString();
+ mPassword = source.readString();
+ mType = source.readInt();
+ mMaxConnsTime = source.readInt();
+ mMaxConns = source.readInt();
+ mWaitTime = source.readInt();
+ mEnabled = source.readBoolean();
+ mSupportedApnTypesBitmap = source.readInt();
+ mRoamingProtocol = source.readString();
+ mBearerBitmap = source.readInt();
+ mMtu = source.readInt();
+ mMvnoType = source.readString();
+ mMvnoMatchData = source.readString();
+ mModemCognitive = source.readBoolean();
+ }
+
+ /**
+ * @return Id of the data profile.
+ */
+ public int getProfileId() { return mProfileId; }
+
+ /**
+ * @return The APN to establish data connection.
+ */
+ public String getApn() { return mApn; }
+
+ /**
+ * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
+ * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ */
+ public String getProtocol() { return mProtocol; }
+
+ /**
+ * @return The authentication protocol used for this PDP context
+ * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+ */
+ public int getAuthType() { return mAuthType; }
+
+ /**
+ * @return The username for APN. Can be null.
+ */
+ public String getUserName() { return mUserName; }
+
+ /**
+ * @return The password for APN. Can be null.
+ */
+ public String getPassword() { return mPassword; }
+
+ /**
+ * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2.
+ */
+ public int getType() { return mType; }
+
+ /**
+ * @return The period in seconds to limit the maximum connections.
+ */
+ public int getMaxConnsTime() { return mMaxConnsTime; }
+
+ /**
+ * @return The maximum connections allowed.
+ */
+ public int getMaxConns() { return mMaxConns; }
+
+ /**
+ * @return The required wait time in seconds after a successful UE initiated disconnect of a
+ * given PDN connection before the device can send a new PDN connection request for that given
+ * PDN.
+ */
+ public int getWaitTime() { return mWaitTime; }
+
+ /**
+ * @return True if the profile is enabled.
+ */
+ public boolean isEnabled() { return mEnabled; }
+
+ /**
+ * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit.
+ */
+ public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
+
+ /**
+ * @return The connection protocol on roaming network, should be one of the PDP_type values in
+ * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ */
+ public String getRoamingProtocol() { return mRoamingProtocol; }
+
+ /**
+ * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit.
+ */
+ public int getBearerBitmap() { return mBearerBitmap; }
+
+ /**
+ * @return The maximum transmission unit (MTU) size in bytes.
+ */
+ public int getMtu() { return mMtu; }
+
+ /**
+ * @return The MVNO type: possible values are "imsi", "gid", "spn".
+ */
+ public String getMvnoType() { return mMvnoType; }
+
+ /**
+ * @return The MVNO match data. For example,
+ * SPN: A MOBILE, BEN NL, ...
+ * IMSI: 302720x94, 2060188, ...
+ * GID: 4E, 33, ...
+ */
+ public String getMvnoMatchData() { return mMvnoMatchData; }
+
+ /**
+ * @return True if the data profile was sent to the modem through setDataProfile earlier.
+ */
+ public boolean isModemCognitive() { return mModemCognitive; }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType
+ + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime
+ + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
+ + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
+ + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof DataProfile == false) return false;
+ return (o == this || toString().equals(o.toString()));
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mProfileId);
+ dest.writeString(mApn);
+ dest.writeString(mProtocol);
+ dest.writeInt(mAuthType);
+ dest.writeString(mUserName);
+ dest.writeString(mPassword);
+ dest.writeInt(mType);
+ dest.writeInt(mMaxConnsTime);
+ dest.writeInt(mMaxConns);
+ dest.writeInt(mWaitTime);
+ dest.writeBoolean(mEnabled);
+ dest.writeInt(mSupportedApnTypesBitmap);
+ dest.writeString(mRoamingProtocol);
+ dest.writeInt(mBearerBitmap);
+ dest.writeInt(mMtu);
+ dest.writeString(mMvnoType);
+ dest.writeString(mMvnoMatchData);
+ dest.writeBoolean(mModemCognitive);
+ }
+
+ public static final Parcelable.Creator<DataProfile> CREATOR =
+ new Parcelable.Creator<DataProfile>() {
+ @Override
+ public DataProfile createFromParcel(Parcel source) {
+ return new DataProfile(source);
+ }
+
+ @Override
+ public DataProfile[] newArray(int size) {
+ return new DataProfile[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 9d91cc3..8230eaf 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -16,13 +16,11 @@
package android.telephony.ims;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.IBinder;
-import android.os.Message;
import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.ims.feature.ImsFeature;
@@ -31,22 +29,13 @@
import android.util.Log;
import android.util.SparseArray;
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsFeatureStatusCallback;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
-import com.android.ims.internal.IImsUt;
import com.android.internal.annotations.VisibleForTesting;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -92,247 +81,38 @@
*/
public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
- // A map of slot Id -> Set of features corresponding to that slot.
- private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
+ // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that
+ // slot.
+ // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and
+ // call ImsFeature#onFeatureRemoved.
+ private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
/**
* @hide
*/
- // Implements all supported features as a flat interface.
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
@Override
- public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+ public IImsMMTelFeature createEmergencyMMTelFeature(int slotId,
+ IImsFeatureStatusCallback c) {
+ return createEmergencyMMTelFeatureInternal(slotId, c);
+ }
+
+ @Override
+ public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) {
+ return createMMTelFeatureInternal(slotId, c);
+ }
+
+ @Override
+ public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
+ return createRcsFeatureInternal(slotId, c);
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c)
throws RemoteException {
- synchronized (mFeatures) {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
- onCreateImsFeatureInternal(slotId, feature, c);
- }
+ ImsService.this.removeImsFeature(slotId, featureType, c);
}
-
- @Override
- public void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
- throws RemoteException {
- synchronized (mFeatures) {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
- onRemoveImsFeatureInternal(slotId, feature, c);
- }
- }
-
- @Override
- public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
- IImsRegistrationListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.startSession(incomingCallIntent, listener);
- }
- }
- return 0;
- }
-
- @Override
- public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
- synchronized (mFeatures) {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.endSession(sessionId);
- }
- }
- }
-
- @Override
- public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
- throws RemoteException {
- enforceReadPhoneStatePermission("isConnected");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.isConnected(callSessionType, callType);
- }
- }
- return false;
- }
-
- @Override
- public boolean isOpened(int slotId, int featureType) throws RemoteException {
- enforceReadPhoneStatePermission("isOpened");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.isOpened();
- }
- }
- return false;
- }
-
- @Override
- public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
- enforceReadPhoneStatePermission("getFeatureStatus");
- int status = ImsFeature.STATE_NOT_AVAILABLE;
- synchronized (mFeatures) {
- SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
- if (featureMap != null) {
- ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
- if (feature != null) {
- status = feature.getFeatureState();
- }
- }
- }
- return status;
- }
-
- @Override
- public void addRegistrationListener(int slotId, int featureType,
- IImsRegistrationListener listener) throws RemoteException {
- enforceReadPhoneStatePermission("addRegistrationListener");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.addRegistrationListener(listener);
- }
- }
- }
-
- @Override
- public void removeRegistrationListener(int slotId, int featureType,
- IImsRegistrationListener listener) throws RemoteException {
- enforceReadPhoneStatePermission("removeRegistrationListener");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.removeRegistrationListener(listener);
- }
- }
- }
-
- @Override
- public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
- int callSessionType, int callType) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.createCallProfile(sessionId, callSessionType, callType);
- }
- }
- return null;
- }
-
- @Override
- public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
- ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.createCallSession(sessionId, profile, listener);
- }
- }
- return null;
- }
-
- @Override
- public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
- String callId) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.getPendingCallSession(sessionId, callId);
- }
- }
- return null;
- }
-
- @Override
- public IImsUt getUtInterface(int slotId, int featureType)
- throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.getUtInterface();
- }
- }
- return null;
- }
-
- @Override
- public IImsConfig getConfigInterface(int slotId, int featureType)
- throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.getConfigInterface();
- }
- }
- return null;
- }
-
- @Override
- public void turnOnIms(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.turnOnIms();
- }
- }
- }
-
- @Override
- public void turnOffIms(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.turnOffIms();
- }
- }
- }
-
- @Override
- public IImsEcbm getEcbmInterface(int slotId, int featureType)
- throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.getEcbmInterface();
- }
- }
- return null;
- }
-
- @Override
- public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
- throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- feature.setUiTTYMode(uiTtyMode, onComplete);
- }
- }
- }
-
- @Override
- public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
- throws RemoteException {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
- synchronized (mFeatures) {
- MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
- if (feature != null) {
- return feature.getMultiEndpointInterface();
- }
- }
- return null;
- }
-
};
/**
@@ -341,127 +121,93 @@
@Override
public IBinder onBind(Intent intent) {
if(SERVICE_INTERFACE.equals(intent.getAction())) {
+ Log.i(LOG_TAG, "ImsService Bound.");
return mImsServiceController;
}
return null;
}
/**
- * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
- * featureType
- * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
- * @param featureType An integer representing the type of ImsFeature being created. This is
- * defined in {@link ImsFeature}.
+ * @hide
*/
- // Be sure to lock on mFeatures before accessing this method
- private void onCreateImsFeatureInternal(int slotId, int featureType,
+ @VisibleForTesting
+ public SparseArray<ImsFeature> getFeatures(int slotId) {
+ return mFeaturesBySlot.get(slotId);
+ }
+
+ private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId,
IImsFeatureStatusCallback c) {
- SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
- if (featureMap == null) {
- featureMap = new SparseArray<>();
- mFeatures.put(slotId, featureMap);
- }
- ImsFeature f = makeImsFeature(slotId, featureType);
+ MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId);
if (f != null) {
- f.setContext(this);
- f.setSlotId(slotId);
- f.addImsFeatureStatusCallback(c);
- featureMap.put(featureType, f);
- }
-
- }
- /**
- * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
- * featureType.
- * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
- * @param featureType An integer representing the type of ImsFeature being removed. This is
- * defined in {@link ImsFeature}.
- */
- // Be sure to lock on mFeatures before accessing this method
- private void onRemoveImsFeatureInternal(int slotId, int featureType,
- IImsFeatureStatusCallback c) {
- SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
- if (featureMap == null) {
- return;
- }
-
- ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
- if (featureToRemove != null) {
- featureMap.remove(featureType);
- featureToRemove.notifyFeatureRemoved(slotId);
- // Remove reference to Binder
- featureToRemove.removeImsFeatureStatusCallback(c);
- }
- }
-
- // Be sure to lock on mFeatures before accessing this method
- private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
- SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
- MMTelFeature feature = null;
- if (features != null) {
- feature = resolveImsFeature(features, featureType, MMTelFeature.class);
- }
- return feature;
- }
-
- // Be sure to lock on mFeatures before accessing this method
- private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
- Class<T> className) {
- ImsFeature feature = getImsFeatureFromType(set, featureType);
- if (feature == null) {
+ setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c);
+ return f.getBinder();
+ } else {
return null;
}
- try {
- return className.cast(feature);
- } catch (ClassCastException e)
- {
- Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
+ }
+
+ private IImsMMTelFeature createMMTelFeatureInternal(int slotId,
+ IImsFeatureStatusCallback c) {
+ MMTelFeature f = onCreateMMTelImsFeature(slotId);
+ if (f != null) {
+ setupFeature(f, slotId, ImsFeature.MMTEL, c);
+ return f.getBinder();
+ } else {
+ return null;
}
- return null;
}
- /**
- * @hide
- */
- @VisibleForTesting
- // Be sure to lock on mFeatures before accessing this method
- public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
- return mFeatures.get(slotId);
- }
-
- /**
- * @hide
- */
- @VisibleForTesting
- // Be sure to lock on mFeatures before accessing this method
- public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
- return set.get(featureType);
- }
-
- private ImsFeature makeImsFeature(int slotId, int feature) {
- switch (feature) {
- case ImsFeature.EMERGENCY_MMTEL: {
- return onCreateEmergencyMMTelImsFeature(slotId);
- }
- case ImsFeature.MMTEL: {
- return onCreateMMTelImsFeature(slotId);
- }
- case ImsFeature.RCS: {
- return onCreateRcsFeature(slotId);
- }
+ private IImsRcsFeature createRcsFeatureInternal(int slotId,
+ IImsFeatureStatusCallback c) {
+ RcsFeature f = onCreateRcsFeature(slotId);
+ if (f != null) {
+ setupFeature(f, slotId, ImsFeature.RCS, c);
+ return f.getBinder();
+ } else {
+ return null;
}
- // Tried to create feature that is not defined.
- return null;
}
- /**
- * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
- * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
- */
- private void enforceReadPhoneStatePermission(String fn) {
- if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ private void setupFeature(ImsFeature f, int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ f.setContext(this);
+ f.setSlotId(slotId);
+ f.addImsFeatureStatusCallback(c);
+ addImsFeature(slotId, featureType, f);
+ }
+
+ private void addImsFeature(int slotId, int featureType, ImsFeature f) {
+ synchronized (mFeaturesBySlot) {
+ // Get SparseArray for Features, by querying slot Id
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ // Populate new SparseArray of features if it doesn't exist for this slot yet.
+ features = new SparseArray<>();
+ mFeaturesBySlot.put(slotId, features);
+ }
+ features.put(featureType, f);
+ }
+ }
+
+ private void removeImsFeature(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
+ + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type "
+ + featureType + " exists on slot " + slotId);
+ return;
+ }
+ f.removeImsFeatureStatusCallback(c);
+ f.onFeatureRemoved();
+ features.remove(featureType);
}
}
@@ -470,7 +216,7 @@
* functionality. Must be able to handle emergency calls at any time as well.
* @hide
*/
- public MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
+ public @Nullable MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
return null;
}
@@ -479,7 +225,7 @@
* functionality.
* @hide
*/
- public MMTelFeature onCreateMMTelImsFeature(int slotId) {
+ public @Nullable MMTelFeature onCreateMMTelImsFeature(int slotId) {
return null;
}
@@ -487,7 +233,7 @@
* @return An implementation of RcsFeature that will be used by the system for RCS.
* @hide
*/
- public RcsFeature onCreateRcsFeature(int slotId) {
+ public @Nullable RcsFeature onCreateRcsFeature(int slotId) {
return null;
}
}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 9d880b7..062858d 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.content.Context;
import android.content.Intent;
+import android.os.IInterface;
import android.os.RemoteException;
import android.telephony.SubscriptionManager;
import android.util.Log;
@@ -91,17 +92,12 @@
public static final int STATE_INITIALIZING = 1;
public static final int STATE_READY = 2;
- private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
private @ImsState int mState = STATE_NOT_AVAILABLE;
private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
private Context mContext;
- public interface INotifyFeatureRemoved {
- void onFeatureRemoved(int slotId);
- }
-
public void setContext(Context context) {
mContext = context;
}
@@ -110,26 +106,6 @@
mSlotId = slotId;
}
- public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
- synchronized (mRemovedListeners) {
- mRemovedListeners.add(listener);
- }
- }
-
- public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
- synchronized (mRemovedListeners) {
- mRemovedListeners.remove(listener);
- }
- }
-
- // Not final for testing.
- public void notifyFeatureRemoved(int slotId) {
- synchronized (mRemovedListeners) {
- mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
- onFeatureRemoved();
- }
- }
-
public int getFeatureState() {
return mState;
}
@@ -215,4 +191,9 @@
* Called when the feature is being removed and must be cleaned up.
*/
public abstract void onFeatureRemoved();
+
+ /**
+ * @return Binder instance
+ */
+ public abstract IInterface getBinder();
}
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
index 758c379..e790d14 100644
--- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -18,18 +18,18 @@
import android.app.PendingIntent;
import android.os.Message;
+import android.os.RemoteException;
import com.android.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMMTelFeature;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsUt;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.android.ims.internal.ImsCallSession;
/**
* Base implementation for MMTel.
@@ -41,6 +41,146 @@
public class MMTelFeature extends ImsFeature {
+ // Lock for feature synchronization
+ private final Object mLock = new Object();
+
+ private final IImsMMTelFeature mImsMMTelBinder = new IImsMMTelFeature.Stub() {
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent,
+ IImsRegistrationListener listener) throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.startSession(incomingCallIntent, listener);
+ }
+ }
+
+ @Override
+ public void endSession(int sessionId) throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.endSession(sessionId);
+ }
+ }
+
+ @Override
+ public boolean isConnected(int callSessionType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.isConnected(callSessionType, callType);
+ }
+ }
+
+ @Override
+ public boolean isOpened() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.isOpened();
+ }
+ }
+
+ @Override
+ public int getFeatureStatus() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getFeatureState();
+ }
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.addRegistrationListener(listener);
+ }
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.removeRegistrationListener(listener);
+ }
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.createCallProfile(sessionId, callSessionType, callType);
+ }
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.createCallSession(sessionId, profile, listener);
+ }
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId)
+ throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getPendingCallSession(sessionId, callId);
+ }
+ }
+
+ @Override
+ public IImsUt getUtInterface() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getUtInterface();
+ }
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getConfigInterface();
+ }
+ }
+
+ @Override
+ public void turnOnIms() throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.turnOnIms();
+ }
+ }
+
+ @Override
+ public void turnOffIms() throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.turnOffIms();
+ }
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getEcbmInterface();
+ }
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException {
+ synchronized (mLock) {
+ MMTelFeature.this.setUiTTYMode(uiTtyMode, onComplete);
+ }
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+ synchronized (mLock) {
+ return MMTelFeature.this.getMultiEndpointInterface();
+ }
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ public final IImsMMTelFeature getBinder() {
+ return mImsMMTelBinder;
+ }
+
/**
* Notifies the MMTel feature that you would like to start a session. This should always be
* done before making/receiving IMS calls. The IMS service will register the device to the
@@ -135,7 +275,7 @@
}
/**
- * Creates a {@link ImsCallSession} with the specified call profile.
+ * Creates an {@link ImsCallSession} with the specified call profile.
* Use other methods, if applicable, instead of interacting with
* {@link ImsCallSession} directly.
*
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 332cca3..a82e608 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -16,6 +16,8 @@
package android.telephony.ims.feature;
+import com.android.ims.internal.IImsRcsFeature;
+
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
* this class and provide implementations of the RcsFeature methods that they support.
@@ -24,6 +26,11 @@
public class RcsFeature extends ImsFeature {
+ private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() {
+ // Empty Default Implementation.
+ };
+
+
public RcsFeature() {
super();
}
@@ -32,4 +39,9 @@
public void onFeatureRemoved() {
}
+
+ @Override
+ public final IImsRcsFeature getBinder() {
+ return mImsRcsBinder;
+ }
}
diff --git a/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl b/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl
new file mode 100644
index 0000000..52b3853
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.ims.internal;
+
+import android.app.PendingIntent;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import android.os.Message;
+
+/**
+ * See MMTelFeature for more information.
+ * {@hide}
+ */
+interface IImsMMTelFeature {
+ int startSession(in PendingIntent incomingCallIntent,
+ in IImsRegistrationListener listener);
+ void endSession(int sessionId);
+ boolean isConnected(int callSessionType, int callType);
+ boolean isOpened();
+ int getFeatureStatus();
+ void addRegistrationListener(in IImsRegistrationListener listener);
+ void removeRegistrationListener(in IImsRegistrationListener listener);
+ ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType);
+ IImsCallSession createCallSession(int sessionId, in ImsCallProfile profile,
+ IImsCallSessionListener listener);
+ IImsCallSession getPendingCallSession(int sessionId, String callId);
+ IImsUt getUtInterface();
+ IImsConfig getConfigInterface();
+ void turnOnIms();
+ void turnOffIms();
+ IImsEcbm getEcbmInterface();
+ void setUiTTYMode(int uiTtyMode, in Message onComplete);
+ IImsMultiEndpoint getMultiEndpointInterface();
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
similarity index 65%
copy from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
copy to telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
index df10700..b1cb23b 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
@@ -17,12 +17,9 @@
package com.android.ims.internal;
/**
- * Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ * See RcsFeature for more information.
* {@hide}
*/
-oneway interface IImsServiceFeatureListener {
- void imsFeatureCreated(int slotId, int feature);
- void imsFeatureRemoved(int slotId, int feature);
- void imsStatusChanged(int slotId, int feature, int status);
+interface IImsRcsFeature {
+ //Empty Default Implementation
}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index f1e2262..857089f 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -16,49 +16,17 @@
package com.android.ims.internal;
-import android.app.PendingIntent;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsFeatureStatusCallback;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsUt;
-
-import android.os.Message;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
/**
* See ImsService and MMTelFeature for more information.
* {@hide}
*/
interface IImsServiceController {
- // ImsService Control
- void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
- void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
- // MMTel Feature
- int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
- in IImsRegistrationListener listener);
- void endSession(int slotId, int featureType, int sessionId);
- boolean isConnected(int slotId, int featureType, int callSessionType, int callType);
- boolean isOpened(int slotId, int featureType);
- int getFeatureStatus(int slotId, int featureType);
- void addRegistrationListener(int slotId, int featureType, in IImsRegistrationListener listener);
- void removeRegistrationListener(int slotId, int featureType,
- in IImsRegistrationListener listener);
- ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
- int callSessionType, int callType);
- IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
- in ImsCallProfile profile, IImsCallSessionListener listener);
- IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
- String callId);
- IImsUt getUtInterface(int slotId, int featureType);
- IImsConfig getConfigInterface(int slotId, int featureType);
- void turnOnIms(int slotId, int featureType);
- void turnOffIms(int slotId, int featureType);
- IImsEcbm getEcbmInterface(int slotId, int featureType);
- void setUiTTYMode(int slotId, int featureType, int uiTtyMode, in Message onComplete);
- IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType);
+ IImsMMTelFeature createEmergencyMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
+ IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
+ IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
+ void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
similarity index 95%
rename from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
rename to telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
index df10700..9a9cf53 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
@@ -21,7 +21,7 @@
* Callback to ImsManager when a feature changes in the ImsServiceController.
* {@hide}
*/
-oneway interface IImsServiceFeatureListener {
+oneway interface IImsServiceFeatureCallback {
void imsFeatureCreated(int slotId, int feature);
void imsFeatureRemoved(int slotId, int feature);
void imsStatusChanged(int slotId, int feature, int status);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3cc9bde..fd6091a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -38,8 +38,9 @@
import android.telephony.SignalStrength;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.OperatorInfo;
@@ -784,12 +785,27 @@
int getTetherApnRequired();
/**
- * Get ImsServiceController binder from ImsResolver that corresponds to the subId and feature
- * requested as well as registering the ImsServiceController for callbacks using the
- * IImsServiceFeatureListener interface.
+ * Get IImsMMTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
+ * as well as registering the MMTelFeature for callbacks using the IImsServiceFeatureCallback
+ * interface.
*/
- IImsServiceController getImsServiceControllerAndListen(int slotIndex, int feature,
- IImsServiceFeatureListener callback);
+ IImsMMTelFeature getMMTelFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
+
+ /**
+ * Get IImsMMTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
+ * as well as registering the MMTelFeature for callbacks using the IImsServiceFeatureCallback
+ * interface.
+ * Used for emergency calling only.
+ */
+ IImsMMTelFeature getEmergencyMMTelFeatureAndListen(int slotId,
+ in IImsServiceFeatureCallback callback);
+
+ /**
+ * Get IImsRcsFeature binder from ImsResolver that corresponds to the subId and RCS feature
+ * as well as registering the RcsFeature for callbacks using the IImsServiceFeatureCallback
+ * interface.
+ */
+ IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
/**
* Set the network selection mode to automatic.
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 7b07038..8e579aa 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -23,7 +23,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
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.verify;
import static org.mockito.Mockito.when;
@@ -46,6 +50,8 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +63,8 @@
public class IpSecServiceTest {
private static final int DROID_SPI = 0xD1201D;
+ private static final int MAX_NUM_ENCAP_SOCKETS = 100;
+ private static final int MAX_NUM_SPIS = 100;
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
@@ -260,4 +268,115 @@
}
}
}
+
+ /**
+ * This function checks if the number of encap UDP socket that one UID can reserve
+ * has a reasonable limit.
+ */
+ @Test
+ public void testSocketResourceTrackerLimitation() throws Exception {
+ List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
+ // Reserve sockets until it fails.
+ for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
+ IpSecUdpEncapResponse newUdpEncapSocket =
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(newUdpEncapSocket);
+ if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
+ break;
+ }
+ openUdpEncapSockets.add(newUdpEncapSocket);
+ }
+ // Assert that the total sockets quota has a reasonable limit.
+ assertTrue(
+ openUdpEncapSockets.size() > 0
+ && openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
+
+ // Try to reserve one more UDP encapsulation socket, and should fail.
+ IpSecUdpEncapResponse extraUdpEncapSocket =
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(extraUdpEncapSocket);
+ assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
+
+ // Close one of the open UDP encapsulation scokets.
+ mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
+ openUdpEncapSockets.get(0).fileDescriptor.close();
+ openUdpEncapSockets.remove(0);
+
+ // Try to reserve one more UDP encapsulation socket, and should be successful.
+ extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(extraUdpEncapSocket);
+ assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
+ openUdpEncapSockets.add(extraUdpEncapSocket);
+
+ // Close open UDP sockets.
+ for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
+ mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
+ openSocket.fileDescriptor.close();
+ }
+ }
+
+ /**
+ * This function checks if the number of SPI that one UID can reserve
+ * has a reasonable limit.
+ * This test does not test for both address families or duplicate SPIs because resource
+ * tracking code does not depend on them.
+ */
+ @Test
+ public void testSpiResourceTrackerLimitation() throws Exception {
+ List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
+ // Return the same SPI for all SPI allocation since IpSecService only
+ // tracks the resource ID.
+ when(mMockNetd.ipSecAllocateSpi(
+ anyInt(),
+ eq(IpSecTransform.DIRECTION_OUT),
+ anyString(),
+ eq(InetAddress.getLoopbackAddress().getHostAddress()),
+ anyInt()))
+ .thenReturn(DROID_SPI);
+ // Reserve spis until it fails.
+ for (int i = 0; i < MAX_NUM_SPIS; i++) {
+ IpSecSpiResponse newSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + i,
+ new Binder());
+ assertNotNull(newSpi);
+ if (IpSecManager.Status.OK != newSpi.status) {
+ break;
+ }
+ reservedSpis.add(newSpi);
+ }
+ // Assert that the SPI quota has a reasonable limit.
+ assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
+
+ // Try to reserve one more SPI, and should fail.
+ IpSecSpiResponse extraSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + MAX_NUM_SPIS,
+ new Binder());
+ assertNotNull(extraSpi);
+ assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
+
+ // Release one reserved spi.
+ mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
+ reservedSpis.remove(0);
+
+ // Should successfully reserve one more spi.
+ extraSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + MAX_NUM_SPIS,
+ new Binder());
+ assertNotNull(extraSpi);
+ assertEquals(IpSecManager.Status.OK, extraSpi.status);
+
+ // Release reserved SPIs.
+ for (IpSecSpiResponse spiResp : reservedSpis) {
+ mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
+ }
+ }
}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_linter.py
similarity index 100%
rename from tools/fonts/fontchain_lint.py
rename to tools/fonts/fontchain_linter.py
diff --git a/vr/Android.mk b/vr/Android.mk
index 5b65d3f..73e9f23 100644
--- a/vr/Android.mk
+++ b/vr/Android.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE := libdvr_loader
LOCAL_MODULE_OWNER := google
LOCAL_SRC_FILES := dvr_library_loader.cpp
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_SHARED_LIBRARY)
# Java platform library for vr stuff.