diff options
59 files changed, 2785 insertions, 250 deletions
diff --git a/Android.bp b/Android.bp index e2b432cdd8cd..ee593aac39ad 100644 --- a/Android.bp +++ b/Android.bp @@ -689,6 +689,7 @@ java_defaults { "android.hardware.vibrator-V1.2-java", "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", + "android.hardware.radio-V1.3-java", "android.hardware.usb.gadget-V1.0-java", ], diff --git a/api/current.txt b/api/current.txt index 93fcf3b80a56..7e3629274ba6 100755 --- a/api/current.txt +++ b/api/current.txt @@ -21,6 +21,7 @@ package android { field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; field public static final java.lang.String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE"; + field public static final java.lang.String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE"; field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE"; field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; @@ -43024,6 +43025,36 @@ package android.telephony.data { } +package android.telephony.emergency { + + public final class EmergencyNumber implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getCountryIso(); + method public int getEmergencyNumberSourceBitmask(); + method public java.util.List<java.lang.Integer> getEmergencyNumberSources(); + method public java.util.List<java.lang.Integer> getEmergencyServiceCategories(); + method public int getEmergencyServiceCategoryBitmask(); + method public java.lang.String getNumber(); + method public boolean isFromSources(int); + method public boolean isInEmergencyServiceCategories(int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR; + field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8 + field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4 + field public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 1; // 0x1 + field public static final int EMERGENCY_NUMBER_SOURCE_SIM = 2; // 0x2 + field public static final int EMERGENCY_SERVICE_CATEGORY_AIEC = 64; // 0x40 + field public static final int EMERGENCY_SERVICE_CATEGORY_AMBULANCE = 2; // 0x2 + field public static final int EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = 4; // 0x4 + field public static final int EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = 8; // 0x8 + field public static final int EMERGENCY_SERVICE_CATEGORY_MIEC = 32; // 0x20 + field public static final int EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = 16; // 0x10 + field public static final int EMERGENCY_SERVICE_CATEGORY_POLICE = 1; // 0x1 + field public static final int EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = 0; // 0x0 + } + +} + package android.telephony.euicc { public final class DownloadableSubscription implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index 231a32785b00..89ac7210de46 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5138,9 +5138,12 @@ package android.telephony { } public class ServiceState implements android.os.Parcelable { + method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int); method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(); - method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int); - method public android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int); + method public deprecated java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int); + method public deprecated android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int); + method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForDomain(int); + method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(int); } public final class SmsManager { @@ -5657,7 +5660,7 @@ package android.telephony.ims { field public static final java.lang.String EXTRA_CODEC = "Codec"; field public static final java.lang.String EXTRA_DIALSTRING = "dialstring"; field public static final java.lang.String EXTRA_DISPLAY_TEXT = "DisplayText"; - field public static final java.lang.String EXTRA_E_CALL = "e_call"; + field public static final java.lang.String EXTRA_EMERGENCY_CALL = "e_call"; field public static final java.lang.String EXTRA_IS_CALL_PULL = "CallPull"; field public static final java.lang.String EXTRA_OI = "oi"; field public static final java.lang.String EXTRA_OIR = "oir"; diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index fff909c12441..581ed3e5ef22 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -489,6 +489,9 @@ const std::map<string, uint32_t> UidMap::sAidToUidMapping = {{"AID_ROOT", 0}, {"AID_RESERVED_DISK", 1065}, {"AID_STATSD", 1066}, {"AID_INCIDENTD", 1067}, + {"AID_SECURE_ELEMENT", 1068}, + {"AID_LMKD", 1069}, + {"AID_LLKD", 1070}, {"AID_SHELL", 2000}, {"AID_CACHE", 2001}, {"AID_DIAG", 2002}}; diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index 7fd83bc6c8b9..f6d80a572c75 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -34,9 +34,18 @@ import java.util.function.Predicate; /** * Helper functions for dumping the state of system services. * Test: - atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java + atest FrameworksCoreTests:DumpUtilsTest */ public final class DumpUtils { + + /** + * List of component names that should be dumped in the bug report critical section. + * + * @hide + */ + public static final ComponentName[] CRITICAL_SECTION_COMPONENTS = { + new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService") + }; private static final String TAG = "DumpUtils"; private static final boolean DEBUG = false; @@ -213,6 +222,45 @@ public final class DumpUtils { } /** + * Return whether a package should be dumped in the critical section. + */ + private static boolean isCriticalPackage(@Nullable ComponentName cname) { + if (cname == null) { + return false; + } + + for (int i = 0; i < CRITICAL_SECTION_COMPONENTS.length; i++) { + if (cname.equals(CRITICAL_SECTION_COMPONENTS[i])) { + return true; + } + } + return false; + } + + /** + * Return whether a package name is considered to be part of the platform and in the critical + * section. + * + * @hide + */ + public static boolean isPlatformCriticalPackage(@Nullable ComponentName.WithComponentName wcn) { + return (wcn != null) && isPlatformPackage(wcn.getComponentName()) && + isCriticalPackage(wcn.getComponentName()); + } + + /** + * Return whether a package name is considered to be part of the platform but not in the the + * critical section. + * + * @hide + */ + public static boolean isPlatformNonCriticalPackage( + @Nullable ComponentName.WithComponentName wcn) { + return (wcn != null) && isPlatformPackage(wcn.getComponentName()) && + !isCriticalPackage(wcn.getComponentName()); + } + + /** * Used for dumping providers and services. Return a predicate for a given filter string. * @hide */ @@ -238,6 +286,16 @@ public final class DumpUtils { return DumpUtils::isNonPlatformPackage; } + // Dump all platform-critical? + if ("all-platform-critical".equals(filterString)) { + return DumpUtils::isPlatformCriticalPackage; + } + + // Dump all platform-non-critical? + if ("all-platform-non-critical".equals(filterString)) { + return DumpUtils::isPlatformNonCriticalPackage; + } + // Is the filter a component name? If so, do an exact match. final ComponentName filterCname = ComponentName.unflattenFromString(filterString); if (filterCname != null) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ac9617c5dc62..73bb1fc1b4a7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1827,6 +1827,13 @@ <permission android:name="android.permission.BIND_SCREENING_SERVICE" android:protectionLevel="signature|privileged" /> + <!-- Must be required by a {@link android.telecom.CallRedirectionService}, + to ensure that only the system can bind to it. + <p>Protection level: signature|privileged + --> + <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE" + android:protectionLevel="signature|privileged" /> + <!-- Must be required by a {@link android.telecom.ConnectionService}, to ensure that only the system can bind to it. @deprecated {@link android.telecom.ConnectionService}s should require diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java index 45b19bccff88..a44b86074ee2 100644 --- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java @@ -15,8 +15,11 @@ */ package com.android.internal.util; +import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS; import static com.android.internal.util.DumpUtils.filterRecord; import static com.android.internal.util.DumpUtils.isNonPlatformPackage; +import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage; +import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformPackage; import android.content.ComponentName; @@ -25,7 +28,7 @@ import junit.framework.TestCase; /** * Run with: - atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java + atest FrameworksCoreTests:DumpUtilsTest */ public class DumpUtilsTest extends TestCase { @@ -89,6 +92,32 @@ public class DumpUtilsTest extends TestCase { assertTrue(isNonPlatformPackage(wcn("com.google.def/abc"))); } + public void testIsPlatformCriticalPackage() { + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertTrue(isPlatformCriticalPackage(() -> componentName)); + assertTrue(isPlatformPackage(componentName)); + } + assertFalse(isPlatformCriticalPackage(wcn("com.google.p/abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android.def/abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android.abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android"))); + assertFalse(isPlatformCriticalPackage(wcn(null))); + assertFalse(isPlatformCriticalPackage(null)); + } + + public void testIsPlatformNonCriticalPackage() { + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertFalse(isPlatformNonCriticalPackage(() -> componentName)); + } + assertTrue(isPlatformNonCriticalPackage(wcn("android/abc"))); + assertTrue(isPlatformNonCriticalPackage(wcn("android.abc/abc"))); + assertTrue(isPlatformNonCriticalPackage(wcn("com.android.def/abc"))); + + assertFalse(isPlatformNonCriticalPackage(wcn("com.google.def/abc"))); + assertFalse(isPlatformNonCriticalPackage(wcn(null))); + assertFalse(isPlatformNonCriticalPackage(null)); + } + public void testFilterRecord() { assertFalse(filterRecord(null).test(wcn("com.google.p/abc"))); assertFalse(filterRecord(null).test(wcn("com.android.p/abc"))); @@ -105,6 +134,19 @@ public class DumpUtilsTest extends TestCase { assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc"))); assertFalse(filterRecord("all-non-platform").test(wcn(null))); + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertTrue(filterRecord("all-platform-critical").test((() -> componentName))); + assertFalse(filterRecord("all-platform-non-critical").test((() -> componentName))); + assertTrue(filterRecord("all-platform").test((() -> componentName))); + } + assertFalse(filterRecord("all-platform-critical").test(wcn("com.google.p/abc"))); + assertFalse(filterRecord("all-platform-critical").test(wcn("com.android.p/abc"))); + assertFalse(filterRecord("all-platform-critical").test(wcn(null))); + + assertTrue(filterRecord("all-platform-non-critical").test(wcn("com.android.p/abc"))); + assertFalse(filterRecord("all-platform-non-critical").test(wcn("com.google.p/abc"))); + assertFalse(filterRecord("all-platform-non-critical").test(wcn(null))); + // Partial string match. assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc"))); assertFalse(filterRecord("abc").test(wcn("com.google.p/.def"))); diff --git a/media/jni/OWNERS b/media/jni/OWNERS new file mode 100644 index 000000000000..bb91d4b26ecc --- /dev/null +++ b/media/jni/OWNERS @@ -0,0 +1,2 @@ +# extra for MTP related files +per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS new file mode 100644 index 000000000000..1928ba811e7e --- /dev/null +++ b/media/tests/MtpTests/OWNERS @@ -0,0 +1,7 @@ +set noparent + +marcone@google.com +jsharkey@android.com +jameswei@google.com +rmojumder@google.com + diff --git a/packages/ExtServices/tests/AndroidTest.xml b/packages/ExtServices/tests/AndroidTest.xml new file mode 100644 index 000000000000..c3d32de4bfaf --- /dev/null +++ b/packages/ExtServices/tests/AndroidTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs Tests for ExtServices"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="ExtServicesUnitTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="ExtServicesUnitTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.ext.services.tests.unit" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration>
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 08fbbedac19c..75cbb6589037 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -29,6 +29,7 @@ import android.bluetooth.BluetoothMapClient; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothPbap; import android.bluetooth.BluetoothPbapClient; +import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; @@ -101,6 +102,7 @@ public class LocalBluetoothProfileManager { private final boolean mUsePbapPce; private final boolean mUseMapClient; private HearingAidProfile mHearingAidProfile; + private SapProfile mSapProfile; /** * Mapping from profile name, e.g. "HEADSET" to profile object. @@ -196,12 +198,14 @@ public class LocalBluetoothProfileManager { if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) { if (mA2dpSinkProfile == null) { if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile"); - mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this); + mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, + mDeviceManager, this); addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME, BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); } } else if (mA2dpSinkProfile != null) { - Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing."); + Log.w(TAG, "Warning: A2DP Sink profile was previously added but the " + + "UUID is now missing."); } // Headset / Handsfree @@ -217,7 +221,8 @@ public class LocalBluetoothProfileManager { BluetoothHeadset.STATE_AUDIO_DISCONNECTED); } } else if (mHeadsetProfile != null) { - Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing."); + Log.w(TAG, "Warning: HEADSET profile was previously added but the " + + "UUID is now missing."); } // Headset HF @@ -249,7 +254,8 @@ public class LocalBluetoothProfileManager { } } else if (mMapClientProfile != null) { Log.w(TAG, - "Warning: MAP Client profile was previously added but the UUID is now missing."); + "Warning: MAP Client profile was previously added but the " + + "UUID is now missing."); } else { Log.d(TAG, "MAP Client Uuid not found."); } @@ -266,7 +272,7 @@ public class LocalBluetoothProfileManager { Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); } - //PBAP Client + // PBAP Client if (mUsePbapPce) { if (mPbapClientProfile == null) { if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile"); @@ -280,18 +286,27 @@ public class LocalBluetoothProfileManager { "Warning: PBAP Client profile was previously added but the UUID is now missing."); } - //Hearing Aid Client + // Hearing Aid Client if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) { if (mHearingAidProfile == null) { if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile"); - mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this); + mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, + mDeviceManager, this); addProfile(mHearingAidProfile, HearingAidProfile.NAME, BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); } } else if (mHearingAidProfile != null) { - Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing."); + Log.w(TAG, "Warning: Hearing Aid profile was previously added but the " + + "UUID is now missing."); } + // SAP + if (mSapProfile == null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) { + Log.d(TAG, "Adding local SAP profile"); + mSapProfile = new SapProfile(mContext, mLocalAdapter, mDeviceManager, this); + addProfile(mSapProfile, SapProfile.NAME, + BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); + } mEventManager.registerProfileIntentReceiver(); // There is no local SDP record for HID and Settings app doesn't control PBAP Server. @@ -635,6 +650,11 @@ public class LocalBluetoothProfileManager { removedProfiles.remove(mHearingAidProfile); } + if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) { + profiles.add(mSapProfile); + removedProfiles.remove(mSapProfile); + } + if (DEBUG) { Log.d(TAG,"New Profiles" + profiles.toString()); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java index f7cd39372e11..e83c62d7c222 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -36,7 +36,6 @@ import java.util.List; */ final class SapProfile implements LocalBluetoothProfile { private static final String TAG = "SapProfile"; - private static boolean V = true; private BluetoothSap mService; private boolean mIsProfileReady; @@ -59,7 +58,7 @@ final class SapProfile implements LocalBluetoothProfile { implements BluetoothProfile.ServiceListener { public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); + Log.d(TAG, "Bluetooth service connected, profile:" + profile); mService = (BluetoothSap) proxy; // We just bound to the service, so refresh the UI for any connected SAP devices. List<BluetoothDevice> deviceList = mService.getConnectedDevices(); @@ -81,7 +80,7 @@ final class SapProfile implements LocalBluetoothProfile { } public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); + Log.d(TAG, "Bluetooth service disconnected, profile:" + profile); mProfileManager.callServiceDisconnectedListeners(); mIsProfileReady=false; } @@ -115,50 +114,47 @@ final class SapProfile implements LocalBluetoothProfile { } public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> sinks = mService.getConnectedDevices(); - if (sinks != null) { - for (BluetoothDevice sink : sinks) { - mService.disconnect(sink); - } + if (mService == null) { + return false; } return mService.connect(device); } public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) { - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); - } - return mService.disconnect(device); - } else { + if (mService == null) { return false; } + if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + return mService.disconnect(device); } public int getConnectionStatus(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.STATE_DISCONNECTED; - List<BluetoothDevice> deviceList = mService.getConnectedDevices(); - - return !deviceList.isEmpty() && deviceList.get(0).equals(device) - ? mService.getConnectionState(device) - : BluetoothProfile.STATE_DISCONNECTED; + if (mService == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + return mService.getConnectionState(device); } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; + if (mService == null) { + return false; + } return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return BluetoothProfile.PRIORITY_OFF; + } return mService.getPriority(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; + if (mService == null) { + return; + } if (preferred) { if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { mService.setPriority(device, BluetoothProfile.PRIORITY_ON); @@ -169,7 +165,9 @@ final class SapProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); + if (mService == null) { + return new ArrayList<BluetoothDevice>(0); + } return mService.getDevicesMatchingConnectionStates( new int[] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING, @@ -207,11 +205,11 @@ final class SapProfile implements LocalBluetoothProfile { } protected void finalize() { - if (V) Log.d(TAG, "finalize()"); + Log.d(TAG, "finalize()"); if (mService != null) { try { BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP, - mService); + mService); mService = null; }catch (Throwable t) { Log.w(TAG, "Error cleaning up SAP proxy", t); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java new file mode 100644 index 000000000000..6ff3e7085b3c --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSap; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class SapProfileTest { + + @Mock + private LocalBluetoothAdapter mAdapter; + @Mock + private CachedBluetoothDeviceManager mDeviceManager; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private BluetoothSap mService; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice; + private BluetoothProfile.ServiceListener mServiceListener; + private SapProfile mProfile; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doAnswer((invocation) -> { + mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1]; + return null; + }).when(mAdapter).getProfileProxy(any(Context.class), + any(BluetoothProfile.ServiceListener.class), eq(BluetoothProfile.SAP)); + + mProfile = new SapProfile(RuntimeEnvironment.application, mAdapter, + mDeviceManager, mProfileManager); + mServiceListener.onServiceConnected(BluetoothProfile.SAP, mService); + } + + @Test + public void connect_shouldConnectBluetoothSap() { + mProfile.connect(mBluetoothDevice); + verify(mService).connect(mBluetoothDevice); + } + + @Test + public void disconnect_shouldDisconnectBluetoothSap() { + mProfile.disconnect(mBluetoothDevice); + verify(mService).disconnect(mBluetoothDevice); + } + + @Test + public void getConnectionStatus_shouldReturnConnectionState() { + when(mService.getConnectionState(mBluetoothDevice)). + thenReturn(BluetoothProfile.STATE_CONNECTED); + assertThat(mProfile.getConnectionStatus(mBluetoothDevice)). + isEqualTo(BluetoothProfile.STATE_CONNECTED); + } +}
\ No newline at end of file diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 4fc190d43056..2530abc765da 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -16,6 +16,8 @@ package com.android.shell; +import static android.content.pm.PackageManager.FEATURE_LEANBACK; +import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static com.android.shell.BugreportPrefs.STATE_HIDE; @@ -42,6 +44,7 @@ import java.util.zip.ZipOutputStream; import libcore.io.Streams; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.internal.logging.MetricsLogger; @@ -232,9 +235,11 @@ public class BugreportProgressService extends Service { */ private boolean mTakingScreenshot; + @GuardedBy("sNotificationBundle") private static final Bundle sNotificationBundle = new Bundle(); private boolean mIsWatch; + private boolean mIsTv; private int mLastProgressPercent; @@ -255,6 +260,9 @@ public class BugreportProgressService extends Service { final Configuration conf = mContext.getResources().getConfiguration(); mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_WATCH; + PackageManager packageManager = getPackageManager(); + mIsTv = packageManager.hasSystemFeature(FEATURE_LEANBACK) + || packageManager.hasSystemFeature(FEATURE_TELEVISION); NotificationManager nm = NotificationManager.from(mContext); nm.createNotificationChannel( new NotificationChannel(NOTIFICATION_CHANNEL_ID, @@ -500,8 +508,8 @@ public class BugreportProgressService extends Service { .setProgress(info.max, info.progress, false) .setOngoing(true); - // Wear bugreport doesn't need the bug info dialog, screenshot and cancel action. - if (!mIsWatch) { + // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action. + if (!(mIsWatch || mIsTv)) { final Action cancelAction = new Action.Builder(null, mContext.getString( com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build(); final Intent infoIntent = new Intent(mContext, BugreportProgressService.class); @@ -1053,10 +1061,12 @@ public class BugreportProgressService extends Service { } private static Notification.Builder newBaseNotification(Context context) { - if (sNotificationBundle.isEmpty()) { - // Rename notifcations from "Shell" to "Android System" - sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, - context.getString(com.android.internal.R.string.android_system_label)); + synchronized (sNotificationBundle) { + if (sNotificationBundle.isEmpty()) { + // Rename notifcations from "Shell" to "Android System" + sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, + context.getString(com.android.internal.R.string.android_system_label)); + } } return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) .addExtras(sNotificationBundle) diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java index 0734e0dae790..4fbc22663675 100644 --- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java +++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java @@ -20,6 +20,7 @@ import android.database.Cursor; import android.database.MatrixCursor; import android.database.MatrixCursor.RowBuilder; import android.net.Uri; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUtils; import android.os.ParcelFileDescriptor; @@ -68,6 +69,18 @@ public class BugreportStorageProvider extends FileSystemProvider { } @Override + public Cursor queryChildDocuments( + String parentDocumentId, String[] projection, String sortOrder) + throws FileNotFoundException { + final Cursor c = super.queryChildDocuments(parentDocumentId, projection, sortOrder); + final Bundle extras = new Bundle(); + extras.putCharSequence(DocumentsContract.EXTRA_INFO, + getContext().getText(R.string.bugreport_confirm)); + c.setExtras(extras); + return c; + } + + @Override public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException { if (DOC_ID_ROOT.equals(documentId)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 2031b27c93f2..1fefa18ad631 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -53,6 +53,7 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final Object mCallbacksLock = new Object(); private final Context mContext; private final GlobalSetting mModeSetting; private final GlobalSetting mConfigSetting; @@ -113,16 +114,20 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode @Override public void addCallback(Callback callback) { - if (callback == null) { - Slog.e(TAG, "Attempted to add a null callback."); - return; + synchronized (mCallbacksLock) { + if (callback == null) { + Slog.e(TAG, "Attempted to add a null callback."); + return; + } + mCallbacks.add(callback); } - mCallbacks.add(callback); } @Override public void removeCallback(Callback callback) { - mCallbacks.remove(callback); + synchronized (mCallbacksLock) { + mCallbacks.remove(callback); + } } @Override @@ -186,28 +191,40 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode } private void fireNextAlarmChanged() { - Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged()); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged()); + } } private void fireEffectsSuppressorChanged() { - Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged()); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged()); + } } private void fireZenChanged(int zen) { - Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen)); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen)); + } } private void fireZenAvailableChanged(boolean available) { - Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available)); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available)); + } } private void fireManualRuleChanged(ZenRule rule) { - Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule)); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule)); + } } @VisibleForTesting protected void fireConfigChanged(ZenModeConfig config) { - Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config)); + synchronized (mCallbacksLock) { + Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config)); + } } @VisibleForTesting diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 953c99ff2474..5e8ffb79c493 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1837,7 +1837,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } void systemReady() { - loadGlobalProxy(); + mProxyTracker.loadGlobalProxy(); registerNetdEventCallback(); synchronized (this) { @@ -3455,31 +3455,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mProxyTracker.setGlobalProxy(proxyProperties); } - private void loadGlobalProxy() { - ContentResolver res = mContext.getContentResolver(); - String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST); - int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); - String exclList = Settings.Global.getString(res, - Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); - String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); - if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { - ProxyInfo proxyProperties; - if (!TextUtils.isEmpty(pacFileUrl)) { - proxyProperties = new ProxyInfo(pacFileUrl); - } else { - proxyProperties = new ProxyInfo(host, port, exclList); - } - if (!proxyProperties.isValid()) { - if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); - return; - } - - synchronized (mProxyTracker.mProxyLock) { - mProxyTracker.mGlobalProxy = proxyProperties; - } - } - } - @Override @Nullable public ProxyInfo getGlobalProxy() { diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a69d41683c29..8c25917c7436 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -19,6 +19,8 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_UNSPEC; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -63,6 +65,8 @@ import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -1426,6 +1430,17 @@ public class IpSecService extends IIpSecService.Stub { + "or Encryption algorithms"); } + private int getFamily(String inetAddress) { + int family = AF_UNSPEC; + InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress); + if (checkAddress instanceof Inet4Address) { + family = AF_INET; + } else if (checkAddress instanceof Inet6Address) { + family = AF_INET6; + } + return family; + } + /** * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an * IllegalArgumentException if they are not. @@ -1479,6 +1494,26 @@ public class IpSecService extends IIpSecService.Stub { // Require a valid source address for all transforms. checkInetAddress(config.getSourceAddress()); + // Check to ensure source and destination have the same address family. + String sourceAddress = config.getSourceAddress(); + String destinationAddress = config.getDestinationAddress(); + int sourceFamily = getFamily(sourceAddress); + int destinationFamily = getFamily(destinationAddress); + if (sourceFamily != destinationFamily) { + throw new IllegalArgumentException( + "Source address (" + + sourceAddress + + ") and destination address (" + + destinationAddress + + ") have different address families."); + } + + // Throw an error if UDP Encapsulation is not used in IPv4. + if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) { + throw new IllegalArgumentException( + "UDP Encapsulation is not supported for this address family"); + } + switch (config.getMode()) { case IpSecTransform.MODE_TRANSPORT: break; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9d0a8653178a..6c9871129ba0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -717,8 +717,6 @@ public class ActivityManagerService extends IActivityManager.Stub // Whether we should use SCHED_FIFO for UI and RenderThreads. private boolean mUseFifoUiScheduling = false; - private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService"; - BroadcastQueue mFgBroadcastQueue; BroadcastQueue mBgBroadcastQueue; // Convenient for easy iteration over the queues. Foreground is first @@ -810,7 +808,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean asProto) { if (asProto) return; doDump(fd, pw, new String[]{"activities"}, asProto); - doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto); + doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto); } @Override diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index dc65e1e69834..b7bbd422458f 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -142,6 +142,35 @@ public class ProxyTracker { } /** + * Read the global proxy settings and cache them in memory. + */ + public void loadGlobalProxy() { + ContentResolver res = mContext.getContentResolver(); + String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST); + int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); + String exclList = Settings.Global.getString(res, + Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); + String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); + if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { + ProxyInfo proxyProperties; + if (!TextUtils.isEmpty(pacFileUrl)) { + proxyProperties = new ProxyInfo(pacFileUrl); + } else { + proxyProperties = new ProxyInfo(host, port, exclList); + } + if (!proxyProperties.isValid()) { + if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties); + return; + } + + synchronized (mProxyLock) { + mGlobalProxy = proxyProperties; + } + } + // TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ? + } + + /** * Sends the system broadcast informing apps about a new proxy configuration. * * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 60e9eaab5721..3f031699bd7a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -159,8 +159,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); + // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_REGISTER_GLOBAL_ALERT = 2; + // Perform polling, persist network, and register the global alert again. + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -168,6 +170,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_FORCE = 0x100; + /** + * When global alert quota is high, wait for this delay before processing each polling, + * and do not schedule further polls once there is already one queued. + * This avoids firing the global alert too often on devices with high transfer speeds and + * high quota. + */ + private static final int PERFORM_POLL_DELAY_MS = 1000; + private static final String TAG_NETSTATS_ERROR = "netstats_error"; private final Context mContext; @@ -920,7 +930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Create baseline stats - mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL)); return normalizedRequest; } @@ -1055,13 +1065,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { - // kick off background poll to collect network stats; UID stats - // are handled during normal polling interval. - final int flags = FLAG_PERSIST_NETWORK; - mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); - - // re-arm global alert for next update - mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget(); + // kick off background poll to collect network stats unless there is already + // such a call pending; UID stats are handled during normal polling interval. + if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { + mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, + PERFORM_POLL_DELAY_MS); + } } } }; @@ -1673,11 +1682,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { - final int flags = msg.arg1; - mService.performPoll(flags); + mService.performPoll(FLAG_PERSIST_ALL); return true; } - case MSG_REGISTER_GLOBAL_ALERT: { + case MSG_PERFORM_POLL_REGISTER_ALERT: { + mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); return true; } diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 833cc5bd91f2..1fb51b7fa0e8 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -16,6 +16,8 @@ package com.android.server.pm.dex; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.Context; @@ -57,8 +59,6 @@ import dalvik.system.DexFile; import dalvik.system.VMRuntime; import libcore.io.IoUtils; -import libcore.util.NonNull; -import libcore.util.Nullable; import java.io.File; import java.io.FileNotFoundException; diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp index 05052047e0fb..47790ce68dc1 100644 --- a/services/devicepolicy/Android.bp +++ b/services/devicepolicy/Android.bp @@ -3,7 +3,6 @@ java_library_static { srcs: ["java/**/*.java"], libs: [ - "conscrypt", "services.core", ], } diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index 77a3e2102452..6ba7d94117b1 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -1,5 +1,8 @@ package android.net.dhcp; +import static android.net.util.NetworkConstants.IPV4_MAX_MTU; +import static android.net.util.NetworkConstants.IPV4_MIN_MTU; + import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; @@ -381,6 +384,26 @@ public abstract class DhcpPacket { } /** + * Returns whether a parameter is included in the parameter request list option of this packet. + * + * <p>If there is no parameter request list option in the packet, false is returned. + * + * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}. + */ + public boolean hasRequestedParam(byte paramId) { + if (mRequestedParams == null) { + return false; + } + + for (byte reqParam : mRequestedParams) { + if (reqParam == paramId) { + return true; + } + } + return false; + } + + /** * Creates a new L3 packet (including IP header) containing the * DHCP udp packet. This method relies upon the delegated method * finishPacket() to insert the per-packet contents. @@ -696,7 +719,11 @@ public abstract class DhcpPacket { addTlv(buf, DHCP_ROUTER, mGateways); addTlv(buf, DHCP_DNS_SERVER, mDnsServers); addTlv(buf, DHCP_DOMAIN_NAME, mDomainName); + addTlv(buf, DHCP_HOST_NAME, mHostName); addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo); + if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) { + addTlv(buf, DHCP_MTU, mMtu); + } } /** @@ -1259,7 +1286,8 @@ public abstract class DhcpPacket { boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, - Inet4Address dhcpServerIdentifier, String domainName, boolean metered) { + Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, + short mtu) { DhcpPacket pkt = new DhcpOfferPacket( transactionId, (short) 0, broadcast, serverIpAddr, relayIp, INADDR_ANY /* clientIp */, yourIp, mac); @@ -1267,9 +1295,11 @@ public abstract class DhcpPacket { pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; pkt.mDomainName = domainName; + pkt.mHostName = hostname; pkt.mServerIdentifier = dhcpServerIdentifier; pkt.mSubnetMask = netMask; pkt.mBroadcastAddress = bcAddr; + pkt.mMtu = mtu; if (metered) { pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; } @@ -1283,7 +1313,8 @@ public abstract class DhcpPacket { boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, - Inet4Address dhcpServerIdentifier, String domainName, boolean metered) { + Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, + short mtu) { DhcpPacket pkt = new DhcpAckPacket( transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, mac); @@ -1291,9 +1322,11 @@ public abstract class DhcpPacket { pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; pkt.mDomainName = domainName; + pkt.mHostName = hostname; pkt.mSubnetMask = netMask; pkt.mServerIdentifier = dhcpServerIdentifier; pkt.mBroadcastAddress = bcAddr; + pkt.mMtu = mtu; if (metered) { pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; } diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java index 2b3d577b0eae..cee6fa96bbc5 100644 --- a/services/net/java/android/net/dhcp/DhcpServer.java +++ b/services/net/java/android/net/dhcp/DhcpServer.java @@ -20,6 +20,7 @@ import static android.net.NetworkUtils.getBroadcastAddress; import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; @@ -46,6 +47,7 @@ import android.os.Message; import android.os.SystemClock; import android.system.ErrnoException; import android.system.Os; +import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; @@ -350,6 +352,19 @@ public class DhcpServer { return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr())); } + /** + * Get the hostname from a lease if non-empty and requested in the incoming request. + * @param request The incoming request. + * @return The hostname, or null if not requested or empty. + */ + @Nullable + private static String getHostnameIfRequested(@NonNull DhcpPacket request, + @NonNull DhcpLease lease) { + return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname()) + ? lease.getHostname() + : null; + } + private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease, @NonNull MacAddress clientMac) { final boolean broadcastFlag = getBroadcastFlag(request, lease); @@ -358,12 +373,14 @@ public class DhcpServer { getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength()); final Inet4Address broadcastAddr = getBroadcastAddress( mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength()); + final String hostname = getHostnameIfRequested(request, lease); final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket( ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask, broadcastAddr, new ArrayList<>(mServingParams.defaultRouters), new ArrayList<>(mServingParams.dnsServers), - mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered); + mServingParams.getServerInet4Addr(), null /* domainName */, hostname, + mServingParams.metered, (short) mServingParams.linkMtu); return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag); } @@ -374,13 +391,15 @@ public class DhcpServer { // transmitOffer above final boolean broadcastFlag = getBroadcastFlag(request, lease); final int timeout = getLeaseTimeout(lease); + final String hostname = getHostnameIfRequested(request, lease); final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp, lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(), new ArrayList<>(mServingParams.defaultRouters), new ArrayList<>(mServingParams.dnsServers), - mServingParams.getServerInet4Addr(), null /* domainName */, mServingParams.metered); + mServingParams.getServerInet4Addr(), null /* domainName */, hostname, + mServingParams.metered, (short) mServingParams.linkMtu); return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag); } diff --git a/services/tests/runtests.py b/services/tests/runtests.py index 7980dc23e8e2..f19cc5d567ec 100755 --- a/services/tests/runtests.py +++ b/services/tests/runtests.py @@ -22,8 +22,7 @@ INSTRUMENTED_PACKAGE_RUNNER = ('com.android.frameworks.servicestests/' 'android.support.test.runner.AndroidJUnitRunner') PACKAGE_WHITELIST = ( - 'android.net', - 'com.android.server.connectivity', + "com.android.server", ) COLOR_RED = '\033[0;31m' @@ -37,14 +36,27 @@ def run(shell_command, echo=True): COLOR_NONE) return subprocess.check_call(shell_command, shell=True) - +# usage: +# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py : run tests in com.android.server +# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py -e package [package name, e.g. com.android.server] +# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py -e class [class name, e.g. com.android.server.MountServiceTests] +# +# The available INSTRUMENTED_PACKAGE_RUNNER may differ in different environments. +# In this case, use "adb shell pm list instrumentation" to query available runners +# and use the environment variable INSTRUMENTED_PACKAGE_RUNNER to overwrite +# the default one, e.g., +# INSTRUMENTED_PACKAGE_RUNNER=com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner \ +# ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/runtests.py +# def main(): build_top = os.environ.get('ANDROID_BUILD_TOP', None) out_dir = os.environ.get('OUT', None) + runner = os.environ.get('INSTRUMENTED_PACKAGE_RUNNER', None) if build_top is None or out_dir is None: print 'You need to source and lunch before you can use this script' return 1 - + if runner is None: + runner = INSTRUMENTED_PACKAGE_RUNNER print 'Building tests...' run('make -j32 -C %s -f build/core/main.mk ' 'MODULES-IN-frameworks-base-services-tests-servicestests' % build_top, @@ -57,19 +69,19 @@ def main(): apk_path = ( '%s/data/app/FrameworksServicesTests/FrameworksServicesTests.apk' % out_dir) - run('adb install -r -g "%s"' % apk_path) + run('adb install -t -r -g "%s"' % apk_path) print 'Running tests...' if len(sys.argv) != 1: run('adb shell am instrument -w %s "%s"' % - (' '.join(sys.argv[1:]), INSTRUMENTED_PACKAGE_RUNNER)) + (' '.join(sys.argv[1:]), runner)) return 0 # It would be nice if the activity manager accepted a list of packages, but # in lieu of that... for package in PACKAGE_WHITELIST: run('adb shell am instrument -w -e package %s %s' % - (package, INSTRUMENTED_PACKAGE_RUNNER)) + (package, runner)) return 0 diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 36f8063cca52..4da7285bcf2d 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -539,7 +539,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver // We do not show the USB notification if the primary volume supports mass storage. // The legacy mass storage UI will be used instead. final StorageManager storageManager = StorageManager.from(mContext); - final StorageVolume primary = storageManager.getPrimaryVolume(); + final StorageVolume primary = + storageManager != null ? storageManager.getPrimaryVolume() : null; boolean massStorageSupported = primary != null && primary.allowMassStorage(); mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean( diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp new file mode 100644 index 000000000000..b3b09001e7ee --- /dev/null +++ b/startop/iorap/Android.bp @@ -0,0 +1,28 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +java_library_static { + name: "libiorap-java", + + aidl: { + include_dirs: [ + "system/iorap/binder", + ], + }, + + srcs: [ + ":iorap-aidl", + "**/*.java", + ], +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java new file mode 100644 index 000000000000..1d38f4c1e23d --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Provide a hint to iorapd that an activity has transitioned state.<br /><br /> + * + * Knowledge of when an activity starts/stops can be used by iorapd to increase system + * performance (e.g. by launching perfetto tracing to record an io profile, or by + * playing back an ioprofile via readahead) over the long run.<br /><br /> + * + * /@see com.google.android.startop.iorap.IIorap#onActivityHintEvent<br /><br /> + * + * Once an activity hint is in {@link #TYPE_STARTED} it must transition to another type. + * All other states could be terminal, see below: <br /><br /> + * + * <pre> + * + * ┌──────────────────────────────────────┐ + * │ ▼ + * ┌─────────┐ ╔════════════════╗ ╔═══════════╗ + * ──▶ │ STARTED │ ──▶ ║ COMPLETED ║ ──▶ ║ CANCELLED ║ + * └─────────┘ ╚════════════════╝ ╚═══════════╝ + * │ + * │ + * ▼ + * ╔════════════════╗ + * ║ POST_COMPLETED ║ + * ╚════════════════╝ + * + * </pre> <!-- system/iorap/docs/binder/ActivityHint.dot --> + * + * @hide + */ +public class ActivityHintEvent implements Parcelable { + + public static final int TYPE_STARTED = 0; + public static final int TYPE_CANCELLED = 1; + public static final int TYPE_COMPLETED = 2; + public static final int TYPE_POST_COMPLETED = 3; + private static final int TYPE_MAX = TYPE_POST_COMPLETED; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_STARTED, + TYPE_CANCELLED, + TYPE_COMPLETED, + TYPE_POST_COMPLETED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + public final ActivityInfo activityInfo; + + public ActivityHintEvent(@Type int type, ActivityInfo activityInfo) { + this.type = type; + this.activityInfo = activityInfo; + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + Objects.requireNonNull(activityInfo, "activityInfo"); + } + + @Override + public String toString() { + return String.format("{type: %d, activityInfo: %s}", type, activityInfo); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof ActivityHintEvent) { + return equals((ActivityHintEvent) other); + } + return false; + } + + private boolean equals(ActivityHintEvent other) { + return type == other.type && + Objects.equals(activityInfo, other.activityInfo); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + activityInfo.writeToParcel(out, flags); + } + + private ActivityHintEvent(Parcel in) { + this.type = in.readInt(); + this.activityInfo = ActivityInfo.CREATOR.createFromParcel(in); + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<ActivityHintEvent> CREATOR + = new Parcelable.Creator<ActivityHintEvent>() { + public ActivityHintEvent createFromParcel(Parcel in) { + return new ActivityHintEvent(in); + } + + public ActivityHintEvent[] newArray(int size) { + return new ActivityHintEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java new file mode 100644 index 000000000000..f47a42cffdd8 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import java.util.Objects; + +import android.os.Parcelable; +import android.os.Parcel; + +/** + * Provide minimal information for launched activities to iorap.<br /><br /> + * + * This uniquely identifies a system-wide activity by providing the {@link #packageName} and + * {@link #activityName}. + * + * @see ActivityHintEvent + * @see AppIntentEvent + * + * @hide + */ +public class ActivityInfo implements Parcelable { + + /** The name of the package, for example {@code com.android.calculator}. */ + public final String packageName; + /** The name of the activity, for example {@code .activities.activity.MainActivity} */ + public final String activityName; + + public ActivityInfo(String packageName, String activityName) { + this.packageName = packageName; + this.activityName = activityName; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + Objects.requireNonNull(packageName, "packageName"); + Objects.requireNonNull(activityName, "activityName"); + } + + @Override + public String toString() { + return String.format("{packageName: %s, activityName: %s}", packageName, activityName); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof ActivityInfo) { + return equals((ActivityInfo) other); + } + return false; + } + + private boolean equals(ActivityInfo other) { + return Objects.equals(packageName, other.packageName) && + Objects.equals(activityName, other.activityName); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(packageName); + out.writeString(activityName); + } + + private ActivityInfo(Parcel in) { + packageName = in.readString(); + activityName = in.readString(); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<ActivityInfo> CREATOR + = new Parcelable.Creator<ActivityInfo>() { + public ActivityInfo createFromParcel(Parcel in) { + return new ActivityInfo(in); + } + + public ActivityInfo[] newArray(int size) { + return new ActivityInfo[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java new file mode 100644 index 000000000000..1cd37b5546b9 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Notifications for iorapd specifying when a system-wide intent defaults change.<br /><br /> + * + * Intent defaults provide a mechanism for an app to register itself as an automatic handler. + * For example the camera app might be registered as the default handler for + * {@link android.provider.MediaStore#INTENT_ACTION_STILL_IMAGE_CAMERA} intent. Subsequently, + * if an arbitrary other app requests for a still image camera photo to be taken, the system + * will launch the respective default camera app to be launched to handle that request.<br /><br /> + * + * In some cases iorapd might need to know default intents, e.g. for boot-time pinning of + * applications that resolve from the default intent. If the application would now be resolved + * differently, iorapd would unpin the old application and pin the new application.<br /><br /> + * + * @hide + */ +public class AppIntentEvent implements Parcelable { + + /** @see android.content.Intent#CATEGORY_DEFAULT */ + public static final int TYPE_DEFAULT_INTENT_CHANGED = 0; + private static final int TYPE_MAX = 0; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_DEFAULT_INTENT_CHANGED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + + public final ActivityInfo oldActivityInfo; + public final ActivityInfo newActivityInfo; + + // TODO: Probably need the corresponding action here as well. + + public static AppIntentEvent createDefaultIntentChanged(ActivityInfo oldActivityInfo, + ActivityInfo newActivityInfo) { + return new AppIntentEvent(TYPE_DEFAULT_INTENT_CHANGED, oldActivityInfo, + newActivityInfo); + } + + private AppIntentEvent(@Type int type, ActivityInfo oldActivityInfo, + ActivityInfo newActivityInfo) { + this.type = type; + this.oldActivityInfo = oldActivityInfo; + this.newActivityInfo = newActivityInfo; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + Objects.requireNonNull(oldActivityInfo, "oldActivityInfo"); + Objects.requireNonNull(oldActivityInfo, "newActivityInfo"); + } + + @Override + public String toString() { + return String.format("{oldActivityInfo: %s, newActivityInfo: %s}", oldActivityInfo, + newActivityInfo); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof AppIntentEvent) { + return equals((AppIntentEvent) other); + } + return false; + } + + private boolean equals(AppIntentEvent other) { + return type == other.type && + Objects.equals(oldActivityInfo, other.oldActivityInfo) && + Objects.equals(newActivityInfo, other.newActivityInfo); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + oldActivityInfo.writeToParcel(out, flags); + newActivityInfo.writeToParcel(out, flags); + } + + private AppIntentEvent(Parcel in) { + this.type = in.readInt(); + this.oldActivityInfo = ActivityInfo.CREATOR.createFromParcel(in); + this.newActivityInfo = ActivityInfo.CREATOR.createFromParcel(in); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<AppIntentEvent> CREATOR + = new Parcelable.Creator<AppIntentEvent>() { + public AppIntentEvent createFromParcel(Parcel in) { + return new AppIntentEvent(in); + } + + public AppIntentEvent[] newArray(int size) { + return new AppIntentEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java b/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java new file mode 100644 index 000000000000..34aedd7685d8 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.startop.iorap; + +/** + * Convenience short-hand to throw {@link IllegalAccessException} when the arguments + * are out-of-range. + */ +public class CheckHelpers { + /** @throws IllegalAccessException if {@param type} is not in {@code [0..maxValue]} */ + public static void checkTypeInRange(int type, int maxValue) { + if (type < 0) { + throw new IllegalArgumentException( + String.format("type must be non-negative (value=%d)", type)); + } + if (type > maxValue) { + throw new IllegalArgumentException( + String.format("type out of range (value=%d, max=%d)", type, maxValue)); + } + } + + /** @throws IllegalAccessException if {@param state} is not in {@code [0..maxValue]} */ + public static void checkStateInRange(int state, int maxValue) { + if (state < 0) { + throw new IllegalArgumentException( + String.format("state must be non-negative (value=%d)", state)); + } + if (state > maxValue) { + throw new IllegalArgumentException( + String.format("state out of range (value=%d, max=%d)", state, maxValue)); + } + } +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java b/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java new file mode 100644 index 000000000000..aa4eea716363 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.annotation.NonNull; +import android.os.Parcelable; +import android.os.Parcel; +import android.net.Uri; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Forward package manager events to iorapd. <br /><br /> + * + * Knowing when packages are modified by the system are a useful tidbit to help with performance: + * for example when a package is replaced, it could be a hint used to invalidate any collected + * io profiles used for prefetching or pinning. + * + * @hide + */ +public class PackageEvent implements Parcelable { + + /** @see android.content.Intent#ACTION_PACKAGE_REPLACED */ + public static final int TYPE_REPLACED = 0; + private static final int TYPE_MAX = 0; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_REPLACED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + + /** The path that a package is installed in, for example {@code /data/app/.../base.apk}. */ + public final Uri packageUri; + /** The name of the package, for example {@code com.android.calculator}. */ + public final String packageName; + + @NonNull + public static PackageEvent createReplaced(Uri packageUri, String packageName) { + return new PackageEvent(TYPE_REPLACED, packageUri, packageName); + } + + private PackageEvent(@Type int type, Uri packageUri, String packageName) { + this.type = type; + this.packageUri = packageUri; + this.packageName = packageName; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + Objects.requireNonNull(packageUri, "packageUri"); + Objects.requireNonNull(packageName, "packageName"); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof PackageEvent) { + return equals((PackageEvent) other); + } + return false; + } + + private boolean equals(PackageEvent other) { + return type == other.type && + Objects.equals(packageUri, other.packageUri) && + Objects.equals(packageName, other.packageName); + } + + @Override + public String toString() { + return String.format("{packageUri: %s, packageName: %s}", packageUri, packageName); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + packageUri.writeToParcel(out, flags); + out.writeString(packageName); + } + + private PackageEvent(Parcel in) { + this.type = in.readInt(); + this.packageUri = Uri.CREATOR.createFromParcel(in); + this.packageName = in.readString(); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<PackageEvent> CREATOR + = new Parcelable.Creator<PackageEvent>() { + public PackageEvent createFromParcel(Parcel in) { + return new PackageEvent(in); + } + + public PackageEvent[] newArray(int size) { + return new PackageEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java new file mode 100644 index 000000000000..2c79319a1459 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.NonNull; + +/** + * Uniquely identify an {@link com.google.android.startop.iorap.IIorap} method invocation, + * used for asynchronous callbacks by the server. <br /><br /> + * + * As all system server binder calls must be {@code oneway}, this means all invocations + * into {@link com.google.android.startop.iorap.IIorap} are non-blocking. The request ID + * exists to associate all calls with their respective callbacks in + * {@link com.google.android.startop.iorap.ITaskListener}. + * + * @see com.google.android.startop.iorap.IIorap + * + * @hide + */ +public class RequestId implements Parcelable { + + public final long requestId; + + private static Object mLock = new Object(); + private static long mNextRequestId = 0; + + /** + * Create a monotonically increasing request ID.<br /><br /> + * + * It is invalid to re-use the same request ID for multiple method calls on + * {@link com.google.android.startop.iorap.IIorap}; a new request ID must be created + * each time. + */ + @NonNull public static RequestId nextValueForSequence() { + long currentRequestId; + synchronized (mLock) { + currentRequestId = mNextRequestId; + ++mNextRequestId; + } + return new RequestId(currentRequestId); + } + + private RequestId(long requestId) { + this.requestId = requestId; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + if (requestId < 0) { + throw new IllegalArgumentException("request id must be non-negative"); + } + } + + @Override + public String toString() { + return String.format("{requestId: %ld}", requestId); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof RequestId) { + return equals((RequestId) other); + } + return false; + } + + private boolean equals(RequestId other) { + return requestId == other.requestId; + } + + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeLong(requestId); + } + + private RequestId(Parcel in) { + requestId = in.readLong(); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<RequestId> CREATOR + = new Parcelable.Creator<RequestId>() { + public RequestId createFromParcel(Parcel in) { + return new RequestId(in); + } + + public RequestId[] newArray(int size) { + return new RequestId[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java new file mode 100644 index 000000000000..75d47f9e3d17 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Forward system service events to iorapd. + * + * @see com.android.server.SystemService + * + * @hide + */ +public class SystemServiceEvent implements Parcelable { + + /** @see com.android.server.SystemService#onBootPhase */ + public static final int TYPE_BOOT_PHASE = 0; + /** @see com.android.server.SystemService#onStart */ + public static final int TYPE_START = 1; + private static final int TYPE_MAX = TYPE_START; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_BOOT_PHASE, + TYPE_START, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + + // TODO: do we want to pass the exact build phase enum? + + public SystemServiceEvent(@Type int type) { + this.type = type; + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + } + + @Override + public String toString() { + return String.format("{type: %d}", type); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof SystemServiceEvent) { + return equals((SystemServiceEvent) other); + } + return false; + } + + private boolean equals(SystemServiceEvent other) { + return type == other.type; + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + } + + private SystemServiceEvent(Parcel in) { + this.type = in.readInt(); + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<SystemServiceEvent> CREATOR + = new Parcelable.Creator<SystemServiceEvent>() { + public SystemServiceEvent createFromParcel(Parcel in) { + return new SystemServiceEvent(in); + } + + public SystemServiceEvent[] newArray(int size) { + return new SystemServiceEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java new file mode 100644 index 000000000000..b77c03c1584a --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Forward user events to iorapd.<br /><br /> + * + * Knowledge of the logged-in user is reserved to be used to set-up appropriate policies + * by iorapd (e.g. to handle user default pinned applications changing). + * + * @see com.android.server.SystemService + * + * @hide + */ +public class SystemServiceUserEvent implements Parcelable { + + /** @see com.android.server.SystemService#onStartUser */ + public static final int TYPE_START_USER = 0; + /** @see com.android.server.SystemService#onUnlockUser */ + public static final int TYPE_UNLOCK_USER = 1; + /** @see com.android.server.SystemService#onSwitchUser*/ + public static final int TYPE_SWITCH_USER = 2; + /** @see com.android.server.SystemService#onStopUser */ + public static final int TYPE_STOP_USER = 3; + /** @see com.android.server.SystemService#onCleanupUser */ + public static final int TYPE_CLEANUP_USER = 4; + private static final int TYPE_MAX = TYPE_CLEANUP_USER; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_START_USER, + TYPE_UNLOCK_USER, + TYPE_SWITCH_USER, + TYPE_STOP_USER, + TYPE_CLEANUP_USER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + public final int userHandle; + + public SystemServiceUserEvent(@Type int type, int userHandle) { + this.type = type; + this.userHandle = userHandle; + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + if (userHandle < 0) { + throw new IllegalArgumentException("userHandle must be non-negative"); + } + } + + @Override + public String toString() { + return String.format("{type: %d, userHandle: %d}", type, userHandle); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof SystemServiceUserEvent) { + return equals((SystemServiceUserEvent) other); + } + return false; + } + + private boolean equals(SystemServiceUserEvent other) { + return type == other.type && + userHandle == other.userHandle; + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + out.writeInt(userHandle); + } + + private SystemServiceUserEvent(Parcel in) { + this.type = in.readInt(); + this.userHandle = in.readInt(); + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<SystemServiceUserEvent> CREATOR + = new Parcelable.Creator<SystemServiceUserEvent>() { + public SystemServiceUserEvent createFromParcel(Parcel in) { + return new SystemServiceUserEvent(in); + } + + public SystemServiceUserEvent[] newArray(int size) { + return new SystemServiceUserEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java b/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java new file mode 100644 index 000000000000..b5fd6d8d1c45 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.startop.iorap; + +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Result data accompanying a request for {@link com.google.android.startop.iorap.ITaskListener} + * callbacks.<br /><br /> + * + * Following {@link com.google.android.startop.iorap.IIorap} method invocation, + * iorapd will issue in-order callbacks for that corresponding {@link RequestId}.<br /><br /> + * + * State transitions are as follows: <br /><br /> + * + * <pre> + * ┌─────────────────────────────┐ + * │ ▼ + * ┌───────┐ ┌─────────┐ ╔═══════════╗ + * ──▶ │ BEGAN │ ──▶ │ ONGOING │ ──▶ ║ COMPLETED ║ + * └───────┘ └─────────┘ ╚═══════════╝ + * │ │ + * │ │ + * ▼ │ + * ╔═══════╗ │ + * ──▶ ║ ERROR ║ ◀─────┘ + * ╚═══════╝ + * + * </pre> <!-- system/iorap/docs/binder/TaskResult.dot --> + * + * @hide + */ +public class TaskResult implements Parcelable { + + public static final int STATE_BEGAN = 0; + public static final int STATE_ONGOING = 1; + public static final int STATE_COMPLETED = 2; + public static final int STATE_ERROR = 3; + private static final int STATE_MAX = STATE_ERROR; + + /** @hide */ + @IntDef(flag = true, prefix = { "STATE_" }, value = { + STATE_BEGAN, + STATE_ONGOING, + STATE_COMPLETED, + STATE_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface State {} + + @State public final int state; + + @Override + public String toString() { + return String.format("{state: %d}", state); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof TaskResult) { + return equals((TaskResult) other); + } + return false; + } + + private boolean equals(TaskResult other) { + return state == other.state; + } + + public TaskResult(@State int state) { + this.state = state; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkStateInRange(state, STATE_MAX); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(state); + } + + private TaskResult(Parcel in) { + state = in.readInt(); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<TaskResult> CREATOR + = new Parcelable.Creator<TaskResult>() { + public TaskResult createFromParcel(Parcel in) { + return new TaskResult(in); + } + + public TaskResult[] newArray(int size) { + return new TaskResult[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp new file mode 100644 index 000000000000..76057846e896 --- /dev/null +++ b/startop/iorap/tests/Android.bp @@ -0,0 +1,40 @@ +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: once b/80095087 is fixed, rewrite this back to android_test +java_library { + name: "libiorap-java-test-lib", + srcs: ["src/**/*.kt"], + + static_libs: [ + // non-test dependencies + "libiorap-java", + // test android dependencies + "platform-test-annotations", + "android-support-test", + // test framework dependencies + "mockito-target-inline-minus-junit4", + // "mockito-target-minus-junit4", + // Mockito also requires JNI (see Android.mk) + // and android:debuggable=true (see AndroidManifest.xml) + "truth-prebuilt", + ], + + // sdk_version: "current", + // certificate: "platform", + + libs: ["android.test.base", "android.test.runner"], + + // test_suites: ["device-tests"], +} diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk new file mode 100644 index 000000000000..1b2aa46a6418 --- /dev/null +++ b/startop/iorap/tests/Android.mk @@ -0,0 +1,46 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# android_test does not support JNI libraries +# TODO: once b/80095087 is fixed, rewrite this back to android_test +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_JACK_FLAGS := --multi-dex native +LOCAL_DX_FLAGS := --multi-dex + +LOCAL_PACKAGE_NAME := libiorap-java-tests +LOCAL_COMPATIBILITY_SUITE := device-tests + +LOCAL_STATIC_JAVA_LIBRARIES := \ + libiorap-java-test-lib + +LOCAL_MULTILIB := both + +LOCAL_JNI_SHARED_LIBRARIES := \ + libdexmakerjvmtiagent \ + libstaticjvmtiagent \ + libmultiplejvmtiagentsinterferenceagent + +LOCAL_JAVA_LIBRARIES := \ + android.test.base \ + android.test.runner + +# Use private APIs +LOCAL_CERTIFICATE := platform +LOCAL_PRIVATE_PLATFORM_APIS := true + +include $(BUILD_PACKAGE) diff --git a/startop/iorap/tests/AndroidManifest.xml b/startop/iorap/tests/AndroidManifest.xml new file mode 100644 index 000000000000..99f4add6579f --- /dev/null +++ b/startop/iorap/tests/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!--suppress AndroidUnknownAttribute --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.startop.iorap.tests" + android:sharedUserId="com.google.android.startop.iorap.tests" + android:versionCode="1" + android:versionName="1.0" > + + <!--suppress AndroidDomInspection --> + <instrumentation + android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.google.android.startop.iorap.tests" /> + + <!-- + 'debuggable=true' is required to properly load mockito jvmti dependencies, + otherwise it gives the following error at runtime: + + Openjdkjvmti plugin was loaded on a non-debuggable Runtime. + Plugin was loaded too late to change runtime state to DEBUGGABLE. --> + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> +</manifest> diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt new file mode 100644 index 000000000000..4ba44a93f2a8 --- /dev/null +++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.google.android.startop.iorap + +import android.net.Uri +import android.os.ServiceManager +import android.support.test.filters.MediumTest +import org.junit.Test +import org.junit.Ignore +import org.mockito.Mockito.* + +// @Ignore("Test is disabled until iorapd is added to init and there's selinux policies for it") +@MediumTest +class IIorapIntegrationTest { + /** + * @throws ServiceManager.ServiceNotFoundException if iorapd service could not be found + */ + private val iorapService : IIorap by lazy { + // TODO: connect to 'iorapd.stub' which doesn't actually do any work other than reply. + IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd")) + + // Use 'adb shell setenforce 0' otherwise this whole test fails, + // because the servicemanager is not allowed to hand out the binder token for iorapd. + + // TODO: implement the selinux policies for iorapd. + } + + // A dummy binder stub implementation is required to use with mockito#spy. + // Mockito overrides the methods at runtime and tracks how methods were invoked. + open class DummyTaskListener : ITaskListener.Stub() { + // Note: make parameters nullable to avoid the kotlin IllegalStateExceptions + // from using the mockito matchers (eq, argThat, etc). + override fun onProgress(requestId: RequestId?, result: TaskResult?) { + } + + override fun onComplete(requestId: RequestId?, result: TaskResult?) { + } + } + + private fun testAnyMethod(func : (RequestId) -> Unit) { + val taskListener = spy(DummyTaskListener())!! + + try { + iorapService.setTaskListener(taskListener) + // Note: Binder guarantees total order for oneway messages sent to the same binder + // interface, so we don't need any additional blocking here before sending later calls. + + // Every new method call should have a unique request id. + val requestId = RequestId.nextValueForSequence()!! + + // Apply the specific function under test. + func(requestId) + + // Typical mockito behavior is to allow any-order callbacks, but we want to test order. + val inOrder = inOrder(taskListener) + + // The "stub" behavior of iorapd is that every request immediately gets a response of + // BEGAN,ONGOING,COMPLETED + inOrder.verify(taskListener, timeout(100)). + onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN }) + inOrder.verify(taskListener, timeout(100)). + onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING }) + inOrder.verify(taskListener, timeout(100)). + onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED }) + inOrder.verifyNoMoreInteractions() + + } finally { + iorapService.setTaskListener(null) + } + } + + @Test + fun testOnPackageEvent() { + testAnyMethod { requestId : RequestId -> + iorapService.onPackageEvent(requestId, + PackageEvent.createReplaced( + Uri.parse("https://www.google.com"), "com.fake.package")) + } + } + + @Test + fun testOnAppIntentEvent() { + testAnyMethod { requestId : RequestId -> + iorapService.onAppIntentEvent(requestId, AppIntentEvent.createDefaultIntentChanged( + ActivityInfo("dont care", "dont care"), + ActivityInfo("dont care 2", "dont care 2"))) + } + } + + @Test + fun testOnSystemServiceEvent() { + testAnyMethod { requestId : RequestId -> + iorapService.onSystemServiceEvent(requestId, + SystemServiceEvent(SystemServiceEvent.TYPE_START)) + } + } + + @Test + fun testOnSystemServiceUserEvent() { + testAnyMethod { requestId : RequestId -> + iorapService.onSystemServiceUserEvent(requestId, + SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER,0)) + } + } +} diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt new file mode 100644 index 000000000000..4abbb3e9f162 --- /dev/null +++ b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.google.android.startop.iorap + +import android.net.Uri +import android.os.Parcel +import android.os.Parcelable +import android.support.test.filters.SmallTest +import org.junit.Test +import org.junit.runner.RunWith +import com.google.common.truth.Truth.assertThat +import org.junit.runners.Parameterized + +/** + * Basic unit tests to ensure that all of the [Parcelable]s in [com.google.android.startop.iorap] + * have a valid-conforming interface implementation. + */ +@SmallTest +@RunWith(Parameterized::class) +class ParcelablesTest<T : Parcelable>(private val inputData : InputData<T>) { + companion object { + private val initialRequestId = RequestId.nextValueForSequence()!! + + @JvmStatic + @Parameterized.Parameters + fun data() = listOf( + InputData( + newActivityInfo(), + newActivityInfo(), + ActivityInfo("some package", "some other activity")), + InputData( + ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()), + ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()), + ActivityHintEvent(ActivityHintEvent.TYPE_POST_COMPLETED, + newActivityInfo())), + InputData( + AppIntentEvent.createDefaultIntentChanged(newActivityInfo(), + newActivityInfoOther()), + AppIntentEvent.createDefaultIntentChanged(newActivityInfo(), + newActivityInfoOther()), + AppIntentEvent.createDefaultIntentChanged(newActivityInfoOther(), + newActivityInfo())), + InputData( + PackageEvent.createReplaced(newUri(), "some package"), + PackageEvent.createReplaced(newUri(), "some package"), + PackageEvent.createReplaced(newUri(), "some other package") + ), + InputData(initialRequestId, cloneRequestId(initialRequestId), + RequestId.nextValueForSequence()), + InputData( + SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE), + SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE), + SystemServiceEvent(SystemServiceEvent.TYPE_START)), + InputData( + SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345), + SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345), + SystemServiceUserEvent(SystemServiceUserEvent.TYPE_CLEANUP_USER, 12345)), + InputData( + TaskResult(TaskResult.STATE_COMPLETED), + TaskResult(TaskResult.STATE_COMPLETED), + TaskResult(TaskResult.STATE_ONGOING)) + ) + + private fun newActivityInfo() : ActivityInfo { + return ActivityInfo("some package", "some activity") + } + + private fun newActivityInfoOther() : ActivityInfo { + return ActivityInfo("some package 2", "some activity 2") + } + + private fun newUri() : Uri { + return Uri.parse("https://www.google.com") + } + + private fun cloneRequestId(requestId: RequestId) : RequestId { + val constructor = requestId::class.java.declaredConstructors[0] + constructor.isAccessible = true + return constructor.newInstance(requestId.requestId) as RequestId + } + } + + /** + * Test for [Object.equals] implementation. + */ + @Test + fun testEquality() { + assertThat(inputData.valid).isEqualTo(inputData.valid) + assertThat(inputData.valid).isEqualTo(inputData.validCopy) + assertThat(inputData.valid).isNotEqualTo(inputData.validOther) + } + + /** + * Test for [Parcelable] implementation. + */ + @Test + fun testParcelRoundTrip() { + // calling writeToParcel and then T::CREATOR.createFromParcel would return the same data. + val assertParcels = { it : T, data : InputData<T> -> + val parcel = Parcel.obtain() + it.writeToParcel(parcel, 0) + parcel.setDataPosition(0) // future reads will see all previous writes. + assertThat(it).isEqualTo(data.createFromParcel(parcel)) + parcel.recycle() + } + + assertParcels(inputData.valid, inputData) + assertParcels(inputData.validCopy, inputData) + assertParcels(inputData.validOther, inputData) + } + + data class InputData<T : Parcelable>(val valid : T, val validCopy : T, val validOther : T) { + val kls = valid.javaClass + init { + assertThat(valid).isNotSameAs(validCopy) + // Don't use isInstanceOf because of phantom warnings in intellij about Class! + assertThat(validCopy.javaClass).isEqualTo(valid.javaClass) + assertThat(validOther.javaClass).isEqualTo(valid.javaClass) + } + + fun createFromParcel(parcel : Parcel) : T { + val field = kls.getDeclaredField("CREATOR") + val creator = field.get(null) as Parcelable.Creator<T> + + return creator.createFromParcel(parcel) + } + } +} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 82808fc30291..6eaecc6760bc 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1633,11 +1633,21 @@ public class CarrierConfigManager { * When {@code false}, use default title for Enhanced 4G LTE Mode settings. * When {@code true}, use the variant. * @hide + * @deprecated use {@link #KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT}. */ + @Deprecated public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL = "enhanced_4g_lte_title_variant_bool"; /** + * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings. + * Default value is 0, which indicates the default title string. + * @hide + */ + public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = + "enhanced_4g_lte_title_variant_int"; + + /** * Indicates whether the carrier wants to notify the user when handover of an LTE video call to * WIFI fails. * <p> @@ -2420,6 +2430,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null); sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false); + sDefaults.putInt(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, 0); sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false); sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null); sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false); diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index ee5cdc2780db..d7169b23d94b 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -319,6 +319,29 @@ public class DisconnectCause { */ public static final int IMS_SIP_ALTERNATE_EMERGENCY_CALL = 71; + /** + * Indicates that a new outgoing call cannot be placed because there is already an outgoing + * call dialing out. + */ + public static final int ALREADY_DIALING = 72; + + /** + * Indicates that a new outgoing call cannot be placed while there is a ringing call. + */ + public static final int CANT_CALL_WHILE_RINGING = 73; + + /** + * Indicates that a new outgoing call cannot be placed because calling has been disabled using + * the ro.telephony.disable-call system property. + */ + public static final int CALLING_DISABLED = 74; + + /** + * Indicates that a new outgoing call cannot be placed because there is currently an ongoing + * foreground and background call. + */ + public static final int TOO_MANY_ONGOING_CALLS = 75; + //********************************************************************************************* // When adding a disconnect type: // 1) Update toString() with the newly added disconnect type. @@ -474,6 +497,14 @@ public class DisconnectCause { return "NORMAL_UNSPECIFIED"; case IMS_SIP_ALTERNATE_EMERGENCY_CALL: return "IMS_SIP_ALTERNATE_EMERGENCY_CALL"; + case ALREADY_DIALING: + return "ALREADY_DIALING"; + case CANT_CALL_WHILE_RINGING: + return "CANT_CALL_WHILE_RINGING"; + case CALLING_DISABLED: + return "CALLING_DISABLED"; + case TOO_MANY_ONGOING_CALLS: + return "TOO_MANY_ONGOING_CALLS"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 5e4518f67538..79298fd54c50 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -33,8 +33,9 @@ import android.os.Parcelable; * Represents the neighboring cell information, including * Received Signal Strength and Cell ID location. * - * @deprecated This class should not be used by anyone targeting SDK level 29 (Q) or higher. - * Instead callers should use {@Link android.telephony.CellInfo}. + * @deprecated This class should not be used by any app targeting + * {@link Build.VERSION_CODES.Q Android Q} or higher. Instead callers should use + * {@Link android.telephony.CellInfo CellInfo}. */ @Deprecated public class NeighboringCellInfo implements Parcelable diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index f2b73dccee2d..7469186a5d51 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.NetworkRegistrationState.Domain; import android.text.TextUtils; import java.lang.annotation.Retention; @@ -1595,7 +1596,7 @@ public class ServiceState implements Parcelable { /** * Get all of the available network registration states. * - * @return List of registration states + * @return List of {@link NetworkRegistrationState} * @hide */ @SystemApi @@ -1606,14 +1607,30 @@ public class ServiceState implements Parcelable { } /** - * Get the network registration states with given transport type. + * Get the network registration states for the transport type. * - * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType} - * @return List of registration states. + * @param transportType The {@link AccessNetworkConstants.TransportType transport type} + * @return List of {@link NetworkRegistrationState} * @hide + * + * @deprecated Use {@link #getNetworkRegistrationStatesFromTransportType(int)} */ + @Deprecated @SystemApi public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) { + return getNetworkRegistrationStatesForTransportType(transportType); + } + + /** + * Get the network registration states for the transport type. + * + * @param transportType The {@link AccessNetworkConstants.TransportType transport type} + * @return List of {@link NetworkRegistrationState} + * @hide + */ + @SystemApi + public List<NetworkRegistrationState> getNetworkRegistrationStatesForTransportType( + int transportType) { List<NetworkRegistrationState> list = new ArrayList<>(); synchronized (mNetworkRegistrationStates) { @@ -1628,16 +1645,57 @@ public class ServiceState implements Parcelable { } /** - * Get the network registration states with given transport type and domain. + * Get the network registration states for the network domain. * - * @param domain The network domain. Must be {@link NetworkRegistrationState#DOMAIN_CS} or - * {@link NetworkRegistrationState#DOMAIN_PS}. - * @param transportType The transport type. See {@link AccessNetworkConstants.TransportType} - * @return The matching NetworkRegistrationState. + * @param domain The network {@link NetworkRegistrationState.Domain domain} + * @return List of {@link NetworkRegistrationState} * @hide */ @SystemApi - public NetworkRegistrationState getNetworkRegistrationStates(int domain, int transportType) { + public List<NetworkRegistrationState> getNetworkRegistrationStatesForDomain( + @Domain int domain) { + List<NetworkRegistrationState> list = new ArrayList<>(); + + synchronized (mNetworkRegistrationStates) { + for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { + if (networkRegistrationState.getDomain() == domain) { + list.add(networkRegistrationState); + } + } + } + + return list; + } + + /** + * Get the network registration state for the transport type and network domain. + * + * @param domain The network {@link NetworkRegistrationState.Domain domain} + * @param transportType The {@link AccessNetworkConstants.TransportType transport type} + * @return The matching {@link NetworkRegistrationState} + * @hide + * + * @deprecated Use {@link #getNetworkRegistrationState(int, int)} + */ + @Deprecated + @SystemApi + public NetworkRegistrationState getNetworkRegistrationStates(@Domain int domain, + int transportType) { + return getNetworkRegistrationState(domain, transportType); + } + + /** + * Get the network registration state for the transport type and network domain. + * + * @param domain The network {@link NetworkRegistrationState.Domain domain} + * @param transportType The {@link AccessNetworkConstants.TransportType transport type} + * @return The matching {@link NetworkRegistrationState} + * @hide + * + */ + @SystemApi + public NetworkRegistrationState getNetworkRegistrationState(@Domain int domain, + int transportType) { synchronized (mNetworkRegistrationStates) { for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) { if (networkRegistrationState.getTransportType() == transportType @@ -1669,5 +1727,4 @@ public class ServiceState implements Parcelable { mNetworkRegistrationStates.add(regState); } } - } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f83ea68af1c5..bba4868c54c1 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -166,7 +166,6 @@ public class TelephonyManager { /** @hide */ static public final int OTASP_SIM_UNPROVISIONED = 5; - /** @hide */ static public final int KEY_TYPE_EPDG = 1; @@ -2914,7 +2913,7 @@ public class TelephonyManager { * of time the mode may be unknown. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE} * or {@link PhoneConstants#LTE_ON_CDMA_TRUE} @@ -5949,7 +5948,7 @@ public class TelephonyManager { * Sets the network selection mode to automatic. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling @@ -5974,7 +5973,7 @@ public class TelephonyManager { * Perform a radio scan and return the list of available networks. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * <p> Note that this scan can take a long time (sometimes minutes) to happen. * @@ -6053,7 +6052,7 @@ public class TelephonyManager { * Ask the radio to connect to the input network and change selection mode to manual. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling @@ -6078,7 +6077,7 @@ public class TelephonyManager { * Ask the radio to connect to the input network and change selection mode to manual. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling @@ -6111,7 +6110,7 @@ public class TelephonyManager { * Get the network selection mode. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * @return the network selection mode. * @@ -7001,7 +7000,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - isDataRoamingEnabled = telephony.isDataRoamingEnabled(getSubId()); + isDataRoamingEnabled = telephony.isDataRoamingEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#isDataRoamingEnabled", e); @@ -7013,7 +7013,7 @@ public class TelephonyManager { * Gets the roaming mode for CDMA phone. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * @return one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, {@link #CDMA_ROAMING_MODE_HOME}, * {@link #CDMA_ROAMING_MODE_AFFILIATED}, {@link #CDMA_ROAMING_MODE_ANY}. @@ -7038,7 +7038,7 @@ public class TelephonyManager { * Sets the roaming mode for CDMA phone to the given mode {@code mode}. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * @param mode should be one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, * {@link #CDMA_ROAMING_MODE_HOME}, {@link #CDMA_ROAMING_MODE_AFFILIATED}, @@ -7107,7 +7107,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - telephony.setDataRoamingEnabled(getSubId(), isEnabled); + telephony.setDataRoamingEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), isEnabled); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#setDataRoamingEnabled", e); @@ -7900,7 +7901,7 @@ public class TelephonyManager { * Returns the current {@link ServiceState} information. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -8369,7 +8370,7 @@ public class TelephonyManager { * Checks if phone is in emergency callback mode. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the - * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} * * @return true if phone is in emergency callback mode. * @hide diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 0e4a7addd58c..951bed468eda 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -31,6 +31,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; @@ -1205,7 +1206,8 @@ public class ApnSetting implements Parcelable { /** @hide */ public static int getMvnoTypeIntFromString(String mvnoType) { - Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoType); + String mvnoTypeString = TextUtils.isEmpty(mvnoType) ? mvnoType : mvnoType.toLowerCase(); + Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString); return mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt; } diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.aidl b/telephony/java/android/telephony/emergency/EmergencyNumber.aidl new file mode 100644 index 000000000000..bfb0a59b16c8 --- /dev/null +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.emergency; + +parcelable EmergencyNumber; diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java new file mode 100644 index 000000000000..d6a08543b9cd --- /dev/null +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.emergency; + +import android.annotation.IntDef; +import android.hardware.radio.V1_3.EmergencyNumberSource; +import android.hardware.radio.V1_3.EmergencyServiceCategory; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A parcelable class that wraps and retrieves the information of number, service category(s) and + * country code for a specific emergency number. + */ +public final class EmergencyNumber implements Parcelable { + + private static final String LOG_TAG = "EmergencyNumber"; + + /** + * Defining Emergency Service Category as follows: + * - General emergency call, all categories; + * - Police; + * - Ambulance; + * - Fire Brigade; + * - Marine Guard; + * - Mountain Rescue; + * - Manually Initiated eCall (MIeC); + * - Automatically Initiated eCall (AIeC); + * + * Category UNSPECIFIED (General emergency call, all categories) indicates that no specific + * services are associated with this emergency number; if the emergency number is specified, + * it has one or more defined emergency service categories. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + * + * @hide + */ + @IntDef(flag = true, prefix = { "EMERGENCY_SERVICE_CATEGORY_" }, value = { + EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + EMERGENCY_SERVICE_CATEGORY_POLICE, + EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD, + EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE, + EMERGENCY_SERVICE_CATEGORY_MIEC, + EMERGENCY_SERVICE_CATEGORY_AIEC + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EmergencyServiceCategories {} + + /** + * Emergency Service Category UNSPECIFIED (General emergency call, all categories) bit-field + * indicates that no specific services are associated with this emergency number; if the + * emergency number is specified, it has one or more defined emergency service categories. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = + EmergencyServiceCategory.UNSPECIFIED; + /** + * Bit-field that indicates Emergency Service Category for Police. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_POLICE = EmergencyServiceCategory.POLICE; + /** + * Bit-field that indicates Emergency Service Category for Ambulance. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_AMBULANCE = + EmergencyServiceCategory.AMBULANCE; + /** + * Bit-field that indicates Emergency Service Category for Fire Brigade. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = + EmergencyServiceCategory.FIRE_BRIGADE; + /** + * Bit-field that indicates Emergency Service Category for Marine Guard. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = + EmergencyServiceCategory.MARINE_GUARD; + /** + * Bit-field that indicates Emergency Service Category for Mountain Rescue. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = + EmergencyServiceCategory.MOUNTAIN_RESCUE; + /** + * Bit-field that indicates Emergency Service Category for Manually Initiated eCall (MIeC) + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_MIEC = EmergencyServiceCategory.MIEC; + /** + * Bit-field that indicates Emergency Service Category for Automatically Initiated eCall (AIeC) + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_SERVICE_CATEGORY_AIEC = EmergencyServiceCategory.AIEC; + + private static final Set<Integer> EMERGENCY_SERVICE_CATEGORY_SET; + static { + EMERGENCY_SERVICE_CATEGORY_SET = new HashSet<Integer>(); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_POLICE); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AMBULANCE); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MIEC); + EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AIEC); + } + + /** + * The source to tell where the corresponding @1.3::EmergencyNumber comes from. + * + * The emergency number has one or more defined emergency number sources. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + * + * @hide + */ + @IntDef(flag = true, prefix = { "EMERGENCY_NUMBER_SOURCE_" }, value = { + EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EMERGENCY_NUMBER_SOURCE_SIM, + EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, + EMERGENCY_NUMBER_SOURCE_DEFAULT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EmergencyNumberSources {} + + /** + * Bit-field which indicates the number is from the network signaling. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = + EmergencyNumberSource.NETWORK_SIGNALING; + /** + * Bit-field which indicates the number is from the sim. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_NUMBER_SOURCE_SIM = EmergencyNumberSource.SIM; + /** Bit-field which indicates the number is from the modem config. */ + public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = + EmergencyNumberSource.MODEM_CONFIG; + /** + * Bit-field which indicates the number is available as default. + * + * 112, 911 must always be available; additionally, 000, 08, 110, 999, 118 and 119 must be + * available when sim is not present. + * + * Reference: 3gpp 22.101, Section 10 - Emergency Calls + */ + public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = EmergencyNumberSource.DEFAULT; + + private static final Set<Integer> EMERGENCY_NUMBER_SOURCE_SET; + static { + EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>(); + EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING); + EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_SIM); + EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG); + EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT); + } + + private final String mNumber; + private final String mCountryIso; + private final int mEmergencyServiceCategoryBitmask; + private final int mEmergencyNumberSourceBitmask; + + /** @hide */ + public EmergencyNumber(String number, String countryIso, + int emergencyServiceCategories, + int emergencyNumberSources) { + this.mNumber = number; + this.mCountryIso = countryIso; + this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories; + this.mEmergencyNumberSourceBitmask = emergencyNumberSources; + } + + /** @hide */ + public EmergencyNumber(Parcel source) { + mNumber = source.readString(); + mCountryIso = source.readString(); + mEmergencyServiceCategoryBitmask = source.readInt(); + mEmergencyNumberSourceBitmask = source.readInt(); + } + + /** + * Get the dialing number of the emergency number. + * + * The character in the number string is only the dial pad + * character('0'-'9', '*', or '#'). For example: 911. + * + * @return the dialing number. + */ + public String getNumber() { + return mNumber; + } + + /** + * Get the country code string (lowercase character) in ISO 3166 format of the emergency number. + * + * @return the country code string (lowercase character) in ISO 3166 format. + */ + public String getCountryIso() { + return mCountryIso; + } + + /** + * Returns the bitmask of emergency service categories {@link EmergencyServiceCategories} of + * the emergency number. + * + * @return bitmask of the emergency service categories {@link EmergencyServiceCategories} + */ + public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() { + return mEmergencyServiceCategoryBitmask; + } + + /** + * Returns the emergency service categories {@link EmergencyServiceCategories} of the emergency + * number. + * + * @return a list of the emergency service categories {@link EmergencyServiceCategories} + */ + public List<Integer> getEmergencyServiceCategories() { + List<Integer> categories = new ArrayList<>(); + if (serviceUnspecified()) { + categories.add(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED); + return categories; + } + for (Integer category : EMERGENCY_SERVICE_CATEGORY_SET) { + if (isInEmergencyServiceCategories(category)) { + categories.add(category); + } + } + return categories; + } + + /** + * Checks if the emergency service category is unspecified for the emergency number + * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}. + * + * @return {@code true} if the emergency service category is unspecified for the emergency + * number {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise. + */ + private boolean serviceUnspecified() { + return mEmergencyServiceCategoryBitmask == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; + } + + /** + * Checks if the emergency number is in the specified emergency service category(s) + * {@link EmergencyServiceCategories}. + * + * @return {@code true} if the emergency number is in the specified emergency service + * category(s) {@link EmergencyServiceCategories}; {@code false} otherwise. + * + * @param categories - emergency service categories {@link EmergencyServiceCategories} + */ + public boolean isInEmergencyServiceCategories(@EmergencyServiceCategories int categories) { + if (categories == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED) { + return serviceUnspecified(); + } + return (mEmergencyServiceCategoryBitmask & categories) == categories; + } + + /** + * Returns the bitmask of the sources {@link EmergencyNumberSources} of the emergency number. + * + * @return bitmask of the emergency number sources {@link EmergencyNumberSources} + */ + public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() { + return mEmergencyNumberSourceBitmask; + } + + /** + * Returns a list of {@link EmergencyNumberSources} of the emergency number. + * + * @return a list of {@link EmergencyNumberSources} + */ + public List<Integer> getEmergencyNumberSources() { + List<Integer> sources = new ArrayList<>(); + for (Integer source : EMERGENCY_NUMBER_SOURCE_SET) { + if ((mEmergencyNumberSourceBitmask & source) == source) { + sources.add(source); + } + } + return sources; + } + + /** + * Checks if the emergency number is from the specified emergency number source(s) + * {@link EmergencyNumberSources}. + * + * @return {@code true} if the emergency number is from the specified emergency number + * source(s) {@link EmergencyNumberSources}; {@code false} otherwise. + * + * @param sources - {@link EmergencyNumberSources} + */ + public boolean isFromSources(@EmergencyNumberSources int sources) { + return (mEmergencyNumberSourceBitmask & sources) == sources; + } + + @Override + /** @hide */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mNumber); + dest.writeString(mCountryIso); + dest.writeInt(mEmergencyServiceCategoryBitmask); + dest.writeInt(mEmergencyNumberSourceBitmask); + } + + @Override + /** @hide */ + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "EmergencyNumber = " + "[Number]" + mNumber + " / [CountryIso]" + mCountryIso + + " / [ServiceCategories]" + + Integer.toBinaryString(mEmergencyServiceCategoryBitmask) + + " / [Sources]" + Integer.toBinaryString(mEmergencyNumberSourceBitmask); + } + + @Override + public boolean equals(Object o) { + if (!EmergencyNumber.class.isInstance(o)) { + return false; + } + return (o == this || toString().equals(o.toString())); + } + + public static final Parcelable.Creator<EmergencyNumber> CREATOR = + new Parcelable.Creator<EmergencyNumber>() { + @Override + public EmergencyNumber createFromParcel(Parcel in) { + return new EmergencyNumber(in); + } + + @Override + public EmergencyNumber[] newArray(int size) { + return new EmergencyNumber[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 5d6a8c158eed..89ef33914c12 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -117,12 +117,14 @@ public final class ImsCallProfile implements Parcelable { * @hide */ public static final String EXTRA_CONFERENCE = "conference"; + /** * Boolean extra property set on an {@link ImsCallProfile} to indicate that this call is an * emergency call. The {@link ImsService} sets this on a call to indicate that the network has * identified the call as an emergency call. */ - public static final String EXTRA_E_CALL = "e_call"; + public static final String EXTRA_EMERGENCY_CALL = "e_call"; + /** * @hide */ diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index a20d4f5ad27b..df903cc270a2 100644 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -16,22 +16,16 @@ package android.telephony.ims; -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.SystemApi; import android.os.Message; import android.os.RemoteException; import android.telephony.ims.aidl.IImsCallSessionListener; - -import java.util.Objects; -import java.util.concurrent.Executor; - -import android.telephony.ims.stub.ImsCallSessionImplBase; import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsVideoCallProvider; +import java.util.Objects; + /** * Provides the call initiation/termination, and media exchange between two IMS endpoints. * It directly communicates with IMS service which implements the IMS protocol behavior. @@ -42,7 +36,8 @@ public class ImsCallSession { private static final String TAG = "ImsCallSession"; /** - * Defines IMS call session state. Please use {@link ImsCallSessionImplBase.State} definition. + * Defines IMS call session state. Please use + * {@link android.telephony.ims.stub.ImsCallSessionImplBase.State} definition. * This is kept around for capability reasons. */ public static class State { @@ -1027,9 +1022,9 @@ public class ImsCallSession { } /** - * Sends RTT Upgrade request + * Sends RTT Upgrade or downgrade request * - * @param to : expected profile + * @param to Profile with the RTT flag set to the desired value */ public void sendRttModifyRequest(ImsCallProfile to) { if (mClosed) { diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 31381804d143..cecf2e26f139 100644 --- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -21,12 +21,11 @@ import android.annotation.SystemApi; import android.net.Uri; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.util.Log; -import android.telephony.ims.ImsReasonInfo; - import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; @@ -81,13 +80,14 @@ public class ImsRegistrationImplBase { * Callback class for receiving Registration callback events. * @hide */ - public static class Callback { + public static class Callback extends IImsRegistrationCallback.Stub { /** * Notifies the framework when the IMS Provider is connected to the IMS network. * * @param imsRadioTech the radio access technology. Valid values are defined in * {@link ImsRegistrationTech}. */ + @Override public void onRegistered(@ImsRegistrationTech int imsRadioTech) { } @@ -97,6 +97,7 @@ public class ImsRegistrationImplBase { * @param imsRadioTech the radio access technology. Valid values are defined in * {@link ImsRegistrationTech}. */ + @Override public void onRegistering(@ImsRegistrationTech int imsRadioTech) { } @@ -105,6 +106,7 @@ public class ImsRegistrationImplBase { * * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. */ + @Override public void onDeregistered(ImsReasonInfo info) { } @@ -115,6 +117,7 @@ public class ImsRegistrationImplBase { * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed * @param info A {@link ImsReasonInfo} that identifies the reason for failure. */ + @Override public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) { } @@ -125,6 +128,7 @@ public class ImsRegistrationImplBase { * @param uris new array of subscriber {@link Uri}s that are associated with this IMS * subscription. */ + @Override public void onSubscriberAssociatedUriChanged(Uri[] uris) { } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java index 6bf22a05beec..8015b07fa024 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java @@ -33,6 +33,7 @@ import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsConstants; import java.io.UnsupportedEncodingException; +import java.util.Locale; /** * Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is @@ -44,16 +45,34 @@ public class GsmSmsCbMessage { * Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5. */ private static final String[] LANGUAGE_CODES_GROUP_0 = { - "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu", - "pl", null + Locale.GERMAN.getLanguage(), // German + Locale.ENGLISH.getLanguage(), // English + Locale.ITALIAN.getLanguage(), // Italian + Locale.FRENCH.getLanguage(), // French + new Locale("es").getLanguage(), // Spanish + new Locale("nl").getLanguage(), // Dutch + new Locale("sv").getLanguage(), // Swedish + new Locale("da").getLanguage(), // Danish + new Locale("pt").getLanguage(), // Portuguese + new Locale("fi").getLanguage(), // Finnish + new Locale("nb").getLanguage(), // Norwegian + new Locale("el").getLanguage(), // Greek + new Locale("tr").getLanguage(), // Turkish + new Locale("hu").getLanguage(), // Hungarian + new Locale("pl").getLanguage(), // Polish + null }; /** * Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5. */ private static final String[] LANGUAGE_CODES_GROUP_2 = { - "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null, - null, null + new Locale("cs").getLanguage(), // Czech + new Locale("he").getLanguage(), // Hebrew + new Locale("ar").getLanguage(), // Arabic + new Locale("ru").getLanguage(), // Russian + new Locale("is").getLanguage(), // Icelandic + null, null, null, null, null, null, null, null, null, null, null }; private static final char CARRIAGE_RETURN = 0x0d; diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java index 0fabc2ff6b86..541ca8d1e5c0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java @@ -118,71 +118,103 @@ public class SmsCbConstants { public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE = 0x111E; // 4382 - /** CMAS Message Identifier for Presidential Level alerts for additional languages - * for additional languages. */ + /** + * CMAS Message Identifier for Presidential Level alerts for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE = 0x111F; // 4383 - /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed - * for additional languages. */ + /** + * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE = 0x1120; // 4384 - /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely - * for additional languages. */ + /** + * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE = 0x1121; // 4385 - /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed - * for additional languages. */ + /** + * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE = 0x1122; // 4386 - /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely - * for additional languages. */ + /** + * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE = 0x1123; // 4387 - /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed - * for additional languages. */ + /** + * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE = 0x1124; // 4388 - /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely - * for additional languages.*/ + /** + * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE = 0x1125; // 4389 - /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed - * for additional languages. */ + /** + * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE = 0x1126; // 4390 - /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely - * for additional languages.*/ + /** + * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE = 0x1127; // 4391 - /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert) - * for additional languages. */ + /** + * CMAS Message Identifier for Child Abduction Emergency (Amber Alert) + * for additional languages. + */ public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE = 0x1128; // 4392 - /** CMAS Message Identifier for the Required Monthly Test - * for additional languages. */ + /** CMAS Message Identifier for the Required Monthly Test for additional languages. */ public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE = 0x1129; // 4393 - /** CMAS Message Identifier for CMAS Exercise - * for additional languages. */ + /** CMAS Message Identifier for CMAS Exercise for additional languages. */ public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE = 0x112A; // 4394 - /** CMAS Message Identifier for operator defined use - * for additional languages. */ + /** CMAS Message Identifier for operator defined use for additional languages. */ public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE = 0x112B; // 4395 + /** CMAS Message Identifier for CMAS Public Safety Alerts. */ + public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY + = 0x112C; // 4396 + + /** CMAS Message Identifier for CMAS Public Safety Alerts for additional languages. */ + public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY_LANGUAGE + = 0x112D; // 4397 + + /** CMAS Message Identifier for CMAS State/Local Test. */ + public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST + = 0x112E; // 4398 + + /** CMAS Message Identifier for CMAS State/Local Test for additional languages. */ + public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST_LANGUAGE + = 0x112F; // 4399 + /** End of CMAS Message Identifier range (including future extensions). */ public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER = 0x112F; // 4399 diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk index fe65eccedd24..c225e170c377 100644 --- a/tests/NetworkSecurityConfigTest/Android.mk +++ b/tests/NetworkSecurityConfigTest/Android.mk @@ -7,7 +7,6 @@ LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := \ android.test.runner \ - bouncycastle \ conscrypt \ android.test.base \ diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/tests/net/java/android/net/dhcp/DhcpPacketTest.java index 312b3d1878d6..a592809618e6 100644 --- a/tests/net/java/android/net/dhcp/DhcpPacketTest.java +++ b/tests/net/java/android/net/dhcp/DhcpPacketTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; import android.net.NetworkUtils; @@ -37,6 +38,7 @@ import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; import java.net.Inet4Address; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -56,6 +58,8 @@ public class DhcpPacketTest { private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH); private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress( SERVER_ADDR, PREFIX_LENGTH); + private static final String HOSTNAME = "testhostname"; + private static final short MTU = 1500; // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code // doesn't use == instead of equals when comparing addresses. private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0"); @@ -960,7 +964,8 @@ public class DhcpPacketTest { assertTrue(msg, Arrays.equals(expected, actual)); } - public void checkBuildOfferPacket(int leaseTimeSecs) throws Exception { + public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname) + throws Exception { final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2); final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000); final int transactionId = 0xdeadbeef; @@ -971,7 +976,8 @@ public class DhcpPacketTest { CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */, BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */, Collections.singletonList(SERVER_ADDR) /* dnsServers */, - SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, false /* metered */); + SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname, + false /* metered */, MTU); ByteArrayOutputStream bos = new ByteArrayOutputStream(); // BOOTP headers @@ -1027,12 +1033,22 @@ public class DhcpPacketTest { // Nameserver bos.write(new byte[] { (byte) 0x06, (byte) 0x04 }); bos.write(SERVER_ADDR.getAddress()); + // Hostname + if (hostname != null) { + bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()}); + bos.write(hostname.getBytes(Charset.forName("US-ASCII"))); + } + // MTU + bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 }); + bos.write(shortToByteArray(MTU)); // End options. bos.write(0xff); - final byte[] expected = bos.toByteArray(); - assertTrue((expected.length & 1) == 0); + if ((bos.size() & 1) != 0) { + bos.write(0x00); + } + final byte[] expected = bos.toByteArray(); final byte[] actual = new byte[packet.limit()]; packet.get(actual); final String msg = "Expected:\n " + HexDump.dumpHexString(expected) + @@ -1042,13 +1058,18 @@ public class DhcpPacketTest { @Test public void testOfferPacket() throws Exception { - checkBuildOfferPacket(3600); - checkBuildOfferPacket(Integer.MAX_VALUE); - checkBuildOfferPacket(0x80000000); - checkBuildOfferPacket(INFINITE_LEASE); + checkBuildOfferPacket(3600, HOSTNAME); + checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME); + checkBuildOfferPacket(0x80000000, HOSTNAME); + checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME); + checkBuildOfferPacket(3600, null); } private static byte[] intToByteArray(int val) { return ByteBuffer.allocate(4).putInt(val).array(); } + + private static byte[] shortToByteArray(short val) { + return ByteBuffer.allocate(2).putShort(val).array(); + } } diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java index 45a50d9a8b5f..df34c7310b63 100644 --- a/tests/net/java/android/net/dhcp/DhcpServerTest.java +++ b/tests/net/java/android/net/dhcp/DhcpServerTest.java @@ -17,6 +17,7 @@ package android.net.dhcp; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INADDR_ANY; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; @@ -87,6 +88,7 @@ public class DhcpServerTest { Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); private static final long TEST_LEASE_TIME_SECS = 3600L; private static final int TEST_MTU = 1500; + private static final String TEST_HOSTNAME = "testhostname"; private static final int TEST_TRANSACTION_ID = 123; private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 }; @@ -96,7 +98,10 @@ public class DhcpServerTest { private static final long TEST_CLOCK_TIME = 1234L; private static final int TEST_LEASE_EXPTIME_SECS = 3600; private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC, - TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS*1000L + TEST_CLOCK_TIME, null /* hostname */); + TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, + null /* hostname */); + private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC, + TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME); @NonNull @Mock private Dependencies mDeps; @@ -217,15 +222,17 @@ public class DhcpServerTest { public void testRequest_Selecting_Ack() throws Exception { when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */, - eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */)) - .thenReturn(TEST_LEASE); + eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME))) + .thenReturn(TEST_LEASE_WITH_HOSTNAME); final DhcpRequestPacket request = makeRequestSelectingPacket(); + request.mHostName = TEST_HOSTNAME; + request.mRequestedParams = new byte[] { DHCP_HOST_NAME }; mServer.processPacket(request, DHCP_CLIENT); assertResponseSentTo(TEST_CLIENT_ADDR); final DhcpAckPacket packet = assertAck(getPacket()); - assertMatchesTestLease(packet); + assertMatchesTestLease(packet, TEST_HOSTNAME); } @Test @@ -270,14 +277,18 @@ public class DhcpServerTest { * - other request states (init-reboot/renewing/rebinding) */ - private void assertMatchesTestLease(@NonNull DhcpPacket packet) { + private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) { assertMatchesClient(packet); assertFalse(packet.hasExplicitClientId()); assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier); assertEquals(TEST_CLIENT_ADDR, packet.mYourIp); assertNotNull(packet.mLeaseTime); assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime); - assertNull(packet.mHostName); + assertEquals(hostname, packet.mHostName); + } + + private void assertMatchesTestLease(@NonNull DhcpPacket packet) { + assertMatchesTestLease(packet, null); } private void assertMatchesClient(@NonNull DhcpPacket packet) { diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 99a5a69213fa..9b919abfa41d 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -34,8 +36,10 @@ import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; import android.net.IpSecSpiResponse; +import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecTunnelInterfaceResponse; +import android.net.IpSecUdpEncapResponse; import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; @@ -62,16 +66,17 @@ public class IpSecServiceParameterizedTest { private static final int TEST_SPI = 0xD1201D; - private final String mDestinationAddr; private final String mSourceAddr; + private final String mDestinationAddr; private final LinkAddress mLocalInnerAddress; + private final int mFamily; @Parameterized.Parameters public static Collection ipSecConfigs() { return Arrays.asList( new Object[][] { - {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"}, - {"2601::2", "2601::10", "2001:db8::1/64"} + {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET}, + {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6} }); } @@ -129,12 +134,14 @@ public class IpSecServiceParameterizedTest { new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); private static final IpSecAlgorithm AEAD_ALGO = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); + private static final int REMOTE_ENCAP_PORT = 4500; public IpSecServiceParameterizedTest( - String sourceAddr, String destAddr, String localInnerAddr) { + String sourceAddr, String destAddr, String localInnerAddr, int family) { mSourceAddr = sourceAddr; mDestinationAddr = destAddr; mLocalInnerAddress = new LinkAddress(localInnerAddr); + mFamily = family; } @Before @@ -157,6 +164,8 @@ public class IpSecServiceParameterizedTest { .thenReturn(AppOpsManager.MODE_IGNORED); } + //TODO: Add a test to verify SPI. + @Test public void testIpSecServiceReserveSpi() throws Exception { when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI))) @@ -257,6 +266,47 @@ public class IpSecServiceParameterizedTest { config.setAuthentication(AUTH_ALGO); } + private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception { + config.setEncapType(IpSecTransform.ENCAP_ESPINUDP); + config.setEncapSocketResourceId(resourceId); + config.setEncapRemotePort(REMOTE_ENCAP_PORT); + } + + private void verifyTransformNetdCalledForCreatingSA( + IpSecConfig config, IpSecTransformResponse resp) throws Exception { + verifyTransformNetdCalledForCreatingSA(config, resp, 0); + } + + private void verifyTransformNetdCalledForCreatingSA( + IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception { + IpSecAlgorithm auth = config.getAuthentication(); + IpSecAlgorithm crypt = config.getEncryption(); + IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption(); + + verify(mMockNetd, times(1)) + .ipSecAddSecurityAssociation( + eq(mUid), + eq(config.getMode()), + eq(config.getSourceAddress()), + eq(config.getDestinationAddress()), + eq((config.getNetwork() != null) ? config.getNetwork().netId : 0), + eq(TEST_SPI), + eq(0), + eq(0), + eq((auth != null) ? auth.getName() : ""), + eq((auth != null) ? auth.getKey() : new byte[] {}), + eq((auth != null) ? auth.getTruncationLengthBits() : 0), + eq((crypt != null) ? crypt.getName() : ""), + eq((crypt != null) ? crypt.getKey() : new byte[] {}), + eq((crypt != null) ? crypt.getTruncationLengthBits() : 0), + eq((authCrypt != null) ? authCrypt.getName() : ""), + eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}), + eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0), + eq(config.getEncapType()), + eq(encapSocketPort), + eq(config.getEncapRemotePort())); + } + @Test public void testCreateTransform() throws Exception { IpSecConfig ipSecConfig = new IpSecConfig(); @@ -267,28 +317,7 @@ public class IpSecServiceParameterizedTest { mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); assertEquals(IpSecManager.Status.OK, createTransformResp.status); - verify(mMockNetd) - .ipSecAddSecurityAssociation( - eq(mUid), - anyInt(), - anyString(), - anyString(), - anyInt(), - eq(TEST_SPI), - anyInt(), - anyInt(), - eq(IpSecAlgorithm.AUTH_HMAC_SHA256), - eq(AUTH_KEY), - anyInt(), - eq(IpSecAlgorithm.CRYPT_AES_CBC), - eq(CRYPT_KEY), - anyInt(), - eq(""), - eq(new byte[] {}), - eq(0), - anyInt(), - anyInt(), - anyInt()); + verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp); } @Test @@ -302,28 +331,59 @@ public class IpSecServiceParameterizedTest { mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); assertEquals(IpSecManager.Status.OK, createTransformResp.status); - verify(mMockNetd) - .ipSecAddSecurityAssociation( - eq(mUid), - anyInt(), - anyString(), - anyString(), - anyInt(), - eq(TEST_SPI), - anyInt(), - anyInt(), - eq(""), - eq(new byte[] {}), - eq(0), - eq(""), - eq(new byte[] {}), - eq(0), - eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM), - eq(AEAD_KEY), - anyInt(), - anyInt(), - anyInt(), - anyInt()); + verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp); + } + + @Test + public void testCreateTransportModeTransformWithEncap() throws Exception { + IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder()); + + IpSecConfig ipSecConfig = new IpSecConfig(); + ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); + addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig); + + if (mFamily == AF_INET) { + IpSecTransformResponse createTransformResp = + mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); + assertEquals(IpSecManager.Status.OK, createTransformResp.status); + + verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port); + } else { + try { + IpSecTransformResponse createTransformResp = + mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); + fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6"); + } catch (IllegalArgumentException expected) { + } + } + } + + @Test + public void testCreateTunnelModeTransformWithEncap() throws Exception { + IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder()); + + IpSecConfig ipSecConfig = new IpSecConfig(); + ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); + addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig); + + if (mFamily == AF_INET) { + IpSecTransformResponse createTransformResp = + mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); + assertEquals(IpSecManager.Status.OK, createTransformResp.status); + + verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port); + } else { + try { + IpSecTransformResponse createTransformResp = + mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); + fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6"); + } catch (IllegalArgumentException expected) { + } + } } @Test |