diff options
78 files changed, 2009 insertions, 726 deletions
diff --git a/Android.bp b/Android.bp index 7d75f62ee183..1f4c59a407ed 100644 --- a/Android.bp +++ b/Android.bp @@ -102,3 +102,29 @@ java_library { 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 dd5379309234..c61227fc1edb 100644 --- a/Android.mk +++ b/Android.mk @@ -519,10 +519,12 @@ LOCAL_SRC_FILES += \ 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 @@ aidl_files := \ 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 4dbbfaa45a15..2b9e3721286e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25529,7 +25529,6 @@ package android.net { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { } 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 9bce26584e89..1620e6561c56 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -27725,7 +27725,6 @@ package android.net { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { } 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.cdma { } +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 7534e9f9d618..33d96a7b6e6b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -38894,6 +38894,7 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { 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 @@ package android.telecom { } 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 66e762c0558b..955e58ed933b 100644 --- a/cmds/webview_zygote/Android.mk +++ b/cmds/webview_zygote/Android.mk @@ -21,6 +21,8 @@ LOCAL_MODULE := webview_zygote 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 17156e841f3e..384540a910bd 100644 --- a/config/compiled-classes-phone +++ b/config/compiled-classes-phone @@ -5194,7 +5194,7 @@ com.android.ims.internal.IImsRegistrationListener$Stub 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 8c78ccbf2345..0d89c6f6cb07 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4344,7 +4344,7 @@ public class Activity extends ContextThemeWrapper 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 063ad24cd947..aab7d77315f3 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -23,16 +23,19 @@ import android.os.Looper; 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.Set; 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 @@ final class SharedPreferencesImpl implements SharedPreferences { private boolean mLoaded = false; @GuardedBy("mLock") - private long mStatTimestamp; + private StructTimespec mStatTimestamp; @GuardedBy("mLock") private long mStatSize; @@ -162,7 +163,7 @@ final class SharedPreferencesImpl implements SharedPreferences { 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 @@ final class SharedPreferencesImpl implements SharedPreferences { } 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 @@ final class SharedPreferencesImpl implements SharedPreferences { 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 e3d763ab9b1e..6692e137fa0a 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -350,13 +350,22 @@ public final class BluetoothHidDevice implements BluetoothProfile { * 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 @@ public final class BluetoothHidDevice implements BluetoothProfile { * {@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 @@ public final class BluetoothHidDevice implements BluetoothProfile { * @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 @@ public final class BluetoothHidDevice implements BluetoothProfile { * @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 @@ public final class BluetoothHidDevice implements BluetoothProfile { * 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 @@ public final class BluetoothHidDevice implements BluetoothProfile { } /** - * 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 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** * 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 ccc3ef4008fa..881ae98d9889 100644 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java @@ -45,6 +45,21 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable { 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 final class BluetoothHidDeviceAppQosSettings implements Parcelable { 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 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable { 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 f01c49328968..4669637043af 100644 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java @@ -19,6 +19,8 @@ package android.bluetooth; 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 class BluetoothHidDeviceAppSdpSettings implements Parcelable { 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 final class BluetoothHidDeviceAppSdpSettings implements Parcelable { 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 64f8f39e2bca..d6e62cf1f88d 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.lang.annotation.RetentionPolicy; 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 final class IpSecAlgorithm implements Parcelable { 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 final class IpSecAlgorithm implements Parcelable { 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 @@ public final class IpSecAlgorithm implements Parcelable { * * <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 @@ public final class IpSecAlgorithm implements Parcelable { 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. + * + * <p>This constructor only supports algorithms that use a truncation length. i.e. + * Authentication and Authenticated Encryption algorithms. * - * @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). + * @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 61b13a922dd4..e6cd3fc130a0 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -20,7 +20,12 @@ import android.os.Parcelable; 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 @@ public final class IpSecConfig implements Parcelable { // 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 eccd5f47f2dd..a9e60ec88a8e 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; 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.InetAddress; 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 final class IpSecManager { 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 @@ public final class IpSecManager { * 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 @@ public final class IpSecManager { 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 @@ public final class IpSecManager { 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 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the SPI was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -197,13 +216,13 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { * 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 final class IpSecManager { 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. + * + * <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 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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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. + * + * <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. * - * @param socket a socket file descriptor that previously had a transform applied to it. + * <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 @@ public final class IpSecManager { } } - /* 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 @@ public final class IpSecManager { * 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 final class IpSecManager { 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 @@ public final class IpSecManager { 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 @@ public final class IpSecManager { 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 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the socket was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -499,21 +577,14 @@ public final class IpSecManager { }; /** - * Open a socket that is bound to a free UDP port on the system. - * - * <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. + * Open a socket for UDP encapsulation and bind to the given port. * - * <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>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. * - * @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 @@ public final class IpSecManager { } /** - * 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 @@ public final class IpSecManager { } /** - * 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 48b5bd5c3d5b..cda4ec762caf 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -38,27 +38,29 @@ import java.lang.annotation.RetentionPolicy; 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 final class IpSecTransform implements AutoCloseable { 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 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { } } + /** Check that the transform was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -264,65 +268,63 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { // 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. + * + * <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. * - * @param intervalSeconds the maximum number of seconds between keepalive packets, no less - * than 20s and no more than 3600s. * @hide */ @SystemApi @@ -408,36 +412,29 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 @@ public final class IpSecTransform implements AutoCloseable { } /** - * 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 ee75fd443052..f468e5d2f92b 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -31,16 +31,10 @@ import java.util.Objects; 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 final class NetworkCapabilities implements Parcelable { */ public void clearAll() { mNetworkCapabilities = mTransportTypes = 0; - mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0; + mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; mNetworkSpecifier = null; mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; } @@ -359,6 +353,7 @@ public final class NetworkCapabilities implements Parcelable { /** * Sets all the capabilities set on this {@code NetworkCapability} instance. + * This overwrites any existing capabilities. * * @hide */ @@ -582,6 +577,7 @@ public final class NetworkCapabilities implements Parcelable { /** * Sets all the transports set on this {@code NetworkCapability} instance. + * This overwrites any existing transports. * * @hide */ @@ -780,7 +776,7 @@ public final class NetworkCapabilities implements Parcelable { * 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 25b1705262e8..97ded2d73b60 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 @@ public class NetworkRequest implements Parcelable { * 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 @@ public class NetworkRequest implements Parcelable { 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 class NetworkRequest implements Parcelable { 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 95e3802eeefa..b00cb482e73e 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import android.util.Slog; /** * Snapshot of network state. @@ -43,6 +44,16 @@ public class NetworkState implements Parcelable { 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 8f1a5c42e6ac..af9a73ca31ee 100644 --- a/core/java/android/net/metrics/WakeupEvent.java +++ b/core/java/android/net/metrics/WakeupEvent.java @@ -29,7 +29,7 @@ public class WakeupEvent { 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 @@ public class WakeupEvent { 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 1ba97771b595..23c1f20f1a44 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 @@ public class WakeupStats { 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 3544ea1e03e3..a080c8dcbcc5 100644 --- a/core/java/android/os/HidlSupport.java +++ b/core/java/android/os/HidlSupport.java @@ -179,4 +179,9 @@ public class HidlSupport { } 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 e426356dcc95..6746120f410d 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -35,6 +35,10 @@ interface IUserManager { * 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 b5d62e555edc..0874d93e8262 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -151,6 +151,9 @@ public class Process { */ 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 2281fb6d5cc2..b9b9a18e361d 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -19,6 +19,7 @@ package android.os; import android.util.ArrayMap; import android.util.Slog; +import java.io.PrintWriter; import java.util.function.Consumer; /** @@ -399,6 +400,13 @@ public class RemoteCallbackList<E extends IInterface> { } } + /** @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 d230d2d14417..6560a8f9a21f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -194,6 +194,24 @@ public final class Settings { "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 @@ public final class Settings { /** {@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 @@ public final class Settings { } /** + * 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 af26a88e877c..21b72f3eb8c1 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -530,7 +530,7 @@ public class FocusFinder { * 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 c123a807800f..15c18aca96e6 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -51,6 +51,9 @@ import java.util.ArrayList; 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 @@ public final class AutofillManager { private IAutoFillManagerClient mServiceClient; @GuardedBy("mLock") + private Cleaner mServiceClientCleaner; + + @GuardedBy("mLock") private AutofillCallback mCallback; private final Context mContext; @@ -958,10 +964,19 @@ public final class AutofillManager { 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 @@ public final class AutofillManager { 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 627afa7f8364..7f2c080b3f09 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -32,6 +32,7 @@ import android.view.autofill.IAutoFillManagerClient; 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 bc86dddd956f..ec516594eefa 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -77,6 +77,7 @@ cc_library_shared { "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 8b6fc59758e4..6bc6f6355bc2 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -154,6 +154,7 @@ extern int register_android_database_SQLiteDebug(JNIEnv* env); 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 @@ static const RegJNIRec gRegJNI[] = { 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 000000000000..e3602d8f5c72 --- /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 fa645f4d4c6a..ef6eb0913da4 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -254,6 +254,7 @@ message GlobalSettingsProto { 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 a979ac82dafa..9edaffe2bde1 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -121,6 +121,7 @@ public class SettingsBackupTest { 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 92b6aa3faedb..a79376ca774c 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -147,6 +147,7 @@ applications that come with the platform <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 7b2fa76f01df..76eb4e676923 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -112,14 +112,29 @@ include $(BUILD_PREBUILT) # 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 bdc0fda6aca3..31eb948dcd09 100644 --- a/media/java/android/media/MediaMetadata.java +++ b/media/java/android/media/MediaMetadata.java @@ -34,6 +34,7 @@ import android.util.SparseArray; 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 @@ public final class MediaMetadata implements Parcelable { }; /** + * 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 000000000000..a8ff5397c839 --- /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 000000000000..6644eecd71fa --- /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 000000000000..70d0898f71c1 --- /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 819ee3ee57ff..d256b12fe285 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 @@ class SettingsProtoDumpUtil { 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 a4849fcd1ca0..0e2c46b9e623 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4221,6 +4221,16 @@ message MetricsEvent { // ---- 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 cb91f9308b03..e37347a29f12 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 @@ public final class AutofillManagerService extends SystemService { } @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 751c0547afd6..5c63b90bd535 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 @@ final class AutofillManagerServiceImpl { 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 @@ final class AutofillManagerServiceImpl { } sendStateToClients(true); + if (mClients != null) { + mClients.kill(); + mClients = null; + } } CharSequence getServiceLabel() { @@ -605,6 +615,9 @@ final class AutofillManagerServiceImpl { } } + 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 75206e48aa8b..c34c30cf6e43 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -195,6 +195,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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 664c2abdffd3..ce19a1c20134 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5605,7 +5605,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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 4bdbbe3959b7..6f2d77fc8eb4 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 static android.util.TimeUtils.NANOS_PER_MS; 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 @@ public class NetdEventListenerService extends INetdEventListener.Stub { 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 401eb62f0b1b..bf1c4c3dc665 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 @@ public class PackageDexOptimizer { 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 8853aa0e8975..93d889445d41 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 @@ public class PackageManagerService extends IPackageManager.Stub 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 10ceba418f22..0ec61df77369 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 @@ class PackageManagerShellCommand extends ShellCommand { } 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 132b8455eb3f..62f4a301511d 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 @@ public class UserManagerService extends IUserManager.Stub { } } + @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 e8e06808e189..f81c89af8abf 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -856,6 +856,39 @@ public final class Call { */ 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 @@ public final class Call { * {@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 @@ public final class Call { } /** + * 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 35804f64f4d7..da8ac5ec00d7 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -2033,6 +2033,43 @@ public abstract class ConnectionService extends Service { } /** + * 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 9bf04675613d..4bc2a9b149f2 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -435,4 +435,21 @@ public final class InCallAdapter { } 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 691e7cf1d34f..74b9465070c5 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -86,13 +86,11 @@ public final class PhoneAccount implements Parcelable { /** * 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 @@ public final class PhoneAccount implements Parcelable { * 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 @@ public final class PhoneAccount implements Parcelable { * <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 f30d7bdef810..05480dc38a0d 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -1065,7 +1065,7 @@ public final class RemoteConnection { * * @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 aa2323d29ec2..4d2cb04783d9 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1749,6 +1749,41 @@ public class TelecomManager { 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 bce339207042..23ac940edfa8 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -77,4 +77,7 @@ oneway interface IInCallAdapter { 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 8ebac2c6273a..3460754ff9eb 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -274,4 +274,9 @@ interface ITelecomService { * @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 4d7c71febd6f..c9684062b6c3 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -101,9 +101,6 @@ public final class CellIdentityGsm implements Parcelable { * @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 @@ public final class CellIdentityGsm implements Parcelable { // 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 @@ public final class CellIdentityGsm implements Parcelable { // 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 fd837fc0ac26..825dcc336eb9 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -102,9 +102,6 @@ public final class CellIdentityLte implements Parcelable { * @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 @@ public final class CellIdentityLte implements Parcelable { // 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 @@ public final class CellIdentityLte implements Parcelable { // 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 1597245c6fa2..e74b5701233f 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -102,9 +102,6 @@ public final class CellIdentityWcdma implements Parcelable { * @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 @@ public final class CellIdentityWcdma implements Parcelable { // 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 @@ public final class CellIdentityWcdma implements Parcelable { // 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 0d1764b7a80a..d2fd0979df22 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -26,6 +26,7 @@ import android.content.res.Configuration; 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 @@ public class SubscriptionManager { * 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 @@ public class SubscriptionManager { } 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 f461910eaa8b..6b26dbb50c62 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -52,8 +52,9 @@ import android.telephony.VisualVoicemailService.VisualVoicemailTask; 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 @@ public class TelephonyManager { * 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 @@ public class TelephonyManager { "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 class TelephonyManager { 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 IImsMMTelFeature} interface for the feature specified or {@code null} if + * it is unavailable. + * @hide + */ + public @Nullable IImsMMTelFeature getImsMMTelFeatureAndListen(int slotIndex, + IImsServiceFeatureCallback callback) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getMMTelFeatureAndListen(slotIndex, callback); + } + } catch (RemoteException e) { + 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 IImsServiceController} interface for the feature specified or {@link null} if + * @return {@link IImsRcsFeature} 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 IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex, + IImsServiceFeatureCallback callback) { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getImsServiceControllerAndListen(slotIndex, feature, callback); + return telephony.getRcsFeatureAndListen(slotIndex, callback); } } catch (RemoteException e) { - Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage()); + 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 000000000000..65fdf9164843 --- /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 000000000000..41c1430e386f --- /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 9d91cc3387e2..8230eafc2e4d 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.telephony.ims.feature.RcsFeature; 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 class ImsService extends Service { */ 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) - throws RemoteException { - synchronized (mFeatures) { - enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature"); - onCreateImsFeatureInternal(slotId, feature, c); - } + public IImsMMTelFeature createEmergencyMMTelFeature(int slotId, + IImsFeatureStatusCallback c) { + return createEmergencyMMTelFeatureInternal(slotId, c); } @Override - public void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c) - throws RemoteException { - synchronized (mFeatures) { - enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature"); - onRemoveImsFeatureInternal(slotId, feature, c); - } + public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) { + return createMMTelFeatureInternal(slotId, 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; + public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) { + return createRcsFeatureInternal(slotId, c); } @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) + public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) 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); - } - } + ImsService.this.removeImsFeature(slotId, featureType, c); } - - @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 @@ public class ImsService extends Service { @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, - IImsFeatureStatusCallback c) { - SparseArray<ImsFeature> featureMap = mFeatures.get(slotId); - if (featureMap == null) { - featureMap = new SparseArray<>(); - mFeatures.put(slotId, featureMap); - } - ImsFeature f = makeImsFeature(slotId, featureType); - if (f != null) { - f.setContext(this); - f.setSlotId(slotId); - f.addImsFeatureStatusCallback(c); - featureMap.put(featureType, f); - } - + @VisibleForTesting + public SparseArray<ImsFeature> getFeatures(int slotId) { + return mFeaturesBySlot.get(slotId); } - /** - * 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); + private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId, + IImsFeatureStatusCallback c) { + MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId); + if (f != null) { + setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c); + return f.getBinder(); + } else { + return null; } } - // 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); + 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 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) { + 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; } - try { - return className.cast(feature); - } catch (ClassCastException e) - { - Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage()); - } - 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 void setupFeature(ImsFeature f, int slotId, int featureType, + IImsFeatureStatusCallback c) { + f.setContext(this); + f.setSlotId(slotId); + f.addImsFeatureStatusCallback(c); + addImsFeature(slotId, featureType, f); } - 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 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); } - // 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 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 @@ public class ImsService extends Service { * 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 @@ public class ImsService extends Service { * functionality. * @hide */ - public MMTelFeature onCreateMMTelImsFeature(int slotId) { + public @Nullable MMTelFeature onCreateMMTelImsFeature(int slotId) { return null; } @@ -487,7 +233,7 @@ public class ImsService extends Service { * @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 9d880b7395ef..062858d4d237 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -19,6 +19,7 @@ package android.telephony.ims.feature; 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 abstract class ImsFeature { 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 @@ public abstract class ImsFeature { 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 @@ public abstract class ImsFeature { * 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 758c379fcdd1..e790d1460ee0 100644 --- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java @@ -18,18 +18,18 @@ package android.telephony.ims.feature; 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 @@ import java.util.List; 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 @@ public class MMTelFeature extends ImsFeature { } /** - * 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 332cca3e5696..a82e60860972 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 @@ package android.telephony.ims.feature; public class RcsFeature extends ImsFeature { + private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() { + // Empty Default Implementation. + }; + + public RcsFeature() { super(); } @@ -32,4 +39,9 @@ public class RcsFeature extends ImsFeature { 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 000000000000..52b3853ec5b6 --- /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/IImsRcsFeature.aidl b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl new file mode 100644 index 000000000000..b1cb23be8fa3 --- /dev/null +++ b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl @@ -0,0 +1,25 @@ +/* + * 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; + +/** + * See RcsFeature for more information. + * {@hide} + */ +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 f1e2262ee80c..857089fac33a 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 index df10700283f2..9a9cf5325310 100644 --- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl @@ -21,7 +21,7 @@ package com.android.ims.internal; * 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 3cc9bde8423e..fd6091a78f3a 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.ServiceState; 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 @@ interface ITelephony { 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 7b0703851441..8e579aa68eae 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 android.system.OsConstants.SOCK_DGRAM; 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.InetAddress; 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 @@ import org.junit.runner.RunWith; 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 @@ public class IpSecServiceTest { } } } + + /** + * 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 index c6ad4c2aa396..c6ad4c2aa396 100755 --- a/tools/fonts/fontchain_lint.py +++ b/tools/fonts/fontchain_linter.py diff --git a/vr/Android.mk b/vr/Android.mk index 5b65d3fddba1..73e9f23ba067 100644 --- a/vr/Android.mk +++ b/vr/Android.mk @@ -18,6 +18,7 @@ include $(CLEAR_VARS) 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. |