diff options
121 files changed, 3424 insertions, 2014 deletions
diff --git a/Android.bp b/Android.bp index 2af7ca4186c0..3c47d1bb3cbb 100644 --- a/Android.bp +++ b/Android.bp @@ -366,7 +366,9 @@ java_defaults { sdk_version: "core_platform", libs: [ + "app-compat-annotations", "ext", + "unsupportedappusage", "updatable_media_stubs", ], @@ -426,7 +428,6 @@ java_library { name: "framework-minus-apex", defaults: ["framework-defaults"], srcs: [":framework-non-updatable-sources"], - libs: ["app-compat-annotations"], installable: true, javac_shard_size: 150, required: [ @@ -468,14 +469,16 @@ java_library { defaults: ["framework-defaults"], srcs: [":framework-all-sources"], installable: false, - libs: ["app-compat-annotations"], } java_library { name: "framework-annotation-proc", defaults: ["framework-defaults"], srcs: [":framework-all-sources"], - libs: ["app-compat-annotations"], + libs: [ + "app-compat-annotations", + "unsupportedappusage", + ], installable: false, plugins: [ "unsupportedappusage-annotation-processor", @@ -1623,15 +1626,14 @@ filegroup { "core/java/android/os/RegistrantList.java", "core/java/android/os/Registrant.java", "core/java/android/util/LocalLog.java", - "core/java/android/util/Slog.java", "core/java/android/util/TimeUtils.java", "core/java/com/android/internal/os/SomeArgs.java", + "core/java/com/android/internal/util/FastXmlSerializer.java", + "core/java/com/android/internal/util/HexDump.java", + "core/java/com/android/internal/util/IndentingPrintWriter.java", "core/java/com/android/internal/util/Preconditions.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", - "core/java/com/android/internal/util/XmlUtils.java", - "core/java/com/android/internal/util/HexDump.java", - "core/java/com/android/internal/util/IndentingPrintWriter.java", - "core/java/com/android/internal/util/DumpUtils.java" + "core/java/com/android/internal/util/UserIcons.java", ], } diff --git a/api/current.txt b/api/current.txt index 23b5bc6224f1..21ea6e6d3793 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28903,6 +28903,7 @@ package android.net { public class NetworkRequest implements android.os.Parcelable { method public int describeContents(); + method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); method public boolean hasCapability(int); method public boolean hasTransport(int); method public void writeToParcel(android.os.Parcel, int); @@ -44198,6 +44199,7 @@ package android.telephony { field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array"; field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool"; field public static final String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool"; @@ -45499,6 +45501,7 @@ package android.telephony.data { field public static final int TYPE_MCX = 1024; // 0x400 field public static final int TYPE_MMS = 2; // 0x2 field public static final int TYPE_SUPL = 4; // 0x4 + field public static final int TYPE_XCAP = 2048; // 0x800 } public static class ApnSetting.Builder { @@ -46808,7 +46811,7 @@ package android.text.format { field public static final long WEEK_IN_MILLIS = 604800000L; // 0x240c8400L field public static final String YEAR_FORMAT = "%Y"; field public static final String YEAR_FORMAT_TWO_DIGITS = "%g"; - field public static final long YEAR_IN_MILLIS = 31449600000L; // 0x7528ad000L + field @Deprecated public static final long YEAR_IN_MILLIS = 31449600000L; // 0x7528ad000L field @Deprecated public static final int[] sameMonthTable; field @Deprecated public static final int[] sameYearTable; } @@ -48245,6 +48248,13 @@ package android.util { ctor public Base64OutputStream(java.io.OutputStream, int); } + public final class CloseGuard { + ctor public CloseGuard(); + method public void close(); + method public void open(@NonNull String); + method public void warnIfOpen(); + } + @Deprecated public final class Config { field @Deprecated public static final boolean DEBUG = false; field @Deprecated public static final boolean LOGD = true; diff --git a/api/system-current.txt b/api/system-current.txt index ebfd55edf8fe..52e5255609c9 100644..100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -75,6 +75,7 @@ package android { field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO"; field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"; field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS"; + field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"; field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES"; field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST"; field public static final String HDMI_CEC = "android.permission.HDMI_CEC"; @@ -1343,15 +1344,24 @@ package android.bluetooth { public final class BluetoothDevice implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess(); + method public boolean cancelPairing(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBatteryLevel(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getMessageAccessPermission(); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getPhonebookAccessPermission(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isBondingInitiatedLocally(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPin(@Nullable String); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int); field public static final int ACCESS_ALLOWED = 1; // 0x1 field public static final int ACCESS_REJECTED = 2; // 0x2 field public static final int ACCESS_UNKNOWN = 0; // 0x0 @@ -1386,7 +1396,9 @@ package android.bluetooth { } public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile { + method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getActiveDevices(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public long getHiSyncId(@Nullable android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); } @@ -4072,6 +4084,7 @@ package android.media.tv { method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo); method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo); method @Nullable public String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo); + method public void onHdmiDeviceUpdated(@NonNull android.hardware.hdmi.HdmiDeviceInfo); } public abstract static class TvInputService.RecordingSession { @@ -7912,6 +7925,10 @@ package android.telephony { field public final double lng; } + public class CellBroadcastIntents { + method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); + } + public abstract class CellBroadcastService extends android.app.Service { ctor public CellBroadcastService(); method @CallSuper @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent); @@ -8933,6 +8950,7 @@ package android.telephony { method public void updateServiceLocation(); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String); field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; + field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE"; field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp index 1173d57e5e3f..3a260639de0f 100644 --- a/cmds/uiautomator/library/Android.bp +++ b/cmds/uiautomator/library/Android.bp @@ -22,6 +22,7 @@ droiddoc { "android.test.runner", "junit", "android.test.base", + "unsupportedappusage", ], custom_template: "droiddoc-templates-sdk", installable: false, diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java new file mode 100644 index 000000000000..c8e5a4a97ae7 --- /dev/null +++ b/core/java/android/annotation/Hide.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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.annotation; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that an API is hidden by default, in a similar fashion to the + * <pre>@hide</pre> javadoc tag. + * + * <p>Note that, in order for this to work, metalava has to be invoked with + * the flag {@code --hide-annotation android.annotation.Hide}. + * @hide + */ +@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) +@Retention(RetentionPolicy.CLASS) +public @interface Hide { +} diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl index d8cea2860aa8..6d790b381ace 100644 --- a/core/java/android/app/role/IRoleManager.aidl +++ b/core/java/android/app/role/IRoleManager.aidl @@ -19,7 +19,6 @@ package android.app.role; import android.app.role.IOnRoleHoldersChangedListener; import android.os.Bundle; import android.os.RemoteCallback; -import android.telephony.IFinancialSmsCallback; /** * @hide @@ -55,9 +54,4 @@ interface IRoleManager { List<String> getHeldRolesFromController(in String packageName); String getDefaultSmsPackage(int userId); - - /** - * Get filtered SMS messages for financial app. - */ - void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback); } diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java index 471606da4d75..55f92be14cd0 100644 --- a/core/java/android/app/timedetector/ManualTimeSuggestion.java +++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java @@ -56,6 +56,7 @@ public final class ManualTimeSuggestion implements Parcelable { public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { mUtcTime = Objects.requireNonNull(utcTime); + Objects.requireNonNull(utcTime.getValue()); } private static ManualTimeSuggestion createFromParcel(Parcel in) { diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java index dd02af7a3ac7..4a89a1245473 100644 --- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java +++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java @@ -166,7 +166,12 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the builder for call chaining. */ - public Builder setUtcTime(TimestampedValue<Long> utcTime) { + public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { + if (utcTime != null) { + // utcTime can be null, but the value it holds cannot. + Objects.requireNonNull(utcTime.getValue()); + } + mUtcTime = utcTime; return this; } diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 49187dcde342..323c7d172033 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -33,8 +34,12 @@ import android.os.Process; import android.os.RemoteException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.UUID; /** @@ -771,6 +776,13 @@ public final class BluetoothDevice implements Parcelable { @UnsupportedAppUsage public static final String EXTRA_SDP_SEARCH_STATUS = "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; + + /** @hide */ + @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN, + ACCESS_ALLOWED, ACCESS_REJECTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface AccessPermission{} + /** * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. @@ -1096,15 +1108,14 @@ public final class BluetoothDevice implements Parcelable { /** * Get the most recent identified battery level of this Bluetooth device - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * * @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if * Bluetooth is disabled, or device is disconnected, or does not have any battery reporting * service, or return value is invalid * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - @UnsupportedAppUsage public int getBatteryLevel() { final IBluetooth service = sService; if (service == null) { @@ -1187,8 +1198,15 @@ public final class BluetoothDevice implements Parcelable { return false; } - /** @hide */ - @UnsupportedAppUsage + /** + * Gets whether bonding was initiated locally + * + * @return true if bonding is initiated locally, false otherwise + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isBondingInitiatedLocally() { final IBluetooth service = sService; if (service == null) { @@ -1480,15 +1498,20 @@ public final class BluetoothDevice implements Parcelable { return false; } - /** @hide */ - @UnsupportedAppUsage - public boolean setPasskey(int passkey) { - //TODO(BT) - /* - try { - return sService.setPasskey(this, true, 4, passkey); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ - return false; + /** + * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} + * + * @return true pin has been set false for error + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setPin(@Nullable String pin) { + byte[] pinBytes = convertPinToBytes(pin); + if (pinBytes == null) { + return false; + } + return setPin(pinBytes); } /** @@ -1511,22 +1534,18 @@ public final class BluetoothDevice implements Parcelable { return false; } - /** @hide */ - public boolean setRemoteOutOfBandData() { - // TODO(BT) - /* - try { - return sService.setRemoteOutOfBandData(this); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ - return false; - } - - /** @hide */ - @UnsupportedAppUsage - public boolean cancelPairingUserInput() { + /** + * Cancels pairing to this device + * + * @return true if pairing cancelled successfully, false otherwise + * + * @hide + */ + @SystemApi + public boolean cancelPairing() { final IBluetooth service = sService; if (service == null) { - Log.e(TAG, "BT not enabled. Cannot create pairing user input"); + Log.e(TAG, "BT not enabled. Cannot cancel pairing"); return false; } try { @@ -1537,17 +1556,6 @@ public final class BluetoothDevice implements Parcelable { return false; } - /** @hide */ - @UnsupportedAppUsage - public boolean isBluetoothDock() { - // TODO(BT) - /* - try { - return sService.isBluetoothDock(this); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ - return false; - } - boolean isBluetoothEnabled() { boolean ret = false; BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); @@ -1558,13 +1566,14 @@ public final class BluetoothDevice implements Parcelable { } /** - * Requires {@link android.Manifest.permission#BLUETOOTH}. + * Gets whether the phonebook access is allowed for this bluetooth device * * @return Whether the phonebook access is allowed to this device. Can be {@link * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) public int getPhonebookAccessPermission() { final IBluetooth service = sService; if (service == null) { @@ -1667,14 +1676,14 @@ public final class BluetoothDevice implements Parcelable { } /** - * Requires {@link android.Manifest.permission#BLUETOOTH}. + * Gets whether message access is allowed to this bluetooth device * - * @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, - * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. + * @return Whether the message access is allowed to this device. * @hide */ - @UnsupportedAppUsage - public int getMessageAccessPermission() { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) + public @AccessPermission int getMessageAccessPermission() { final IBluetooth service = sService; if (service == null) { return ACCESS_UNKNOWN; @@ -1689,15 +1698,18 @@ public final class BluetoothDevice implements Parcelable { /** * Sets whether the message access is allowed to this device. - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. * - * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link - * #ACCESS_REJECTED}. + * @param value is the value we are setting the message access permission to * @return Whether the value has been successfully set. * @hide */ - @UnsupportedAppUsage - public boolean setMessageAccessPermission(int value) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setMessageAccessPermission(@AccessPermission int value) { + // Validates param value is one of the accepted constants + if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { + throw new IllegalArgumentException(value + "is not a valid AccessPermission value"); + } final IBluetooth service = sService; if (service == null) { return false; @@ -1711,13 +1723,14 @@ public final class BluetoothDevice implements Parcelable { } /** - * Requires {@link android.Manifest.permission#BLUETOOTH}. + * Gets whether sim access is allowed for this bluetooth device * - * @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, - * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. + * @return Whether the Sim access is allowed to this device. * @hide */ - public int getSimAccessPermission() { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) + public @AccessPermission int getSimAccessPermission() { final IBluetooth service = sService; if (service == null) { return ACCESS_UNKNOWN; @@ -1732,14 +1745,14 @@ public final class BluetoothDevice implements Parcelable { /** * Sets whether the Sim access is allowed to this device. - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. * * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link * #ACCESS_REJECTED}. * @return Whether the value has been successfully set. * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int value) { final IBluetooth service = sService; if (service == null) { @@ -1970,7 +1983,7 @@ public final class BluetoothDevice implements Parcelable { * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. * @hide */ - @UnsupportedAppUsage + @VisibleForTesting public static byte[] convertPinToBytes(String pin) { if (pin == null) { return null; diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java index ead8429e4a75..b4521c623ec2 100644 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -335,9 +335,9 @@ public final class BluetoothHearingAid implements BluetoothProfile { * is not active, it will be null on that position. Returns empty list on error. * @hide */ - @UnsupportedAppUsage + @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public List<BluetoothDevice> getActiveDevices() { + public @NonNull List<BluetoothDevice> getActiveDevices() { if (VDBG) log("getActiveDevices()"); final IBluetoothHearingAid service = getService(); try { @@ -559,8 +559,9 @@ public final class BluetoothHearingAid implements BluetoothProfile { * @return the CustomerId of the device * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public long getHiSyncId(BluetoothDevice device) { + public long getHiSyncId(@Nullable BluetoothDevice device) { if (VDBG) { log("getCustomerId(" + device + ")"); } diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl index c02cc6a5472e..5031fbaca9e6 100644 --- a/core/java/android/content/pm/ParceledListSlice.aidl +++ b/core/java/android/content/pm/ParceledListSlice.aidl @@ -16,4 +16,4 @@ package android.content.pm; -parcelable ParceledListSlice; +parcelable ParceledListSlice<T>; diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 4270740cc722..471b23e04775 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; @@ -461,6 +462,14 @@ public class NetworkRequest implements Parcelable { return networkCapabilities.hasTransport(transportType); } + /** + * @see Builder#setNetworkSpecifier(NetworkSpecifier) + */ + @Nullable + public NetworkSpecifier getNetworkSpecifier() { + return networkCapabilities.getNetworkSpecifier(); + } + public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 450bfaef50d4..1130f1db6256 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -519,11 +519,12 @@ public class Process { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. - * + * @param disabledCompatChanges null-ok list of disabled compat changes for the process being + * started. * @param zygoteArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure - * + * * {@hide} */ public static ProcessStartResult start(@NonNull final String processClass, @@ -538,11 +539,12 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + @Nullable long[] disabledCompatChanges, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ true, zygoteArgs); + /*useUsapPool=*/ true, disabledCompatChanges, zygoteArgs); } /** @hide */ @@ -558,11 +560,12 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + @Nullable long[] disabledCompatChanges, @Nullable String[] zygoteArgs) { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ false, zygoteArgs); + /*useUsapPool=*/ false, disabledCompatChanges, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 3a55aff14659..c2d3eccfa3b1 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -306,6 +306,8 @@ public class ZygoteProcess { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param disabledCompatChanges null-ok list of disabled compat changes for the process being + * started. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. @@ -323,6 +325,7 @@ public class ZygoteProcess { @Nullable String invokeWith, @Nullable String packageName, boolean useUsapPool, + @Nullable long[] disabledCompatChanges, @Nullable String[] zygoteArgs) { // TODO (chriswailes): Is there a better place to check this value? if (fetchUsapPoolEnabledPropWithMinInterval()) { @@ -333,7 +336,7 @@ public class ZygoteProcess { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, - packageName, useUsapPool, zygoteArgs); + packageName, useUsapPool, disabledCompatChanges, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -534,6 +537,7 @@ public class ZygoteProcess { * @param startChildZygote Start a sub-zygote. This creates a new zygote process * that has its state cloned from this zygote process. * @param packageName null-ok the name of the package this process belongs to. + * @param disabledCompatChanges a list of disabled compat changes for the process being started. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason @@ -552,6 +556,7 @@ public class ZygoteProcess { boolean startChildZygote, @Nullable String packageName, boolean useUsapPool, + @Nullable long[] disabledCompatChanges, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<>(); @@ -623,6 +628,21 @@ public class ZygoteProcess { argsForZygote.add("--package-name=" + packageName); } + if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { + final StringBuilder sb = new StringBuilder(); + sb.append("--disabled-compat-changes="); + + final int sz = disabledCompatChanges.length; + for (int i = 0; i < sz; i++) { + if (i != 0) { + sb.append(','); + } + sb.append(disabledCompatChanges[i]); + } + + argsForZygote.add(sb.toString()); + } + argsForZygote.add(processClass); if (extraArgs != null) { @@ -1170,7 +1190,8 @@ public class ZygoteProcess { gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, abi, instructionSet, null /* appDataDir */, null /* invokeWith */, true /* startChildZygote */, null /* packageName */, - false /* useUsapPool */, extraArgs); + false /* useUsapPool */, + null /* disabledCompatChanges */, extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index ebdde0a54a86..066ba6e8678e 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -25,7 +25,6 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; -import android.app.job.JobService; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; @@ -4119,20 +4118,6 @@ public final class Telephony { public static final String CID = "cid"; /** - * Message code. <em>OBSOLETE: merged into SERIAL_NUMBER.</em> - * <P>Type: INTEGER</P> - * @hide - */ - public static final String V1_MESSAGE_CODE = "message_code"; - - /** - * Message identifier. <em>OBSOLETE: renamed to SERVICE_CATEGORY.</em> - * <P>Type: INTEGER</P> - * @hide - */ - public static final String V1_MESSAGE_IDENTIFIER = "message_id"; - - /** * Service category which represents the general topic of the message. * <p> * For GSM/UMTS: message identifier (see 3GPP TS 23.041 section 9.4.1.2.2) @@ -4380,9 +4365,11 @@ public final class Telephony { * ServiceState provider. * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the - * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * {@link ServiceState} while your app is running. + * You can also use a {@link android.app.job.JobService} to * ensure your app is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * Note, however, that using a {@link android.app.job.JobService} + * does not guarantee timely delivery of * updates to the {@link Uri}. * * @param subscriptionId the subscriptionId to receive updates on @@ -4399,9 +4386,11 @@ public final class Telephony { * ServiceState provider. * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the - * {@link ServiceState} while your app is running. You can also use a {@link JobService} to + * {@link ServiceState} while your app is running. You can also use a + * {@link android.app.job.JobService} to * ensure your app is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * Note, however, that using a {@link android.app.job.JobService} + * does not guarantee timely delivery of * updates to the {@link Uri}. * * @param subscriptionId the subscriptionId to receive updates on @@ -4479,7 +4468,7 @@ public final class Telephony { /** * The current registered voice network operator name in long alphanumeric format. * <p> - * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}. + * This is the same as {@link ServiceState#getOperatorAlphaLong()}. * @hide */ public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long"; @@ -4490,12 +4479,11 @@ public final class Telephony { * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice * network operator name in long alphanumeric format. * <p> - * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}. + * This is the same as {@link ServiceState#getOperatorAlphaShort()}. * @hide */ public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short"; - /** * The current registered operator numeric id. * <p> @@ -4509,7 +4497,7 @@ public final class Telephony { /** * The current registered data network operator name in long alphanumeric format. * <p> - * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}. + * This is the same as {@link ServiceState#getOperatorAlphaLong()}. * @hide */ public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long"; @@ -4517,7 +4505,7 @@ public final class Telephony { /** * The current registered data network operator name in short alphanumeric format. * <p> - * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}. + * This is the same as {@link ServiceState#getOperatorAlphaShort()}. * @hide */ public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short"; @@ -4525,7 +4513,7 @@ public final class Telephony { /** * The current registered data network operator numeric id. * <p> - * This is the same as {@link ServiceState#getDataOperatorNumeric()}. + * This is the same as {@link ServiceState#getOperatorNumeric()}. * @hide */ public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric"; @@ -4656,10 +4644,11 @@ public final class Telephony { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * carrier identity {@link TelephonyManager#getSimCarrierId()} - * while your app is running. You can also use a {@link JobService} to ensure your app + * while your app is running. You can also use a {@link android.app.job.JobService} + * to ensure your app * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee + * timely delivery of updates to the {@link Uri}. * * @param subscriptionId the subscriptionId to receive updates on * @return the Uri used to observe carrier identity changes @@ -4677,10 +4666,11 @@ public final class Telephony { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * specific carrier identity {@link TelephonyManager#getSimSpecificCarrierId()} - * while your app is running. You can also use a {@link JobService} to ensure your app + * while your app is running. You can also use a {@link android.app.job.JobService} + * to ensure your app * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * * @param subscriptionId the subscriptionId to receive updates on * @return the Uri used to observe specific carrier identity changes diff --git a/core/java/android/service/carrier/ApnService.java b/core/java/android/service/carrier/ApnService.java index 57e4b1b40748..0c12fd409078 100644 --- a/core/java/android/service/carrier/ApnService.java +++ b/core/java/android/service/carrier/ApnService.java @@ -26,7 +26,7 @@ import android.content.Intent; import android.os.IBinder; import android.util.Log; -import com.android.internal.telephony.IApnSourceService; +import android.service.carrier.IApnSourceService; import java.util.List; diff --git a/telephony/java/com/android/internal/telephony/IApnSourceService.aidl b/core/java/android/service/carrier/IApnSourceService.aidl index 34c9067c3f2f..fadd2ff1a772 100644 --- a/telephony/java/com/android/internal/telephony/IApnSourceService.aidl +++ b/core/java/android/service/carrier/IApnSourceService.aidl @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.internal.telephony; +package android.service.carrier; import android.content.ContentValues; +/** @hide */ interface IApnSourceService { /** Retreive APNs. */ ContentValues[] getApns(int subId); diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java new file mode 100644 index 000000000000..8446253c6302 --- /dev/null +++ b/core/java/android/telephony/CellBroadcastIntents.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.UserHandle; + +/** + * A static helper class used to send Intents with prepopulated flags. + * <p> + * This is intended to be used by the CellBroadcastService and will throw a security exception if + * used from a UID besides the network stack UID. + * + * @hide + */ +@SystemApi +public class CellBroadcastIntents { + private static final String LOG_TAG = "CellBroadcastIntents"; + + /** + * @hide + */ + private CellBroadcastIntents() { + } + + /** + * Returns an intent which can be received by background BroadcastReceivers. This is only + * intended to be used by the CellBroadcastService and will throw a security exception if called + * from another UID. + * + * @param context The context from which to send the broadcast + * @param user The user from which to send the broadcast + * @param intent The Intent to broadcast; all receivers matching this Intent will + * receive the broadcast. + * @param receiverPermission String naming a permissions that a receiver must hold in order to + * receive your broadcast. If null, no permission is required. + * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is + * required. If both receiverAppOp and receiverPermission are + * non-null, a receiver must have both of them to receive the + * broadcast + * @param resultReceiver Your own BroadcastReceiver to treat as the final receiver of the + * broadcast. + * @param scheduler A custom Handler with which to schedule the resultReceiver + * callback; if null it will be scheduled in the Context's main + * thread. + * @param initialCode An initial value for the result code. Often Activity.RESULT_OK. + * @param initialData An initial value for the result data. Often null. + * @param initialExtras An initial value for the result extras. Often null. + */ + public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull Context context, + @Nullable UserHandle user, @NonNull Intent intent, @Nullable String receiverPermission, + @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver, + @Nullable Handler scheduler, int initialCode, @Nullable String initialData, + @Nullable Bundle initialExtras) { + int status = context.checkCallingOrSelfPermission( + "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"); + if (status == PackageManager.PERMISSION_DENIED) { + throw new SecurityException( + "Caller does not have permission to send broadcast for background receivers"); + } + Intent backgroundIntent = new Intent(intent); + backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + if (user != null) { + context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent, + receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode, + initialData, initialExtras); + } else { + context.sendOrderedBroadcast(backgroundIntent, receiverPermission, + receiverAppOp, resultReceiver, scheduler, initialCode, initialData, + initialExtras); + } + } +} diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index e94b8006d24a..906251837ade 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -56,8 +56,12 @@ public class DateUtils public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7; /** - * This constant is actually the length of 364 days, not of a year! + * @deprecated Not all years have the same number of days, and this constant is actually the + * length of 364 days. Please use other date/time constructs such as + * {@link java.util.concurrent.TimeUnit}, {@link java.util.Calendar} or + * {@link java.time.Duration} instead. */ + @Deprecated public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52; // The following FORMAT_* symbols are used for specifying the format of diff --git a/core/java/android/util/CloseGuard.java b/core/java/android/util/CloseGuard.java new file mode 100644 index 000000000000..c39a6c9aac93 --- /dev/null +++ b/core/java/android/util/CloseGuard.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2019 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.util; + +import android.annotation.NonNull; + +/** + * CloseGuard is a mechanism for flagging implicit finalizer cleanup of + * resources that should have been cleaned up by explicit close + * methods (aka "explicit termination methods" in Effective Java). + * <p> + * A simple example: <pre> {@code + * class Foo { + * + * private final CloseGuard guard = CloseGuard.get(); + * + * ... + * + * public Foo() { + * ...; + * guard.open("cleanup"); + * } + * + * public void cleanup() { + * guard.close(); + * ...; + * } + * + * protected void finalize() throws Throwable { + * try { + * // Note that guard could be null if the constructor threw. + * if (guard != null) { + * guard.warnIfOpen(); + * } + * cleanup(); + * } finally { + * super.finalize(); + * } + * } + * } + * }</pre> + * + * In usage where the resource to be explicitly cleaned up is + * allocated after object construction, CloseGuard protection can + * be deferred. For example: <pre> {@code + * class Bar { + * + * private final CloseGuard guard = CloseGuard.get(); + * + * ... + * + * public Bar() { + * ...; + * } + * + * public void connect() { + * ...; + * guard.open("cleanup"); + * } + * + * public void cleanup() { + * guard.close(); + * ...; + * Reference.reachabilityFence(this); + * // For full correctness in the absence of a close() call, other methods may also need + * // reachabilityFence() calls. + * } + * + * protected void finalize() throws Throwable { + * try { + * // Note that guard could be null if the constructor threw. + * if (guard != null) { + * guard.warnIfOpen(); + * } + * cleanup(); + * } finally { + * super.finalize(); + * } + * } + * } + * }</pre> + * + * When used in a constructor, calls to {@code open} should occur at + * the end of the constructor since an exception that would cause + * abrupt termination of the constructor will mean that the user will + * not have a reference to the object to cleanup explicitly. When used + * in a method, the call to {@code open} should occur just after + * resource acquisition. + */ +public final class CloseGuard { + private final dalvik.system.CloseGuard mImpl; + + /** + * Constructs a new CloseGuard instance. + * {@link #open(String)} can be used to set up the instance to warn on failure to close. + */ + public CloseGuard() { + mImpl = dalvik.system.CloseGuard.get(); + } + + /** + * Initializes the instance with a warning that the caller should have explicitly called the + * {@code closeMethodName} method instead of relying on finalization. + * + * @param closeMethodName non-null name of explicit termination method. Printed by warnIfOpen. + * @throws NullPointerException if closeMethodName is null. + */ + public void open(@NonNull String closeMethodName) { + mImpl.open(closeMethodName); + } + + /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */ + public void close() { + mImpl.close(); + } + + /** + * Logs a warning if the caller did not properly cleanup by calling an explicit close method + * before finalization. + */ + public void warnIfOpen() { + mImpl.warnIfOpen(); + } +} diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index a21187165c65..fa823c4bf2f6 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -367,8 +367,8 @@ public class RuntimeInit { if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); } - protected static Runnable applicationInit(int targetSdkVersion, String[] argv, - ClassLoader classLoader) { + protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, + String[] argv, ClassLoader classLoader) { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the @@ -377,6 +377,7 @@ public class RuntimeInit { nativeSetExitWithoutCleanup(true); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); + VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges); final Arguments args = new Arguments(argv); diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index f0e779694c90..790d7f7ab694 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -23,16 +23,18 @@ import android.system.Os; import android.system.OsConstants; import android.system.StructCapUserData; import android.system.StructCapUserHeader; -import android.util.TimingsTraceLog; import android.util.Slog; +import android.util.TimingsTraceLog; + import dalvik.system.VMRuntime; + +import libcore.io.IoUtils; + import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; -import libcore.io.IoUtils; - /** * Startup class for the wrapper process. * @hide @@ -166,10 +168,10 @@ public class WrapperInit { System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2); argv = removedArgs; } - // Perform the same initialization that would happen after the Zygote forks. Zygote.nativePreApplicationInit(); - return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); + return RuntimeInit.applicationInit(targetSdkVersion, /*disabledCompatChanges*/ null, + argv, classLoader); } /** diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 00ab45ec3537..33adec106d97 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -642,6 +642,7 @@ public final class Zygote { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return ZygoteInit.zygoteInit(args.mTargetSdkVersion, + args.mDisabledCompatChanges, args.mRemainingArgs, null /* classLoader */); } finally { diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index fc55ccf4d6b7..3915ba273dfa 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -210,6 +210,12 @@ class ZygoteArguments { int mHiddenApiAccessStatslogSampleRate = -1; /** + * A set of disabled app compatibility changes for the running app. From + * --disabled-compat-changes. + */ + long[] mDisabledCompatChanges = null; + + /** * Constructs instance and parses args * * @param args zygote command-line args @@ -416,6 +422,16 @@ class ZygoteArguments { mUsapPoolStatusSpecified = true; mUsapPoolEnabled = Boolean.parseBoolean(arg.substring(arg.indexOf('=') + 1)); expectRuntimeArgs = false; + } else if (arg.startsWith("--disabled-compat-changes=")) { + if (mDisabledCompatChanges != null) { + throw new IllegalArgumentException("Duplicate arg specified"); + } + final String[] params = arg.substring(arg.indexOf('=') + 1).split(","); + final int length = params.length; + mDisabledCompatChanges = new long[length]; + for (int i = 0; i < length; i++) { + mDisabledCompatChanges[i] = Long.parseLong(params[i]); + } } else { break; } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index b15e1efa46c8..4c37591d4a66 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -502,6 +502,7 @@ class ZygoteConnection { } else { if (!isZygote) { return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, + parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, null /* classLoader */); } else { return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion, diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 93e61020ff19..7b77a92e3d3a 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -547,6 +547,7 @@ public class ZygoteInit { * Pass the remaining arguments to SystemServer. */ return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, + parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, cl); } @@ -972,14 +973,16 @@ public class ZygoteInit { * * Current recognized args: * <ul> - * <li> <code> [--] <start class name> <args> + * <li> <code> [--] <start class name> <args> * </ul> * * @param targetSdkVersion target SDK version - * @param argv arg strings + * @param disabledCompatChanges set of disabled compat changes for the process (all others + * are enabled) + * @param argv arg strings */ - public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, - ClassLoader classLoader) { + public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, + String[] argv, ClassLoader classLoader) { if (RuntimeInit.DEBUG) { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote"); } @@ -989,7 +992,8 @@ public class ZygoteInit { RuntimeInit.commonInit(); ZygoteInit.nativeZygoteInit(); - return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); + return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, + classLoader); } /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a35c4dbdf383..8dc84c804055 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2030,6 +2030,11 @@ <!-- =========================================== --> <eat-comment /> + <!-- @SystemApi Allows granting runtime permissions to telephony related components. + @hide Used internally. --> + <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" + android:protectionLevel="signature|telephony" /> + <!-- Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. <p>Not for use by third-party applications. --> diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java index b906d84adf52..ed613c36b89b 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java @@ -176,14 +176,12 @@ public class BluetoothTestUtils extends Assert { mDevice.setPin(mPin); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY: - mDevice.setPasskey(mPasskey); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: case BluetoothDevice.PAIRING_VARIANT_CONSENT: mDevice.setPairingConfirmation(true); break; case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: - mDevice.setRemoteOutOfBandData(); break; } } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 1670d49a46c4..4d4f4476a974 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -24,6 +24,7 @@ android_test { ], static_libs: [ "frameworks-base-testutils", + "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport "core-tests-support", "android-common", "frameworks-core-util-lib", diff --git a/core/tests/coretests/src/android/util/CloseGuardTest.java b/core/tests/coretests/src/android/util/CloseGuardTest.java new file mode 100644 index 000000000000..d86c7b79fad6 --- /dev/null +++ b/core/tests/coretests/src/android/util/CloseGuardTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 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.util; + +import libcore.dalvik.system.CloseGuardSupport; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + +/** Unit tests for {@link android.util.CloseGuard} */ +public class CloseGuardTest { + + @Rule + public final TestRule rule = CloseGuardSupport.getRule(); + + @Test + public void testEnabled_NotOpen() throws Throwable { + ResourceOwner owner = new ResourceOwner(); + assertUnreleasedResources(owner, 0); + } + + @Test + public void testEnabled_OpenNotClosed() throws Throwable { + ResourceOwner owner = new ResourceOwner(); + owner.open(); + assertUnreleasedResources(owner, 1); + } + + @Test + public void testEnabled_OpenThenClosed() throws Throwable { + ResourceOwner owner = new ResourceOwner(); + owner.open(); + owner.close(); + assertUnreleasedResources(owner, 0); + } + + @Test(expected = NullPointerException.class) + public void testOpen_withNullMethodName_throwsNPE() throws Throwable { + CloseGuard closeGuard = new CloseGuard(); + closeGuard.open(null); + } + + private void assertUnreleasedResources(ResourceOwner owner, int expectedCount) + throws Throwable { + try { + CloseGuardSupport.getFinalizerChecker().accept(owner, expectedCount); + } finally { + // Close the resource so that CloseGuard does not generate a warning for real when it + // is actually finalized. + owner.close(); + } + } + + /** + * A test user of {@link CloseGuard}. + */ + private static class ResourceOwner { + + private final CloseGuard mCloseGuard; + + ResourceOwner() { + mCloseGuard = new CloseGuard(); + } + + public void open() { + mCloseGuard.open("close"); + } + + public void close() { + mCloseGuard.close(); + } + + /** + * Make finalize public so that it can be tested directly without relying on garbage + * collection to trigger it. + */ + @Override + public void finalize() throws Throwable { + mCloseGuard.warnIfOpen(); + super.finalize(); + } + } +} diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 3455c4f01ff9..1033e56776b9 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; +import android.telephony.TelephonyManager; import android.util.Log; import java.lang.annotation.Retention; @@ -1239,7 +1240,8 @@ public class AudioSystem * </ul> */ public static int getPlatformType(Context context) { - if (context.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) { + if (((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)) + .isVoiceCapable()) { return PLATFORM_VOICE; } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { return PLATFORM_TELEVISION; diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl index bd0518493557..f90c50491129 100644..100755 --- a/media/java/android/media/tv/ITvInputService.aidl +++ b/media/java/android/media/tv/ITvInputService.aidl @@ -38,4 +38,5 @@ oneway interface ITvInputService { void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo); void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo); void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo); + void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo); } diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index ff6977914ac3..5c11ed9bb7b4 100644..100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -173,6 +173,12 @@ public abstract class TvInputService extends Service { mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT, deviceInfo).sendToTarget(); } + + @Override + public void notifyHdmiDeviceUpdated(HdmiDeviceInfo deviceInfo) { + mServiceHandler.obtainMessage(ServiceHandler.DO_UPDATE_HDMI_INPUT, + deviceInfo).sendToTarget(); + } }; } @@ -257,6 +263,24 @@ public abstract class TvInputService extends Service { return null; } + /** + * Called when {@code deviceInfo} is updated. + * + * <p>The changes are usually cuased by the corresponding HDMI-CEC logical device. + * + * <p>The default behavior ignores all changes. + * + * <p>The TV input service responsible for {@code deviceInfo} can update the {@link TvInputInfo} + * object based on the updated {@code deviceInfo} (e.g. update the label based on the preferred + * device OSD name). + * + * @param deviceInfo the updated {@link HdmiDeviceInfo} object. + * @hide + */ + @SystemApi + public void onHdmiDeviceUpdated(@NonNull HdmiDeviceInfo deviceInfo) { + } + private boolean isPassthroughInput(String inputId) { if (mTvInputManager == null) { mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); @@ -1962,6 +1986,7 @@ public abstract class TvInputService extends Service { private static final int DO_REMOVE_HARDWARE_INPUT = 5; private static final int DO_ADD_HDMI_INPUT = 6; private static final int DO_REMOVE_HDMI_INPUT = 7; + private static final int DO_UPDATE_HDMI_INPUT = 8; private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) { int n = mCallbacks.beginBroadcast(); @@ -2131,6 +2156,11 @@ public abstract class TvInputService extends Service { } return; } + case DO_UPDATE_HDMI_INPUT: { + HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; + onHdmiDeviceUpdated(deviceInfo); + return; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); return; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 96aee512c090..a2bd210b67a6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -155,8 +155,8 @@ public class A2dpProfile implements LocalBluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (mService == null) return false; // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -179,23 +179,29 @@ public class A2dpProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(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); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } boolean isA2dpPlaying() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java index 55765dd40d36..9c896c80b409 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java @@ -124,8 +124,8 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -141,14 +141,14 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -156,11 +156,11 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 0d972c5e2e0e..2f34b2bad0ad 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -116,7 +116,7 @@ public class BluetoothUtils { } return new Pair<>( getBluetoothDrawable(context, - com.android.internal.R.drawable.ic_settings_bluetooth), + com.android.internal.R.drawable.ic_settings_bluetooth).mutate(), context.getString(R.string.bluetooth_talkback_bluetooth)); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index c1b89e6f660d..abfee1d415d6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -643,12 +643,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> refresh(); - if (bondState == BluetoothDevice.BOND_BONDED) { - if (mDevice.isBluetoothDock()) { - onBondingDockConnect(); - } else if (mDevice.isBondingInitiatedLocally()) { - connect(false); - } + if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) { + connect(false); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 9f7b7181b19f..560cb3b9b5b4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -120,8 +120,8 @@ public class HeadsetProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -165,14 +165,14 @@ public class HeadsetProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -180,11 +180,11 @@ public class HeadsetProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index ebaeb742b198..58655a2b930a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -153,8 +153,8 @@ public class HearingAidProfile implements LocalBluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (mService == null) return false; // Downgrade priority as user is disconnecting the hearing aid. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -177,23 +177,29 @@ public class HearingAidProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(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); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java index 860b77d1ebcd..a372e23654e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java @@ -135,8 +135,8 @@ final class HfpClientProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -154,15 +154,15 @@ final class HfpClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } @Override public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } @Override @@ -171,11 +171,11 @@ final class HfpClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java index 6d874ab2be9b..975a1e67af5b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java @@ -116,23 +116,27 @@ public class HidProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; - return mService.getPriority(device) != BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return false; + } + return mService.getConnectionPolicy(device) != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; - return mService.getPriority(device); + if (mService == null) { + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + } + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { if (mService == null) return; if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java index d4dda329fa63..95139a1bfab9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java @@ -123,8 +123,8 @@ public final class MapClientProfile implements LocalBluetoothProfile { return false; } // Downgrade priority as user is disconnecting. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -140,14 +140,14 @@ public final class MapClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -155,11 +155,11 @@ public final class MapClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java index b2a9a6a28231..31a0eea56b42 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java @@ -119,8 +119,8 @@ public class MapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -136,14 +136,14 @@ public class MapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -151,11 +151,11 @@ public class MapProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS index 7162121330ef..387bae130374 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS @@ -1,8 +1,7 @@ # Default reviewers for this and subdirectories. -asapperstein@google.com -asargent@google.com -eisenbach@google.com -jackqdyulei@google.com siyuanh@google.com +hughchen@google.com +timhypeng@google.com +robertluo@google.com -# Emergency approvers in case the above are not available
\ No newline at end of file +# Emergency approvers in case the above are not available diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java index e1e5dbe29a1a..8e3f3edcef10 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java @@ -57,7 +57,7 @@ final class OppProfile implements LocalBluetoothProfile { } public int getPreferred(BluetoothDevice device) { - return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; // Settings app doesn't handle OPP } public void setPreferred(BluetoothDevice device, boolean preferred) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java index a2da4fb30e39..4ea0df621bea 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java @@ -151,14 +151,14 @@ public final class PbapClientProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -166,11 +166,11 @@ public final class PbapClientProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java index 9b733f2e0e50..0ca4d6195a32 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -119,8 +119,8 @@ final class SapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } return mService.disconnect(device); } @@ -136,14 +136,14 @@ final class SapProfile implements LocalBluetoothProfile { if (mService == null) { return false; } - return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + return mService.getConnectionPolicy(device) > BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } public int getPreferred(BluetoothDevice device) { if (mService == null) { - return BluetoothProfile.PRIORITY_OFF; + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } - return mService.getPriority(device); + return mService.getConnectionPolicy(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { @@ -151,11 +151,11 @@ final class SapProfile implements LocalBluetoothProfile { return; } if (preferred) { - if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { - mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + if (mService.getConnectionPolicy(device) < BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED); } } else { - mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 5e2b7c86ee93..6821942111f1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -949,8 +949,7 @@ class DatabaseHelper extends SQLiteOpenHelper { (1 << AudioManager.STREAM_NOTIFICATION) | (1 << AudioManager.STREAM_SYSTEM) | (1 << AudioManager.STREAM_SYSTEM_ENFORCED); - if (!mContext.getResources().getBoolean( - com.android.internal.R.bool.config_voice_capable)) { + if (!getTelephonyManager().isVoiceCapable()) { ringerModeAffectedStreams |= (1 << AudioManager.STREAM_MUSIC); } db.execSQL("DELETE FROM system WHERE name='" @@ -2579,7 +2578,7 @@ class DatabaseHelper extends SQLiteOpenHelper { String val = ""; String mode; for (int phoneId = 0; - phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) { + phoneId < getTelephonyManager().getPhoneCount(); phoneId++) { mode = TelephonyManager.getTelephonyProperty(phoneId, "ro.telephony.default_network", Integer.toString(RILConstants.PREFERRED_NETWORK_MODE)); @@ -2693,4 +2692,9 @@ class DatabaseHelper extends SQLiteOpenHelper { private String getDefaultDeviceName() { return mContext.getResources().getString(R.string.def_device_name_simple, Build.MODEL); } + + private TelephonyManager getTelephonyManager() { + return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + } + } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 4dbca47c2f0a..9d9cad825444 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -163,8 +163,7 @@ public class CarrierTextController { public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, boolean showMissingSim) { mContext = context; - mIsEmergencyCallCapable = context.getResources().getBoolean( - com.android.internal.R.bool.config_voice_capable); + mIsEmergencyCallCapable = getTelephonyManager().isVoiceCapable(); mShowAirplaneMode = showAirplaneMode; mShowMissingSim = showMissingSim; diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index 210b82d1d69c..1acccf90c0eb 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Slog; import android.view.MotionEvent; @@ -92,13 +93,16 @@ public class EmergencyButton extends Button { public EmergencyButton(Context context, AttributeSet attrs) { super(context, attrs); - mIsVoiceCapable = context.getResources().getBoolean( - com.android.internal.R.bool.config_voice_capable); + mIsVoiceCapable = getTelephonyManager().isVoiceCapable(); mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); } + private TelephonyManager getTelephonyManager() { + return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 75231448ccfc..0278258ea4b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -51,8 +51,8 @@ import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionD import java.io.PrintWriter; import java.util.BitSet; -import java.util.Objects; import java.util.List; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -556,8 +556,8 @@ public class MobileSignalController extends SignalController< // If this is the data subscription, update the currentState data name if (mCurrentState.networkNameData.equals(mNetworkNameDefault) && mServiceState != null && mCurrentState.dataSim - && !TextUtils.isEmpty(mServiceState.getDataOperatorAlphaShort())) { - mCurrentState.networkNameData = mServiceState.getDataOperatorAlphaShort(); + && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) { + mCurrentState.networkNameData = mServiceState.getOperatorAlphaShort(); } notifyListenersIfNecessary(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index aa4723acba62..99e5a76b3a11 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -500,7 +500,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { public void testUpdateDataNetworkName() { setupDefaultSignal(); String newDataName = "TestDataName"; - when(mServiceState.getDataOperatorAlphaShort()).thenReturn(newDataName); + when(mServiceState.getOperatorAlphaShort()).thenReturn(newDataName); updateServiceState(); assertDataNetworkNameEquals(newDataName); } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 7e8721d3cc70..3c953b348ed9 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -31,6 +31,7 @@ java_defaults { "android.hardware.tetheroffload.control-V1.0-java", "tethering-client", ], + libs: ["unsupportedappusage"], manifest: "AndroidManifestBase.xml", } diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index eb0d443f4bfc..7fb286b5fa11 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -17,6 +17,7 @@ package android.net; import static android.Manifest.permission.NETWORK_STACK; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; +import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL; import android.annotation.NonNull; import android.annotation.Nullable; @@ -175,6 +176,10 @@ public class TetheringManager { */ @Deprecated public int tether(@NonNull String iface) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return TETHER_ERROR_SERVICE_UNAVAIL; + } try { mConnector.tether(iface); } catch (RemoteException e) { @@ -191,6 +196,10 @@ public class TetheringManager { */ @Deprecated public int untether(@NonNull String iface) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return TETHER_ERROR_SERVICE_UNAVAIL; + } try { mConnector.untether(iface); } catch (RemoteException e) { @@ -210,6 +219,10 @@ public class TetheringManager { */ @Deprecated public int setUsbTethering(boolean enable) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return TETHER_ERROR_SERVICE_UNAVAIL; + } try { mConnector.setUsbTethering(enable); } catch (RemoteException e) { @@ -227,6 +240,10 @@ public class TetheringManager { // TODO: improve the usage of ResultReceiver, b/145096122 public void startTethering(int type, @NonNull ResultReceiver receiver, boolean showProvisioningUi) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return; + } try { mConnector.startTethering(type, receiver, showProvisioningUi); } catch (RemoteException e) { @@ -241,6 +258,10 @@ public class TetheringManager { * {@hide} */ public void stopTethering(int type) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return; + } try { mConnector.stopTethering(type); } catch (RemoteException e) { @@ -258,6 +279,10 @@ public class TetheringManager { // TODO: improve the usage of ResultReceiver, b/145096122 public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver, boolean showEntitlementUi) { + if (mConnector == null) { + Slog.wtf(TAG, "Tethering not ready yet"); + return; + } try { mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); } catch (RemoteException e) { diff --git a/services/Android.bp b/services/Android.bp index ef40a351c8d1..3b566078bd51 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -1,3 +1,37 @@ +filegroup { + name: "services-main-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//visibility:private"], +} + +filegroup { + name: "services-sources", + srcs: [ + ":services.core-sources", + ":services.accessibility-sources", + ":services.appprediction-sources", + ":services.appwidget-sources", + ":services.autofill-sources", + ":services.backup-sources", + ":services.companion-sources", + ":services.contentcapture-sources", + ":services.contentsuggestions-sources", + ":services.coverage-sources", + ":services.devicepolicy-sources", + ":services.midi-sources", + ":services.net-sources", + ":services.print-sources", + ":services.restrictions-sources", + ":services.startop.iorap-sources", + ":services.systemcaptions-sources", + ":services.usage-sources", + ":services.usb-sources", + ":services.voiceinteraction-sources", + ], + visibility: ["//visibility:private"], +} + // merge all required services into one jar // ============================================================ java_library { @@ -9,9 +43,7 @@ java_library { profile: "art-profile", }, - srcs: [ - "java/**/*.java", - ], + srcs: [":services-main-sources"], // The convention is to name each service module 'services.$(module_name)' static_libs: [ diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp index f991d7b50fcb..284a2f2626a4 100644 --- a/services/accessibility/Android.bp +++ b/services/accessibility/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.accessibility-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.accessibility", - srcs: ["java/**/*.java"], + srcs: [":services.accessibility-sources"], libs: ["services.core"], } diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp index a7be58783aab..e14e1df0b5c7 100644 --- a/services/appprediction/Android.bp +++ b/services/appprediction/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.appprediction-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.appprediction", - srcs: ["java/**/*.java"], + srcs: [":services.appprediction-sources"], libs: ["services.core"], } diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp index aad2ad198bb7..54cf6cec78ea 100644 --- a/services/appwidget/Android.bp +++ b/services/appwidget/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.appwidget-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.appwidget", - srcs: ["java/**/*.java"], + srcs: [":services.appwidget-sources"], libs: ["services.core"], } diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp index 2768c1851314..539eb1a5220e 100644 --- a/services/autofill/Android.bp +++ b/services/autofill/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.autofill-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.autofill", - srcs: ["java/**/*.java"], + srcs: [":services.autofill-sources"], libs: ["services.core"], } diff --git a/services/backup/Android.bp b/services/backup/Android.bp index ef03d83d4916..f945d0f837a1 100644 --- a/services/backup/Android.bp +++ b/services/backup/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.backup-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.backup", - srcs: ["java/**/*.java"], + srcs: [":services.backup-sources"], libs: ["services.core"], } diff --git a/services/companion/Android.bp b/services/companion/Android.bp index d2dac357a227..9677a7d83bfb 100644 --- a/services/companion/Android.bp +++ b/services/companion/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.companion-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.companion", - srcs: ["java/**/*.java"], + srcs: [":services.companion-sources"], libs: ["services.core"], } diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp index 57e859ebe121..96e20726fed3 100644 --- a/services/contentcapture/Android.bp +++ b/services/contentcapture/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.contentcapture-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.contentcapture", - srcs: ["java/**/*.java"], + srcs: [":services.contentcapture-sources"], libs: ["services.core"], } diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp index fc09d2e5196a..d17f06f79e97 100644 --- a/services/contentsuggestions/Android.bp +++ b/services/contentsuggestions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.contentsuggestions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.contentsuggestions", - srcs: ["java/**/*.java"], + srcs: [":services.contentsuggestions-sources"], libs: ["services.core"], -}
\ No newline at end of file +} diff --git a/services/core/Android.bp b/services/core/Android.bp index 4e75e006e111..725303dc6f1b 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -1,24 +1,21 @@ +filegroup { + name: "services.core-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.core.unboosted", - - aidl: { - include_dirs: [ - "frameworks/base/cmds/idmap2/idmap2d/aidl", - "frameworks/native/aidl/binder", - "frameworks/native/cmds/dumpstate/binder", - "system/core/storaged/binder", - "system/vold/binder", - "system/gsid/aidl", - ], - }, srcs: [ "java/**/*.java", ":dumpstate_aidl", + ":framework_native_aidl", + ":gsiservice_aidl", ":idmap2_aidl", ":installd_aidl", ":storaged_aidl", ":vold_aidl", - ":gsiservice_aidl", ":platform-compat-config", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f8f685d939a7..b71943504bf6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5573,7 +5573,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param linkProperties the initial link properties of this network. They can be updated * later : see {@link #updateLinkProperties}. * @param networkCapabilities the initial capabilites of this network. They can be updated - * later : see {@link #updateNetworkCapabilities}. + * later : see {@link #updateCapabilities}. * @param currentScore the initial score of the network. See * {@link NetworkAgentInfo#getCurrentScore}. * @param networkMisc metadata about the network. This is never updated. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5ffdf02ef11e..35774ed3ca6f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2411,7 +2411,8 @@ public class ActivityManagerService extends IActivityManager.Stub mConstants = hasHandlerThread ? new ActivityManagerConstants(mContext, this, mHandler) : null; final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */); - mProcessList.init(this, activeUids); + mPlatformCompat = null; + mProcessList.init(this, activeUids, mPlatformCompat); mLowMemDetector = null; mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids); @@ -2432,7 +2433,6 @@ public class ActivityManagerService extends IActivityManager.Stub mProcStartHandler = null; mHiddenApiBlacklist = null; mFactoryTest = FACTORY_TEST_OFF; - mPlatformCompat = null; } // Note: This method is invoked on the main thread but may need to attach various @@ -2461,7 +2461,9 @@ public class ActivityManagerService extends IActivityManager.Stub mConstants = new ActivityManagerConstants(mContext, this, mHandler); final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */); - mProcessList.init(this, activeUids); + mPlatformCompat = (PlatformCompat) ServiceManager.getService( + Context.PLATFORM_COMPAT_SERVICE); + mProcessList.init(this, activeUids, mPlatformCompat); mLowMemDetector = new LowMemDetector(this); mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids); @@ -2569,9 +2571,6 @@ public class ActivityManagerService extends IActivityManager.Stub mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext); - mPlatformCompat = (PlatformCompat) ServiceManager.getService( - Context.PLATFORM_COMPAT_SERVICE); - Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); @@ -5048,9 +5047,7 @@ public class ActivityManagerService extends IActivityManager.Stub bindApplicationTimeMillis = SystemClock.elapsedRealtime(); mAtmInternal.preBindApplication(app.getWindowProcessController()); final ActiveInstrumentation instr2 = app.getActiveInstrumentation(); - long[] disabledCompatChanges = {}; if (mPlatformCompat != null) { - disabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info); mPlatformCompat.resetReporting(app.info); } if (app.isolatedEntryPoint != null) { @@ -5069,7 +5066,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - disabledCompatChanges); + app.mDisabledCompatChanges); } else { thread.bindApplication(processName, appInfo, providers, null, profilerInfo, null, null, null, testMode, @@ -5079,7 +5076,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, - disabledCompatChanges); + app.mDisabledCompatChanges); } if (profilerInfo != null) { profilerInfo.closeFd(); diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java new file mode 100644 index 000000000000..cacf6765a28e --- /dev/null +++ b/services/core/java/com/android/server/am/LmkdConnection.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; + +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.os.MessageQueue; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import libcore.io.IoUtils; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +/** + * Lmkd connection to communicate with lowmemorykiller daemon. + */ +public class LmkdConnection { + private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM; + + // lmkd reply max size in bytes + private static final int LMKD_REPLY_MAX_SIZE = 12; + + // connection listener interface + interface LmkdConnectionListener { + boolean onConnect(OutputStream ostream); + void onDisconnect(); + /** + * Check if received reply was expected (reply to an earlier request) + * + * @param replyBuf The buffer provided in exchange() to receive the reply. + * It can be used by exchange() caller to store reply-specific + * tags for later use in isReplyExpected() to verify if + * received packet is the expected reply. + * @param dataReceived The buffer holding received data + * @param receivedLen Size of the data received + */ + boolean isReplyExpected(ByteBuffer replyBuf, ByteBuffer dataReceived, + int receivedLen); + + /** + * Handle the received message if it's unsolicited. + * + * @param dataReceived The buffer holding received data + * @param receivedLen Size of the data received + * @return True if the message has been handled correctly, false otherwise. + */ + boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen); + } + + private final MessageQueue mMsgQueue; + + // lmkd connection listener + private final LmkdConnectionListener mListener; + + // mutex to synchronize access to the socket + private final Object mLmkdSocketLock = new Object(); + + // socket to communicate with lmkd + @GuardedBy("mLmkdSocketLock") + private LocalSocket mLmkdSocket = null; + + // socket I/O streams + @GuardedBy("mLmkdSocketLock") + private OutputStream mLmkdOutputStream = null; + @GuardedBy("mLmkdSocketLock") + private InputStream mLmkdInputStream = null; + + // buffer to store incoming data + private final ByteBuffer mInputBuf = + ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE); + + // object to protect mReplyBuf and to wait/notify when reply is received + private final Object mReplyBufLock = new Object(); + + // reply buffer + @GuardedBy("mReplyBufLock") + private ByteBuffer mReplyBuf = null; + + //////////////////// END FIELDS //////////////////// + + LmkdConnection(MessageQueue msgQueue, LmkdConnectionListener listener) { + mMsgQueue = msgQueue; + mListener = listener; + } + + boolean connect() { + synchronized (mLmkdSocketLock) { + if (mLmkdSocket != null) { + return true; + } + // temporary sockets and I/O streams + final LocalSocket socket = openSocket(); + + if (socket == null) { + Slog.w(TAG, "Failed to connect to lowmemorykiller, retry later"); + return false; + } + + final OutputStream ostream; + final InputStream istream; + try { + ostream = socket.getOutputStream(); + istream = socket.getInputStream(); + } catch (IOException ex) { + IoUtils.closeQuietly(socket); + return false; + } + // execute onConnect callback + if (mListener != null && !mListener.onConnect(ostream)) { + Slog.w(TAG, "Failed to communicate with lowmemorykiller, retry later"); + IoUtils.closeQuietly(socket); + return false; + } + // connection established + mLmkdSocket = socket; + mLmkdOutputStream = ostream; + mLmkdInputStream = istream; + mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(), + EVENT_INPUT | EVENT_ERROR, + new MessageQueue.OnFileDescriptorEventListener() { + public int onFileDescriptorEvents(FileDescriptor fd, int events) { + return fileDescriptorEventHandler(fd, events); + } + } + ); + mLmkdSocketLock.notifyAll(); + } + return true; + } + + private int fileDescriptorEventHandler(FileDescriptor fd, int events) { + if (mListener == null) { + return 0; + } + if ((events & EVENT_INPUT) != 0) { + processIncomingData(); + } + if ((events & EVENT_ERROR) != 0) { + synchronized (mLmkdSocketLock) { + // stop listening on this socket + mMsgQueue.removeOnFileDescriptorEventListener( + mLmkdSocket.getFileDescriptor()); + IoUtils.closeQuietly(mLmkdSocket); + mLmkdSocket = null; + } + // wake up reply waiters if any + synchronized (mReplyBufLock) { + if (mReplyBuf != null) { + mReplyBuf = null; + mReplyBufLock.notifyAll(); + } + } + // notify listener + mListener.onDisconnect(); + return 0; + } + return (EVENT_INPUT | EVENT_ERROR); + } + + private void processIncomingData() { + int len = read(mInputBuf); + if (len > 0) { + synchronized (mReplyBufLock) { + if (mReplyBuf != null) { + if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) { + // copy into reply buffer + mReplyBuf.put(mInputBuf.array(), 0, len); + mReplyBuf.rewind(); + // wakeup the waiting thread + mReplyBufLock.notifyAll(); + } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) { + // received unexpected packet + // treat this as an error + mReplyBuf = null; + mReplyBufLock.notifyAll(); + Slog.e(TAG, "Received an unexpected packet from lmkd"); + } + } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) { + // received asynchronous communication from lmkd + // but we don't recognize it. + Slog.w(TAG, "Received an unexpected packet from lmkd"); + } + } + } + } + + boolean isConnected() { + synchronized (mLmkdSocketLock) { + return (mLmkdSocket != null); + } + } + + boolean waitForConnection(long timeoutMs) { + synchronized (mLmkdSocketLock) { + if (mLmkdSocket != null) { + return true; + } + try { + mLmkdSocketLock.wait(timeoutMs); + return (mLmkdSocket != null); + } catch (InterruptedException e) { + return false; + } + } + } + + private LocalSocket openSocket() { + final LocalSocket socket; + + try { + socket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET); + socket.connect( + new LocalSocketAddress("lmkd", + LocalSocketAddress.Namespace.RESERVED)); + } catch (IOException ex) { + Slog.e(TAG, "Connection failed: " + ex.toString()); + return null; + } + return socket; + } + + private boolean write(ByteBuffer buf) { + synchronized (mLmkdSocketLock) { + try { + mLmkdOutputStream.write(buf.array(), 0, buf.position()); + } catch (IOException ex) { + return false; + } + return true; + } + } + + private int read(ByteBuffer buf) { + synchronized (mLmkdSocketLock) { + try { + return mLmkdInputStream.read(buf.array(), 0, buf.array().length); + } catch (IOException ex) { + } + return -1; + } + } + + /** + * Exchange a request/reply packets with lmkd + * + * @param req The buffer holding the request data to be sent + * @param repl The buffer to receive the reply + */ + public boolean exchange(ByteBuffer req, ByteBuffer repl) { + if (repl == null) { + return write(req); + } + + boolean result = false; + // set reply buffer to user-defined one to fill it + synchronized (mReplyBufLock) { + mReplyBuf = repl; + + if (write(req)) { + try { + // wait for the reply + mReplyBufLock.wait(); + result = (mReplyBuf != null); + } catch (InterruptedException ie) { + result = false; + } + } + + // reset reply buffer + mReplyBuf = null; + } + return result; + } +} diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index a2670d8dd424..3b8d39bf7a19 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -57,8 +57,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.Resources; import android.graphics.Point; -import android.net.LocalSocket; -import android.net.LocalSocketAddress; import android.os.AppZygote; import android.os.Binder; import android.os.Build; @@ -96,17 +94,15 @@ import com.android.internal.util.MemInfoReader; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.Watchdog; +import com.android.server.compat.PlatformCompat; import com.android.server.pm.dex.DexManager; import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; -import libcore.io.IoUtils; - import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.ByteBuffer; @@ -117,11 +113,6 @@ import java.util.List; /** * Activity manager code dealing with processes. - * - * Method naming convention: - * <ul> - * <li> Methods suffixed with "LS" should be called within the {@link #sLmkdSocketLock} lock. - * </ul> */ public final class ProcessList { static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM; @@ -262,11 +253,16 @@ public final class ProcessList { // LMK_PROCREMOVE <pid> // LMK_PROCPURGE // LMK_GETKILLCNT + // LMK_PROCKILL static final byte LMK_TARGET = 0; static final byte LMK_PROCPRIO = 1; static final byte LMK_PROCREMOVE = 2; static final byte LMK_PROCPURGE = 3; static final byte LMK_GETKILLCNT = 4; + static final byte LMK_PROCKILL = 5; // Note: this is an unsolicated command + + // lmkd reconnect delay in msecs + private static final long LMKD_RECONNECT_DELAY_MS = 1000; ActivityManagerService mService = null; @@ -302,16 +298,9 @@ public final class ProcessList { private boolean mHaveDisplaySize; - private static Object sLmkdSocketLock = new Object(); - - @GuardedBy("sLmkdSocketLock") - private static LocalSocket sLmkdSocket; - - @GuardedBy("sLmkdSocketLock") - private static OutputStream sLmkdOutputStream; + private static LmkdConnection sLmkdConnection = null; - @GuardedBy("sLmkdSocketLock") - private static InputStream sLmkdInputStream; + private boolean mOomLevelsSet = false; /** * Temporary to avoid allocations. Protected by main lock. @@ -369,6 +358,12 @@ public final class ProcessList { ActiveUids mActiveUids; /** + * The listener who is intereted with the lmkd kills. + */ + @GuardedBy("mService") + private LmkdKillListener mLmkdKillListener = null; + + /** * The currently running isolated processes. */ final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>(); @@ -384,6 +379,15 @@ public final class ProcessList { final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses = new ArrayMap<AppZygote, ArrayList<ProcessRecord>>(); + private PlatformCompat mPlatformCompat = null; + + interface LmkdKillListener { + /** + * Called when there is a process kill by lmkd. + */ + void onLmkdKillOccurred(int pid, int uid); + } + final class IsolatedUidRange { @VisibleForTesting public final int mFirstUid; @@ -536,6 +540,8 @@ public final class ProcessList { final class KillHandler extends Handler { static final int KILL_PROCESS_GROUP_MSG = 4000; + static final int LMKD_RECONNECT_MSG = 4001; + static final int LMKD_PROC_KILLED_MSG = 4002; public KillHandler(Looper looper) { super(looper, null, true); @@ -549,6 +555,18 @@ public final class ProcessList { Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; + case LMKD_RECONNECT_MSG: + if (!sLmkdConnection.connect()) { + Slog.i(TAG, "Failed to connect to lmkd, retry after " + + LMKD_RECONNECT_DELAY_MS + " ms"); + // retry after LMKD_RECONNECT_DELAY_MS + sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage( + KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS); + } + break; + case LMKD_PROC_KILLED_MSG: + handleLmkdProcKilled(msg.arg1 /* pid */, msg.arg2 /* uid */); + break; default: super.handleMessage(msg); @@ -565,15 +583,61 @@ public final class ProcessList { updateOomLevels(0, 0, false); } - void init(ActivityManagerService service, ActiveUids activeUids) { + void init(ActivityManagerService service, ActiveUids activeUids, + PlatformCompat platformCompat) { mService = service; mActiveUids = activeUids; + mPlatformCompat = platformCompat; if (sKillHandler == null) { sKillThread = new ServiceThread(TAG + ":kill", THREAD_PRIORITY_BACKGROUND, true /* allowIo */); sKillThread.start(); sKillHandler = new KillHandler(sKillThread.getLooper()); + sLmkdConnection = new LmkdConnection(sKillThread.getLooper().getQueue(), + new LmkdConnection.LmkdConnectionListener() { + @Override + public boolean onConnect(OutputStream ostream) { + Slog.i(TAG, "Connection with lmkd established"); + return onLmkdConnect(ostream); + } + @Override + public void onDisconnect() { + Slog.w(TAG, "Lost connection to lmkd"); + // start reconnection after delay to let lmkd restart + sKillHandler.sendMessageDelayed(sKillHandler.obtainMessage( + KillHandler.LMKD_RECONNECT_MSG), LMKD_RECONNECT_DELAY_MS); + } + @Override + public boolean isReplyExpected(ByteBuffer replyBuf, + ByteBuffer dataReceived, int receivedLen) { + // compare the preambule (currently one integer) to check if + // this is the reply packet we are waiting for + return (receivedLen == replyBuf.array().length + && dataReceived.getInt(0) == replyBuf.getInt(0)); + } + + @Override + public boolean handleUnsolicitedMessage(ByteBuffer dataReceived, + int receivedLen) { + if (receivedLen < 4) { + return false; + } + switch (dataReceived.getInt(0)) { + case LMK_PROCKILL: + if (receivedLen != 12) { + return false; + } + sKillHandler.obtainMessage(KillHandler.LMKD_PROC_KILLED_MSG, + dataReceived.getInt(4), dataReceived.getInt(8)) + .sendToTarget(); + return true; + default: + return false; + } + } + } + ); } } @@ -679,6 +743,7 @@ public final class ProcessList { writeLmkd(buf, null); SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve)); + mOomLevelsSet = true; } // GB: 2048,3072,4096,6144,7168,8192 // HC: 8192,10240,12288,14336,16384,20480 @@ -1218,93 +1283,50 @@ public final class ProcessList { buf.putInt(LMK_GETKILLCNT); buf.putInt(min_oom_adj); buf.putInt(max_oom_adj); - if (writeLmkd(buf, repl)) { - int i = repl.getInt(); - if (i != LMK_GETKILLCNT) { - Slog.e("ActivityManager", "Failed to get kill count, code mismatch"); - return null; - } + // indicate what we are waiting for + repl.putInt(LMK_GETKILLCNT); + repl.rewind(); + if (writeLmkd(buf, repl) && repl.getInt() == LMK_GETKILLCNT) { return new Integer(repl.getInt()); } return null; } - @GuardedBy("sLmkdSocketLock") - private static boolean openLmkdSocketLS() { + boolean onLmkdConnect(OutputStream ostream) { try { - sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET); - sLmkdSocket.connect( - new LocalSocketAddress("lmkd", - LocalSocketAddress.Namespace.RESERVED)); - sLmkdOutputStream = sLmkdSocket.getOutputStream(); - sLmkdInputStream = sLmkdSocket.getInputStream(); - } catch (IOException ex) { - Slog.w(TAG, "lowmemorykiller daemon socket open failed"); - sLmkdSocket = null; - return false; - } - - return true; - } - - // Never call directly, use writeLmkd() instead - @GuardedBy("sLmkdSocketLock") - private static boolean writeLmkdCommandLS(ByteBuffer buf) { - try { - sLmkdOutputStream.write(buf.array(), 0, buf.position()); + // Purge any previously registered pids + ByteBuffer buf = ByteBuffer.allocate(4); + buf.putInt(LMK_PROCPURGE); + ostream.write(buf.array(), 0, buf.position()); + if (mOomLevelsSet) { + // Reset oom_adj levels + buf = ByteBuffer.allocate(4 * (2 * mOomAdj.length + 1)); + buf.putInt(LMK_TARGET); + for (int i = 0; i < mOomAdj.length; i++) { + buf.putInt((mOomMinFree[i] * 1024) / PAGE_SIZE); + buf.putInt(mOomAdj[i]); + } + ostream.write(buf.array(), 0, buf.position()); + } } catch (IOException ex) { - Slog.w(TAG, "Error writing to lowmemorykiller socket"); - IoUtils.closeQuietly(sLmkdSocket); - sLmkdSocket = null; return false; } return true; } - // Never call directly, use writeLmkd() instead - @GuardedBy("sLmkdSocketLock") - private static boolean readLmkdReplyLS(ByteBuffer buf) { - int len; - try { - len = sLmkdInputStream.read(buf.array(), 0, buf.array().length); - if (len == buf.array().length) { - return true; - } - } catch (IOException ex) { - Slog.w(TAG, "Error reading from lowmemorykiller socket"); - } - - IoUtils.closeQuietly(sLmkdSocket); - sLmkdSocket = null; - return false; - } - private static boolean writeLmkd(ByteBuffer buf, ByteBuffer repl) { - synchronized (sLmkdSocketLock) { - for (int i = 0; i < 3; i++) { - if (sLmkdSocket == null) { - if (openLmkdSocketLS() == false) { - try { - Thread.sleep(1000); - } catch (InterruptedException ie) { - } - continue; - } + if (!sLmkdConnection.isConnected()) { + // try to connect immediately and then keep retrying + sKillHandler.sendMessage( + sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG)); - // Purge any previously registered pids - ByteBuffer purge_buf = ByteBuffer.allocate(4); - purge_buf.putInt(LMK_PROCPURGE); - if (writeLmkdCommandLS(purge_buf) == false) { - // Write failed, skip the rest and retry - continue; - } - } - if (writeLmkdCommandLS(buf) && (repl == null || readLmkdReplyLS(repl))) { - return true; - } + // wait for connection retrying 3 times (up to 3 seconds) + if (!sLmkdConnection.waitForConnection(3 * LMKD_RECONNECT_DELAY_MS)) { + return false; } } - return false; + + return sLmkdConnection.exchange(buf, repl); } static void killProcessGroup(int uid, int pid) { @@ -1657,6 +1679,10 @@ public final class ProcessList { Slog.wtf(TAG, "startProcessLocked processName:" + app.processName + " with non-zero pid:" + app.pid); } + app.mDisabledCompatChanges = null; + if (mPlatformCompat != null) { + app.mDisabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info); + } final long startSeq = app.startSeq = ++mProcStartSeqCounter; app.setStartParams(uid, hostingRecord, seInfo, startTime); app.setUsingWrapper(invokeWith != null @@ -1811,8 +1837,8 @@ public final class ProcessList { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, - app.info.dataDir, null, app.info.packageName, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges, + new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); @@ -1820,14 +1846,15 @@ public final class ProcessList { app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, - /*useUsapPool=*/ false, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + /*useUsapPool=*/ false, app.mDisabledCompatChanges, + new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, - new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + app.mDisabledCompatChanges, + new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } checkSlow(startTime, "startProcess: returned from zygote!"); return startResult; @@ -3204,4 +3231,28 @@ public final class ProcessList { mService.doStopUidLocked(uidRec.uid, uidRec); } } + + void setLmkdKillListener(final LmkdKillListener listener) { + synchronized (mService) { + mLmkdKillListener = listener; + } + } + + private void handleLmkdProcKilled(final int pid, final int uid) { + // Log only now + if (DEBUG_PROCESSES) { + Slog.i(TAG, "lmkd kill: pid=" + pid + " uid=" + uid); + } + + if (mService == null) { + return; + } + // Notify any interesed party regarding the lmkd kills + synchronized (mService) { + final LmkdKillListener listener = mLmkdKillListener; + if (listener != null) { + mService.mHandler.post(()-> listener.onLmkdKillOccurred(pid, uid)); + } + } + } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index ea3084274ae0..8c1a0d3abcd2 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -307,6 +307,8 @@ class ProcessRecord implements WindowProcessListener { long startTime; // This will be same as {@link #uid} usually except for some apps used during factory testing. int startUid; + // set of disabled compat changes for the process (all others are enabled) + long[] mDisabledCompatChanges; void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 37add3da5a48..135f199d88be 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -62,9 +62,6 @@ public class AudioDeviceInventory { private @NonNull AudioDeviceBroker mDeviceBroker; - // cache of the address of the last dock the device was connected to - private String mDockAddress; - // Monitoring of audio routes. Protected by mAudioRoutes. final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers = @@ -168,7 +165,7 @@ public class AudioDeviceInventory { int a2dpVolume = btInfo.getVolume(); if (AudioService.DEBUG_DEVICES) { Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state=" - + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume); + + state + " vol=" + a2dpVolume); } String address = btDevice.getAddress(); if (!BluetoothAdapter.checkBluetoothAddress(address)) { @@ -196,42 +193,17 @@ public class AudioDeviceInventory { mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice); } } else { - if (btDevice.isBluetoothDock()) { - if (state == BluetoothProfile.STATE_DISCONNECTED) { - // introduction of a delay for transient disconnections of docks when - // power is rapidly turned off/on, this message will be canceled if - // we reconnect the dock under a preset delay - makeA2dpDeviceUnavailableLater(address, - AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS); - // the next time isConnected is evaluated, it will be false for the dock - } - } else { - makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); - } + makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); } - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - if (btDevice.isBluetoothDock()) { - // this could be a reconnection after a transient disconnection - mDeviceBroker.cancelA2dpDockTimeout(); - mDockAddress = address; - } else { - // this could be a connection of another A2DP device before the timeout of - // a dock: cancel the dock timeout, and make the dock unavailable now - if (mDeviceBroker.hasScheduledA2dpDockTimeout() && mDockAddress != null) { - mDeviceBroker.cancelA2dpDockTimeout(); - makeA2dpDeviceUnavailableNow(mDockAddress, - AudioSystem.AUDIO_FORMAT_DEFAULT); - } - } - if (a2dpVolume != -1) { - mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, - // convert index to internal representation in VolumeStreamState - a2dpVolume * 10, - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState"); - } - makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice), - "onSetA2dpSinkConnectionState", a2dpCodec); } + if (a2dpVolume != -1) { + mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC, + // convert index to internal representation in VolumeStreamState + a2dpVolume * 10, + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState"); + } + makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice), + "onSetA2dpSinkConnectionState", a2dpCodec); } } @@ -672,9 +644,6 @@ public class AudioDeviceInventory { DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address)); // Remove A2DP routes as well setCurrentAudioRouteNameIfPossible(null); - if (mDockAddress == address) { - mDockAddress = null; - } } @GuardedBy("mConnectedDevices") diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java index a91fe773a5cf..1cf27ffd1903 100644 --- a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java +++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java @@ -231,7 +231,8 @@ public class EmergencyAffordanceService extends SystemService { // a Sim with a different mcc code was found neededNow = false; } - String simOperator = mTelephonyManager.getSimOperator(info.getSubscriptionId()); + String simOperator = mTelephonyManager + .createForSubscriptionId(info.getSubscriptionId()).getSimOperator(); mcc = 0; if (simOperator != null && simOperator.length() >= 3) { mcc = Integer.parseInt(simOperator.substring(0, 3)); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java index 52cede2121bd..23b5c1411b0e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java @@ -250,7 +250,11 @@ final class HdmiCecKeycode { new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_UP), // No Android keycode defined for CEC_KEYCODE_LEFT_DOWN new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_DOWN), + // Both KEYCODE_HOME and KEYCODE_MENU keys are sent as CEC_KEYCODE_ROOT_MENU + // NOTE that the HOME key is not usually forwarded. + // When CEC_KEYCODE_ROOT_MENU is received, it is translated to KEYCODE_HOME new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU), + new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_ROOT_MENU), new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU), new KeycodeEntry(KeyEvent.KEYCODE_TV_CONTENTS_MENU, CEC_KEYCODE_CONTENTS_MENU, false), // No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java index 9b9f4de7a18f..f295ed37939c 100644 --- a/services/core/java/com/android/server/notification/NotificationComparator.java +++ b/services/core/java/com/android/server/notification/NotificationComparator.java @@ -23,7 +23,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.provider.Settings; import android.telecom.TelecomManager; import com.android.internal.util.NotificationMessagingUtil; @@ -55,14 +54,9 @@ public class NotificationComparator final boolean isLeftHighImportance = leftImportance >= IMPORTANCE_DEFAULT; final boolean isRightHighImportance = rightImportance >= IMPORTANCE_DEFAULT; - // With new interruption model, prefer importance bucket above all other criteria - // (to ensure buckets are contiguous) - if (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) == 1) { - if (isLeftHighImportance != isRightHighImportance) { - // by importance bucket, high importance higher than low importance - return -1 * Boolean.compare(isLeftHighImportance, isRightHighImportance); - } + if (isLeftHighImportance != isRightHighImportance) { + // by importance bucket, high importance higher than low importance + return -1 * Boolean.compare(isLeftHighImportance, isRightHighImportance); } // first all colorized notifications diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9791ff3e02ba..7e7822cd978e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17474,8 +17474,7 @@ public class PackageManagerService extends IPackageManager.Stub if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { try { VerityUtils.setUpFsverity(filePath, signaturePath); - } catch (IOException | DigestException | NoSuchAlgorithmException - | SecurityException e) { + } catch (IOException e) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, "Failed to enable fs-verity: " + e); } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index fff9ec7f02c5..0caf8f835752 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -50,7 +50,6 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; -import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -675,40 +674,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C dumpOutputStream.flush(); } - /** - * Get filtered SMS messages for financial app. - */ - @Override - public void getSmsMessagesForFinancialApp( - String callingPkg, Bundle params, IFinancialSmsCallback callback) { - int mode = PermissionChecker.checkCallingOrSelfPermissionForDataDelivery( - getContext(), - AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); - - if (mode == PermissionChecker.PERMISSION_GRANTED) { - FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext()); - financialSmsManager.getSmsMessages(new RemoteCallback((result) -> { - CursorWindow messages = null; - if (result == null) { - Slog.w(LOG_TAG, "result is null."); - } else { - messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS); - } - try { - callback.onGetSmsMessagesForFinancialApp(messages); - } catch (RemoteException e) { - // do nothing - } - }), params); - } else { - try { - callback.onGetSmsMessagesForFinancialApp(null); - } catch (RemoteException e) { - // do nothing - } - } - } - private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java index b1db46fb3276..856a40f3ef12 100644 --- a/services/core/java/com/android/server/security/VerityUtils.java +++ b/services/core/java/com/android/server/security/VerityUtils.java @@ -26,27 +26,19 @@ import android.util.Slog; import android.util.apk.ApkSignatureVerifier; import android.util.apk.ByteBufferFactory; import android.util.apk.SignatureNotFoundException; -import android.util.apk.VerityBuilder; import libcore.util.HexEncoding; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; -import java.io.RandomAccessFile; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestException; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import sun.security.pkcs.PKCS7; - /** Provides fsverity related operations. */ abstract public class VerityUtils { private static final String TAG = "VerityUtils"; @@ -60,8 +52,6 @@ abstract public class VerityUtils { /** The maximum size of signature file. This is just to avoid potential abuse. */ private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; - private static final int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096; - private static final boolean DEBUG = false; /** Returns true if the given file looks like containing an fs-verity signature. */ @@ -74,42 +64,15 @@ abstract public class VerityUtils { return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION; } - /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */ - public static void setUpFsverity(@NonNull String filePath, String signaturePath) - throws IOException, DigestException, NoSuchAlgorithmException { - final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath))); - final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes(); - if (DEBUG) { - Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement " - + bytesToString(expectedMeasurement)); - Slog.d(TAG, "PKCS#7 info: " + pkcs7); - } - - final TrackedBufferFactory bufferFactory = new TrackedBufferFactory(); - final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath, - bufferFactory); - try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) { - FileChannel ch = raf.getChannel(); - ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES)); - ByteBuffer buffer = bufferFactory.getBuffer(); - - long offset = buffer.position(); - long size = buffer.limit(); - while (offset < size) { - long s = ch.write(buffer); - offset += s; - size -= s; - } + /** Enables fs-verity for the file with a PKCS#7 detached signature file. */ + public static void setUpFsverity(@NonNull String filePath, @NonNull String signaturePath) + throws IOException { + if (Files.size(Paths.get(signaturePath)) > MAX_SIGNATURE_FILE_SIZE_BYTES) { + throw new SecurityException("Signature file is unexpectedly large: " + signaturePath); } - - if (!Arrays.equals(expectedMeasurement, actualMeasurement)) { - throw new SecurityException("fs-verity measurement mismatch: " - + bytesToString(actualMeasurement) + " != " - + bytesToString(expectedMeasurement)); - } - - // This can fail if the public key is not already in .fs-verity kernel keyring. - int errno = enableFsverityNative(filePath); + byte[] pkcs7Signature = Files.readAllBytes(Paths.get(signaturePath)); + // This will fail if the public key is not already in .fs-verity kernel keyring. + int errno = enableFsverityNative(filePath, pkcs7Signature); if (errno != 0) { throw new IOException("Failed to enable fs-verity on " + filePath + ": " + Os.strerror(errno)); @@ -131,12 +94,19 @@ abstract public class VerityUtils { return true; } + private static native int enableFsverityNative(@NonNull String filePath, + @NonNull byte[] pkcs7Signature); + private static native int measureFsverityNative(@NonNull String filePath); + /** * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped. * + * @deprecated This is only used for previous fs-verity implementation, and should never be used + * on new devices. * @return {@code SetupResult} that contains the result code, and when success, the * {@code FileDescriptor} to read all the data from. */ + @Deprecated public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { if (DEBUG) { Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath); @@ -173,7 +143,10 @@ abstract public class VerityUtils { /** * {@see ApkSignatureVerifier#generateApkVerityRootHash(String)}. + * @deprecated This is only used for previous fs-verity implementation, and should never be used + * on new devices. */ + @Deprecated public static byte[] generateApkVerityRootHash(@NonNull String apkPath) throws NoSuchAlgorithmException, DigestException, IOException { return ApkSignatureVerifier.generateApkVerityRootHash(apkPath); @@ -181,104 +154,16 @@ abstract public class VerityUtils { /** * {@see ApkSignatureVerifier#getVerityRootHash(String)}. + * @deprecated This is only used for previous fs-verity implementation, and should never be used + * on new devices. */ + @Deprecated public static byte[] getVerityRootHash(@NonNull String apkPath) throws IOException, SignatureNotFoundException { return ApkSignatureVerifier.getVerityRootHash(apkPath); } /** - * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code - * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and - * extensions, including a PKCS#7 signature provided in {@code signaturePath}. - * - * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code - * ByteBuffer}. The data will be used outside this method via the factory itself. - * - * @return fs-verity signed data (struct fsverity_digest_disk) of {@code filePath}, which - * includes SHA-256 of fs-verity descriptor and authenticated extensions. - */ - private static byte[] generateFsverityMetadata(String filePath, String signaturePath, - @NonNull ByteBufferFactory trackedBufferFactory) - throws IOException, DigestException, NoSuchAlgorithmException { - try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { - VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree( - file, trackedBufferFactory); - - ByteBuffer buffer = result.verityData; - buffer.position(result.merkleTreeSize); - - final byte[] measurement = generateFsverityDescriptorAndMeasurement(file, - result.rootHash, signaturePath, buffer); - buffer.flip(); - return constructFsveritySignedDataNative(measurement); - } - } - - /** - * Generates fs-verity descriptor including the extensions to the {@code output} and returns the - * fs-verity measurement. - * - * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated - * extensions. - */ - private static byte[] generateFsverityDescriptorAndMeasurement( - @NonNull RandomAccessFile file, @NonNull byte[] rootHash, - @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output) - throws IOException, NoSuchAlgorithmException, DigestException { - final short kRootHashExtensionId = 1; - final short kPkcs7SignatureExtensionId = 3; - final int origPosition = output.position(); - - // For generating fs-verity file measurement, which consists of the descriptor and - // authenticated extensions (but not unauthenticated extensions and the footer). - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - // 1. Generate fs-verity descriptor. - final byte[] desc = constructFsverityDescriptorNative(file.length()); - output.put(desc); - md.update(desc); - - // 2. Generate authenticated extensions. - final byte[] authExt = - constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length); - output.put(authExt); - output.put(rootHash); - md.update(authExt); - md.update(rootHash); - - // 3. Generate unauthenticated extensions. - ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); - output.putShort((short) 1); // number of unauthenticated extensions below - output.position(output.position() + 6); - - // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be - // done by the caller if needed). - Path path = Paths.get(pkcs7SignaturePath); - if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) { - throw new IllegalArgumentException("Signature size is unexpectedly large: " - + pkcs7SignaturePath); - } - final byte[] pkcs7Signature = Files.readAllBytes(path); - output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId, - pkcs7Signature.length)); - output.put(pkcs7Signature); - - // 4. Generate the footer. - output.put(constructFsverityFooterNative(output.position() - origPosition)); - - return md.digest(); - } - - private static native int enableFsverityNative(@NonNull String filePath); - private static native int measureFsverityNative(@NonNull String filePath); - private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement); - private static native byte[] constructFsverityDescriptorNative(long fileSize); - private static native byte[] constructFsverityExtensionNative(short extensionId, - int extensionDataSize); - private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead); - - /** * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has @@ -313,6 +198,11 @@ abstract public class VerityUtils { return HexEncoding.encodeToString(bytes); } + /** + * @deprecated This is only used for previous fs-verity implementation, and should never be used + * on new devices. + */ + @Deprecated public static class SetupResult { /** Result code if verity is set up correctly. */ private static final int RESULT_OK = 1; @@ -401,30 +291,4 @@ abstract public class VerityUtils { return mBuffer == null ? -1 : mBuffer.limit(); } } - - /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */ - private static class TrackedBufferFactory implements ByteBufferFactory { - private ByteBuffer mBuffer; - - @Override - public ByteBuffer create(int capacity) { - if (mBuffer != null) { - throw new IllegalStateException("Multiple instantiation from this factory"); - } - mBuffer = ByteBuffer.allocate(capacity); - return mBuffer; - } - - public ByteBuffer getBuffer() { - return mBuffer; - } - } - - /** Round up the number to the next multiple of the divisor. */ - private static long roundUpToNextMultiple(long number, long divisor) { - if (number > (Long.MAX_VALUE - divisor)) { - throw new IllegalArgumentException("arithmetic overflow"); - } - return ((number + (divisor - 1)) / divisor) * divisor; - } } diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java deleted file mode 100644 index 4e8ba078a73c..000000000000 --- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.timedetector; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.AlarmManager; -import android.app.timedetector.ManualTimeSuggestion; -import android.app.timedetector.PhoneTimeSuggestion; -import android.content.Intent; -import android.util.LocalLog; -import android.util.Slog; -import android.util.TimestampedValue; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.util.IndentingPrintWriter; - -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to - * {@link AlarmManager}. - * - * <p>Most public methods are marked synchronized to ensure thread safety around internal state. - */ -public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy { - - private static final boolean DBG = false; - private static final String LOG_TAG = "SimpleTimeDetectorStrategy"; - - @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL }) - @Retention(RetentionPolicy.SOURCE) - public @interface Origin {} - - /** Used when a time value originated from a telephony signal. */ - @Origin - private static final int ORIGIN_PHONE = 1; - - /** Used when a time value originated from a user / manual settings. */ - @Origin - private static final int ORIGIN_MANUAL = 2; - - /** - * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the - * actual system clock time before a warning is logged. Used to help identify situations where - * there is something other than this class setting the system clock automatically. - */ - private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000; - - // A log for changes made to the system clock and why. - @NonNull - private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */); - - // @NonNull after initialize() - private Callback mCallback; - - // Last phone suggestion. - @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion; - - // Information about the last time signal received: Used when toggling auto-time. - @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime; - private boolean mLastAutoSystemClockTimeSendNetworkBroadcast; - - // System clock state. - @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet; - - @Override - public void initialize(@NonNull Callback callback) { - mCallback = callback; - } - - @Override - public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) { - // NITZ logic - - // Empty suggestions are just ignored as we don't currently keep track of suggestion origin. - if (timeSuggestion.getUtcTime() == null) { - return; - } - - boolean timeSuggestionIsValid = - validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion); - if (!timeSuggestionIsValid) { - return; - } - // Always store the last NITZ value received, regardless of whether we go on to use it to - // update the system clock. This is so that we can validate future phone suggestions. - mLastPhoneSuggestion = timeSuggestion; - - // System clock update logic. - final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime(); - setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion); - } - - @Override - public synchronized void suggestManualTime(ManualTimeSuggestion timeSuggestion) { - final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime(); - setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion); - } - - private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion, - @Nullable PhoneTimeSuggestion lastSuggestion) { - - if (lastSuggestion != null) { - long referenceTimeDifference = TimestampedValue.referenceTimeDifference( - newSuggestion.getUtcTime(), lastSuggestion.getUtcTime()); - if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) { - // Out of order or bogus. - Slog.w(LOG_TAG, "Bad NITZ signal received." - + " referenceTimeDifference=" + referenceTimeDifference - + " lastSuggestion=" + lastSuggestion - + " newSuggestion=" + newSuggestion); - return false; - } - } - return true; - } - - @GuardedBy("this") - private void setSystemClockIfRequired( - @Origin int origin, TimestampedValue<Long> time, Object cause) { - // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only - // when setting the time using NITZ. - boolean sendNetworkBroadcast = origin == ORIGIN_PHONE; - - boolean isOriginAutomatic = isOriginAutomatic(origin); - if (isOriginAutomatic) { - // Store the last auto time candidate we've seen in all cases so we can set the system - // clock when/if time detection is off but later enabled. - mLastAutoSystemClockTime = time; - mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast; - - if (!mCallback.isAutoTimeDetectionEnabled()) { - if (DBG) { - Slog.d(LOG_TAG, "Auto time detection is not enabled." - + " origin=" + origin - + ", time=" + time - + ", cause=" + cause); - } - return; - } - } else { - if (mCallback.isAutoTimeDetectionEnabled()) { - if (DBG) { - Slog.d(LOG_TAG, "Auto time detection is enabled." - + " origin=" + origin - + ", time=" + time - + ", cause=" + cause); - } - return; - } - } - - mCallback.acquireWakeLock(); - try { - long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis(); - long actualTimeMillis = mCallback.systemClockMillis(); - - if (isOriginAutomatic) { - // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else - // may be setting the clock. - if (mLastAutoSystemClockTimeSet != null) { - long expectedTimeMillis = TimeDetectorStrategy.getTimeAt( - mLastAutoSystemClockTimeSet, elapsedRealtimeMillis); - long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis); - if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) { - Slog.w(LOG_TAG, - "System clock has not tracked elapsed real time clock. A clock may" - + " be inaccurate or something unexpectedly set the system" - + " clock." - + " elapsedRealtimeMillis=" + elapsedRealtimeMillis - + " expectedTimeMillis=" + expectedTimeMillis - + " actualTimeMillis=" + actualTimeMillis); - } - } - } - - adjustAndSetDeviceSystemClock( - time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause); - } finally { - mCallback.releaseWakeLock(); - } - } - - private static boolean isOriginAutomatic(@Origin int origin) { - return origin == ORIGIN_PHONE; - } - - @Override - public synchronized void handleAutoTimeDetectionChanged() { - // If automatic time detection is enabled we update the system clock instantly if we can. - // Conversely, if automatic time detection is disabled we leave the clock as it is. - boolean enabled = mCallback.isAutoTimeDetectionEnabled(); - if (enabled) { - if (mLastAutoSystemClockTime != null) { - // Only send the network broadcast if the last candidate would have caused one. - final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast; - - mCallback.acquireWakeLock(); - try { - long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis(); - long actualTimeMillis = mCallback.systemClockMillis(); - - final String reason = "Automatic time detection enabled."; - adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast, - elapsedRealtimeMillis, actualTimeMillis, reason); - } finally { - mCallback.releaseWakeLock(); - } - } - } else { - // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what - // it should be in future. - mLastAutoSystemClockTimeSet = null; - } - } - - @Override - public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) { - IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - ipw.println("TimeDetectorStrategy:"); - ipw.increaseIndent(); // level 1 - - ipw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion); - ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet); - ipw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime); - ipw.println("mLastAutoSystemClockTimeSendNetworkBroadcast=" - + mLastAutoSystemClockTimeSendNetworkBroadcast); - - - ipw.println("Time change log:"); - ipw.increaseIndent(); // level 2 - mTimeChangesLog.dump(ipw); - ipw.decreaseIndent(); // level 2 - - ipw.decreaseIndent(); // level 1 - ipw.flush(); - } - - @GuardedBy("this") - private void adjustAndSetDeviceSystemClock( - TimestampedValue<Long> newTime, boolean sendNetworkBroadcast, - long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) { - - // Adjust for the time that has elapsed since the signal was received. - long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis); - - // Check if the new signal would make sufficient difference to the system clock. If it's - // below the threshold then ignore it. - long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis); - long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis(); - if (absTimeDifference < systemClockUpdateThreshold) { - if (DBG) { - Slog.d(LOG_TAG, "Not setting system clock. New time and" - + " system clock are close enough." - + " elapsedRealtimeMillis=" + elapsedRealtimeMillis - + " newTime=" + newTime - + " cause=" + cause - + " systemClockUpdateThreshold=" + systemClockUpdateThreshold - + " absTimeDifference=" + absTimeDifference); - } - return; - } - - mCallback.setSystemClock(newSystemClockMillis); - String logMsg = "Set system clock using time=" + newTime - + " cause=" + cause - + " elapsedRealtimeMillis=" + elapsedRealtimeMillis - + " newSystemClockMillis=" + newSystemClockMillis; - if (DBG) { - Slog.d(LOG_TAG, logMsg); - } - mTimeChangesLog.log(logMsg); - - // CLOCK_PARANOIA : Record the last time this class set the system clock. - mLastAutoSystemClockTimeSet = newTime; - - if (sendNetworkBroadcast) { - // Send a broadcast that telephony code used to send after setting the clock. - // TODO Remove this broadcast as soon as there are no remaining listeners. - Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra("time", newSystemClockMillis); - mCallback.sendStickyBroadcast(intent); - } - } -} diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java index 34400ff6b484..172367a128cc 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java @@ -31,7 +31,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.server.FgThread; import com.android.server.SystemService; -import com.android.server.timedetector.TimeDetectorStrategy.Callback; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -58,17 +57,16 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { @NonNull private final Handler mHandler; @NonNull private final Context mContext; - @NonNull private final Callback mCallback; @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy; private static TimeDetectorService create(@NonNull Context context) { - TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy(); + TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl(); TimeDetectorStrategyCallbackImpl callback = new TimeDetectorStrategyCallbackImpl(context); - timeDetector.initialize(callback); + timeDetectorStrategy.initialize(callback); Handler handler = FgThread.getHandler(); TimeDetectorService timeDetectorService = - new TimeDetectorService(context, handler, callback, timeDetector); + new TimeDetectorService(context, handler, timeDetectorStrategy); // Wire up event listening. ContentResolver contentResolver = context.getContentResolver(); @@ -85,10 +83,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { @VisibleForTesting public TimeDetectorService(@NonNull Context context, @NonNull Handler handler, - @NonNull Callback callback, @NonNull TimeDetectorStrategy timeDetectorStrategy) { + @NonNull TimeDetectorStrategy timeDetectorStrategy) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); - mCallback = Objects.requireNonNull(callback); mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy); } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java new file mode 100644 index 000000000000..1b1ac6d3ed07 --- /dev/null +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timedetector; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AlarmManager; +import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.PhoneTimeSuggestion; +import android.content.Intent; +import android.util.ArrayMap; +import android.util.LocalLog; +import android.util.Slog; +import android.util.TimestampedValue; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.IndentingPrintWriter; + +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.LinkedList; +import java.util.Map; + +/** + * An implementation of TimeDetectorStrategy that passes phone and manual suggestions to + * {@link AlarmManager}. When there are multiple phone sources, the one with the lowest ID is used + * unless the data becomes too stale. + * + * <p>Most public methods are marked synchronized to ensure thread safety around internal state. + */ +public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { + + private static final boolean DBG = false; + private static final String LOG_TAG = "SimpleTimeDetectorStrategy"; + + /** A score value used to indicate "no score", either due to validation failure or age. */ + private static final int PHONE_INVALID_SCORE = -1; + /** The number of buckets phone suggestions can be put in by age. */ + private static final int PHONE_BUCKET_COUNT = 24; + /** Each bucket is this size. All buckets are equally sized. */ + @VisibleForTesting + static final int PHONE_BUCKET_SIZE_MILLIS = 60 * 60 * 1000; + /** Phone suggestions older than this value are considered too old. */ + @VisibleForTesting + static final long PHONE_MAX_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS; + + @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL }) + @Retention(RetentionPolicy.SOURCE) + public @interface Origin {} + + /** Used when a time value originated from a telephony signal. */ + @Origin + private static final int ORIGIN_PHONE = 1; + + /** Used when a time value originated from a user / manual settings. */ + @Origin + private static final int ORIGIN_MANUAL = 2; + + /** + * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the + * actual system clock time before a warning is logged. Used to help identify situations where + * there is something other than this class setting the system clock. + */ + private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000; + + /** The number of previous phone suggestions to keep for each ID (for use during debugging). */ + private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30; + + // A log for changes made to the system clock and why. + @NonNull + private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */); + + // @NonNull after initialize() + private Callback mCallback; + + // Used to store the last time the system clock state was set automatically. It is used to + // detect (and log) issues with the realtime clock or whether the clock is being set without + // going through this strategy code. + @GuardedBy("this") + @Nullable + private TimestampedValue<Long> mLastAutoSystemClockTimeSet; + + /** + * A mapping from phoneId to a linked list of time suggestions (the "first" being the latest). + * We typically expect one or two entries in this Map: devices will have a small number + * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with + * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size. + */ + @GuardedBy("this") + private ArrayMap<Integer, LinkedList<PhoneTimeSuggestion>> mSuggestionByPhoneId = + new ArrayMap<>(); + + @Override + public void initialize(@NonNull Callback callback) { + mCallback = callback; + } + + @Override + public synchronized void suggestManualTime(@NonNull ManualTimeSuggestion suggestion) { + final TimestampedValue<Long> newUtcTime = suggestion.getUtcTime(); + + if (!validateSuggestionTime(newUtcTime, suggestion)) { + return; + } + + String cause = "Manual time suggestion received: suggestion=" + suggestion; + setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, cause); + } + + @Override + public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) { + // Empty time suggestion means that telephony network connectivity has been lost. + // The passage of time is relentless, and we don't expect our users to use a time machine, + // so we can continue relying on previous suggestions when we lose connectivity. This is + // unlike time zone, where a user may lose connectivity when boarding a flight and where we + // do want to "forget" old signals. Suggestions that are too old are discarded later in the + // detection algorithm. + if (timeSuggestion.getUtcTime() == null) { + return; + } + + // Perform validation / input filtering and record the validated suggestion against the + // phoneId. + if (!validateAndStorePhoneSuggestion(timeSuggestion)) { + return; + } + + // Now perform auto time detection. The new suggestion may be used to modify the system + // clock. + String reason = "New phone time suggested. timeSuggestion=" + timeSuggestion; + doAutoTimeDetection(reason); + } + + @Override + public synchronized void handleAutoTimeDetectionChanged() { + boolean enabled = mCallback.isAutoTimeDetectionEnabled(); + // When automatic time detection is enabled we update the system clock instantly if we can. + // Conversely, when automatic time detection is disabled we leave the clock as it is. + if (enabled) { + String reason = "Auto time zone detection setting enabled."; + doAutoTimeDetection(reason); + } else { + // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what + // it should be in future. + mLastAutoSystemClockTimeSet = null; + } + } + + @Override + public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) { + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + ipw.println("TimeDetectorStrategy:"); + ipw.increaseIndent(); // level 1 + + ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet); + + ipw.println("Time change log:"); + ipw.increaseIndent(); // level 2 + mTimeChangesLog.dump(ipw); + ipw.decreaseIndent(); // level 2 + + ipw.println("Phone suggestion history:"); + ipw.increaseIndent(); // level 2 + for (Map.Entry<Integer, LinkedList<PhoneTimeSuggestion>> entry + : mSuggestionByPhoneId.entrySet()) { + ipw.println("Phone " + entry.getKey()); + + ipw.increaseIndent(); // level 3 + for (PhoneTimeSuggestion suggestion : entry.getValue()) { + ipw.println(suggestion); + } + ipw.decreaseIndent(); // level 3 + } + ipw.decreaseIndent(); // level 2 + + ipw.decreaseIndent(); // level 1 + ipw.flush(); + } + + @GuardedBy("this") + private boolean validateAndStorePhoneSuggestion(@NonNull PhoneTimeSuggestion suggestion) { + TimestampedValue<Long> newUtcTime = suggestion.getUtcTime(); + if (!validateSuggestionTime(newUtcTime, suggestion)) { + // There's probably nothing useful we can do: elsewhere we assume that reference + // times are in the past so just stop here. + return false; + } + + int phoneId = suggestion.getPhoneId(); + LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.get(phoneId); + if (phoneSuggestions == null) { + // The first time we've seen this phoneId. + phoneSuggestions = new LinkedList<>(); + mSuggestionByPhoneId.put(phoneId, phoneSuggestions); + } else if (phoneSuggestions.isEmpty()) { + Slog.w(LOG_TAG, "Suggestions unexpectedly empty when adding suggestion=" + suggestion); + } + + if (!phoneSuggestions.isEmpty()) { + // We can log / discard suggestions with obvious issues with the reference time clock. + PhoneTimeSuggestion previousSuggestion = phoneSuggestions.getFirst(); + if (previousSuggestion == null + || previousSuggestion.getUtcTime() == null + || previousSuggestion.getUtcTime().getValue() == null) { + // This should be impossible given we only store validated suggestions. + Slog.w(LOG_TAG, "Previous suggestion is null or has a null time." + + " previousSuggestion=" + previousSuggestion + + ", suggestion=" + suggestion); + return false; + } + + long referenceTimeDifference = TimestampedValue.referenceTimeDifference( + newUtcTime, previousSuggestion.getUtcTime()); + if (referenceTimeDifference < 0) { + // The reference time is before the previously received suggestion. Ignore it. + Slog.w(LOG_TAG, "Out of order phone suggestion received." + + " referenceTimeDifference=" + referenceTimeDifference + + " previousSuggestion=" + previousSuggestion + + " suggestion=" + suggestion); + return false; + } + } + + // Store the latest suggestion. + phoneSuggestions.addFirst(suggestion); + if (phoneSuggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) { + phoneSuggestions.removeLast(); + } + return true; + } + + private boolean validateSuggestionTime( + @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) { + if (newUtcTime.getValue() == null) { + Slog.w(LOG_TAG, "Suggested time value is null. suggestion=" + suggestion); + return false; + } + + // We can validate the suggestion against the reference time clock. + long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis(); + if (elapsedRealtimeMillis < newUtcTime.getReferenceTimeMillis()) { + // elapsedRealtime clock went backwards? + Slog.w(LOG_TAG, "New reference time is in the future? Ignoring." + + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + ", suggestion=" + suggestion); + return false; + } + return true; + } + + @GuardedBy("this") + private void doAutoTimeDetection(@NonNull String detectionReason) { + if (!mCallback.isAutoTimeDetectionEnabled()) { + // Avoid doing unnecessary work with this (race-prone) check. + return; + } + + PhoneTimeSuggestion bestPhoneSuggestion = findBestPhoneSuggestion(); + + // Work out what to do with the best suggestion. + if (bestPhoneSuggestion == null) { + // There is no good phone suggestion. + if (DBG) { + Slog.d(LOG_TAG, "Could not determine time: No best phone suggestion." + + " detectionReason=" + detectionReason); + } + return; + } + + final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime(); + String cause = "Found good suggestion." + + ", bestPhoneSuggestion=" + bestPhoneSuggestion + + ", detectionReason=" + detectionReason; + setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause); + } + + @GuardedBy("this") + @Nullable + private PhoneTimeSuggestion findBestPhoneSuggestion() { + long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis(); + + // Phone time suggestions are assumed to be derived from NITZ or NITZ-like signals. These + // have a number of limitations: + // 1) No guarantee of accuracy ("accuracy of the time information is in the order of + // minutes") [1] + // 2) No guarantee of regular signals ("dependent on the handset crossing radio network + // boundaries") [1] + // + // [1] https://en.wikipedia.org/wiki/NITZ + // + // Generally, when there are suggestions from multiple phoneIds they should usually + // approximately agree. In cases where signals *are* inaccurate we don't want to vacillate + // between signals from two phoneIds. However, it is known for NITZ signals to be incorrect + // occasionally, which means we also don't want to stick forever with one phoneId. Without + // cross-referencing across sources (e.g. the current device time, NTP), or doing some kind + // of statistical analysis of consistency within and across phoneIds, we can't know which + // suggestions are more correct. + // + // For simplicity, we try to value recency, then consistency of phoneId. + // + // The heuristic works as follows: + // Recency: The most recent suggestion from each phone is scored. The score is based on a + // discrete age bucket, i.e. so signals received around the same time will be in the same + // bucket, thus applying a loose reference time ordering. The suggestion with the highest + // score is used. + // Consistency: If there a multiple suggestions with the same score, the suggestion with the + // lowest phoneId is always taken. + // + // In the trivial case with a single ID this will just mean that the latest received + // suggestion is used. + + PhoneTimeSuggestion bestSuggestion = null; + int bestScore = PHONE_INVALID_SCORE; + for (int i = 0; i < mSuggestionByPhoneId.size(); i++) { + Integer phoneId = mSuggestionByPhoneId.keyAt(i); + LinkedList<PhoneTimeSuggestion> phoneSuggestions = mSuggestionByPhoneId.valueAt(i); + if (phoneSuggestions == null) { + // Unexpected - map is missing a value. + Slog.w(LOG_TAG, "Suggestions unexpectedly missing for phoneId." + + " phoneId=" + phoneId); + continue; + } + + PhoneTimeSuggestion candidateSuggestion = phoneSuggestions.getFirst(); + if (candidateSuggestion == null) { + // Unexpected - null suggestions should never be stored. + Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for phoneId." + + " phoneId=" + phoneId); + continue; + } else if (candidateSuggestion.getUtcTime() == null) { + // Unexpected - we do not store empty suggestions. + Slog.w(LOG_TAG, "Latest suggestion unexpectedly empty. " + + " candidateSuggestion=" + candidateSuggestion); + continue; + } + + int candidateScore = scorePhoneSuggestion(elapsedRealtimeMillis, candidateSuggestion); + if (candidateScore == PHONE_INVALID_SCORE) { + // Expected: This means the suggestion is obviously invalid or just too old. + continue; + } + + // Higher scores are better. + if (bestSuggestion == null || bestScore < candidateScore) { + bestSuggestion = candidateSuggestion; + bestScore = candidateScore; + } else if (bestScore == candidateScore) { + // Tie! Use the suggestion with the lowest phoneId. + int candidatePhoneId = candidateSuggestion.getPhoneId(); + int bestPhoneId = bestSuggestion.getPhoneId(); + if (candidatePhoneId < bestPhoneId) { + bestSuggestion = candidateSuggestion; + } + } + } + return bestSuggestion; + } + + private static int scorePhoneSuggestion( + long elapsedRealtimeMillis, @NonNull PhoneTimeSuggestion timeSuggestion) { + // The score is based on the age since receipt. Suggestions are bucketed so two + // suggestions in the same bucket from different phoneIds are scored the same. + TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime(); + long referenceTimeMillis = utcTime.getReferenceTimeMillis(); + if (referenceTimeMillis > elapsedRealtimeMillis) { + // Future times are ignored. They imply the reference time was wrong, or the elapsed + // realtime clock has gone backwards, neither of which are supportable situations. + Slog.w(LOG_TAG, "Existing suggestion found to be in the future. " + + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + ", timeSuggestion=" + timeSuggestion); + return PHONE_INVALID_SCORE; + } + + long ageMillis = elapsedRealtimeMillis - referenceTimeMillis; + + // Any suggestion > MAX_AGE_MILLIS is treated as too old. Although time is relentless and + // predictable, the accuracy of the reference time clock may be poor over long periods which + // would lead to errors creeping in. Also, in edge cases where a bad suggestion has been + // made and never replaced, it could also mean that the time detection code remains + // opinionated using a bad invalid suggestion. This caps that edge case at MAX_AGE_MILLIS. + if (ageMillis > PHONE_MAX_AGE_MILLIS) { + return PHONE_INVALID_SCORE; + } + + // Turn the age into a discrete value: 0 <= bucketIndex < MAX_AGE_HOURS. + int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS); + + // We want the lowest bucket index to have the highest score. 0 > score >= BUCKET_COUNT. + return PHONE_BUCKET_COUNT - bucketIndex; + } + + @GuardedBy("this") + private void setSystemClockIfRequired( + @Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) { + + boolean isOriginAutomatic = isOriginAutomatic(origin); + if (isOriginAutomatic) { + if (!mCallback.isAutoTimeDetectionEnabled()) { + if (DBG) { + Slog.d(LOG_TAG, "Auto time detection is not enabled." + + " origin=" + origin + + ", time=" + time + + ", cause=" + cause); + } + return; + } + } else { + if (mCallback.isAutoTimeDetectionEnabled()) { + if (DBG) { + Slog.d(LOG_TAG, "Auto time detection is enabled." + + " origin=" + origin + + ", time=" + time + + ", cause=" + cause); + } + return; + } + } + + mCallback.acquireWakeLock(); + try { + setSystemClockUnderWakeLock(origin, time, cause); + } finally { + mCallback.releaseWakeLock(); + } + } + + private static boolean isOriginAutomatic(@Origin int origin) { + return origin == ORIGIN_PHONE; + } + + @GuardedBy("this") + private void setSystemClockUnderWakeLock( + int origin, @NonNull TimestampedValue<Long> newTime, @NonNull Object cause) { + + long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis(); + boolean isOriginAutomatic = isOriginAutomatic(origin); + long actualSystemClockMillis = mCallback.systemClockMillis(); + if (isOriginAutomatic) { + // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else + // may be setting the clock. + if (mLastAutoSystemClockTimeSet != null) { + long expectedTimeMillis = TimeDetectorStrategy.getTimeAt( + mLastAutoSystemClockTimeSet, elapsedRealtimeMillis); + long absSystemClockDifference = + Math.abs(expectedTimeMillis - actualSystemClockMillis); + if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) { + Slog.w(LOG_TAG, + "System clock has not tracked elapsed real time clock. A clock may" + + " be inaccurate or something unexpectedly set the system" + + " clock." + + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + " expectedTimeMillis=" + expectedTimeMillis + + " actualTimeMillis=" + actualSystemClockMillis + + " cause=" + cause); + } + } + } + + // Adjust for the time that has elapsed since the signal was received. + long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis); + + // Check if the new signal would make sufficient difference to the system clock. If it's + // below the threshold then ignore it. + long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis); + long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis(); + if (absTimeDifference < systemClockUpdateThreshold) { + if (DBG) { + Slog.d(LOG_TAG, "Not setting system clock. New time and" + + " system clock are close enough." + + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + " newTime=" + newTime + + " cause=" + cause + + " systemClockUpdateThreshold=" + systemClockUpdateThreshold + + " absTimeDifference=" + absTimeDifference); + } + return; + } + + mCallback.setSystemClock(newSystemClockMillis); + String logMsg = "Set system clock using time=" + newTime + + " cause=" + cause + + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + " newSystemClockMillis=" + newSystemClockMillis; + if (DBG) { + Slog.d(LOG_TAG, logMsg); + } + mTimeChangesLog.log(logMsg); + + // CLOCK_PARANOIA : Record the last time this class set the system clock due to an auto-time + // signal, or clear the record it is being done manually. + if (isOriginAutomatic(origin)) { + mLastAutoSystemClockTimeSet = newTime; + } else { + mLastAutoSystemClockTimeSet = null; + } + + // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only + // when setting the time using NITZ. + if (origin == ORIGIN_PHONE) { + // Send a broadcast that telephony code used to send after setting the clock. + // TODO Remove this broadcast as soon as there are no remaining listeners. + Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra("time", newSystemClockMillis); + mCallback.sendStickyBroadcast(intent); + } + } + + /** + * Returns the current best phone suggestion. Not intended for general use: it is used during + * tests to check strategy behavior. + */ + @VisibleForTesting + @Nullable + public synchronized PhoneTimeSuggestion findBestPhoneSuggestionForTests() { + return findBestPhoneSuggestion(); + } + + /** + * A method used to inspect state during tests. Not intended for general use. + */ + @VisibleForTesting + @Nullable + public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) { + LinkedList<PhoneTimeSuggestion> suggestions = mSuggestionByPhoneId.get(phoneId); + if (suggestions == null) { + return null; + } + return suggestions.getFirst(); + } +} diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 8e66b149d344..18ed51a6cd5e 100644..100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -2943,6 +2943,16 @@ public final class TvInputManagerService extends SystemService { if (state != null) { setStateLocked(inputId, state, mCurrentUserId); } + UserState userState = getOrCreateUserStateLocked(mCurrentUserId); + // Broadcast the event to all hardware inputs. + for (ServiceState serviceState : userState.serviceStateMap.values()) { + if (!serviceState.isHardware || serviceState.service == null) continue; + try { + serviceState.service.notifyHdmiDeviceUpdated(deviceInfo); + } catch (RemoteException e) { + Slog.e(TAG, "error in notifyHdmiDeviceUpdated", e); + } + } } } } diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp index 6cd9f2c718ee..9ceb7706628a 100644 --- a/services/core/jni/com_android_server_security_VerityUtils.cpp +++ b/services/core/jni/com_android_server_security_VerityUtils.cpp @@ -36,61 +36,33 @@ #include <linux/fsverity.h> #else -// Before fs-verity is upstreamed, use the current snapshot for development. -// https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/tree/include/uapi/linux/fsverity.h?h=fsverity - #include <linux/limits.h> #include <linux/ioctl.h> #include <linux/types.h> +#define FS_VERITY_HASH_ALG_SHA256 1 + +struct fsverity_enable_arg { + __u32 version; + __u32 hash_algorithm; + __u32 block_size; + __u32 salt_size; + __u64 salt_ptr; + __u32 sig_size; + __u32 __reserved1; + __u64 sig_ptr; + __u64 __reserved2[11]; +}; + struct fsverity_digest { __u16 digest_algorithm; __u16 digest_size; /* input/output */ __u8 digest[]; }; -#define FS_IOC_ENABLE_VERITY _IO('f', 133) +#define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) #define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest) -#define FS_VERITY_MAGIC "FSVerity" - -#define FS_VERITY_ALG_SHA256 1 - -struct fsverity_descriptor { - __u8 magic[8]; /* must be FS_VERITY_MAGIC */ - __u8 major_version; /* must be 1 */ - __u8 minor_version; /* must be 0 */ - __u8 log_data_blocksize;/* log2(data-bytes-per-hash), e.g. 12 for 4KB */ - __u8 log_tree_blocksize;/* log2(tree-bytes-per-hash), e.g. 12 for 4KB */ - __le16 data_algorithm; /* hash algorithm for data blocks */ - __le16 tree_algorithm; /* hash algorithm for tree blocks */ - __le32 flags; /* flags */ - __le32 __reserved1; /* must be 0 */ - __le64 orig_file_size; /* size of the original file data */ - __le16 auth_ext_count; /* number of authenticated extensions */ - __u8 __reserved2[30]; /* must be 0 */ -}; - -#define FS_VERITY_EXT_ROOT_HASH 1 -#define FS_VERITY_EXT_PKCS7_SIGNATURE 3 - -struct fsverity_extension { - __le32 length; - __le16 type; /* Type of this extension (see codes above) */ - __le16 __reserved; /* Reserved, must be 0 */ -}; - -struct fsverity_digest_disk { - __le16 digest_algorithm; - __le16 digest_size; - __u8 digest[]; -}; - -struct fsverity_footer { - __le32 desc_reverse_offset; /* distance to fsverity_descriptor */ - __u8 magic[8]; /* FS_VERITY_MAGIC */ -} __packed; - #endif const int kSha256Bytes = 32; @@ -99,52 +71,24 @@ namespace android { namespace { -class JavaByteArrayHolder { - public: - JavaByteArrayHolder(const JavaByteArrayHolder &other) = delete; - JavaByteArrayHolder(JavaByteArrayHolder &&other) - : mEnv(other.mEnv), mBytes(other.mBytes), mElements(other.mElements) { - other.mElements = nullptr; - } - - static JavaByteArrayHolder newArray(JNIEnv* env, jsize size) { - return JavaByteArrayHolder(env, size); - } - - jbyte* getRaw() { - return mElements; - } - - jbyteArray release() { - mEnv->ReleaseByteArrayElements(mBytes, mElements, 0); - mElements = nullptr; - return mBytes; - } - - ~JavaByteArrayHolder() { - LOG_ALWAYS_FATAL_IF(mElements != nullptr, "Elements are not released"); - } - - private: - JavaByteArrayHolder(JNIEnv* env, jsize size) { - mEnv = env; - mBytes = mEnv->NewByteArray(size); - mElements = mEnv->GetByteArrayElements(mBytes, nullptr); - memset(mElements, 0, size); - } - - JNIEnv* mEnv; - jbyteArray mBytes; - jbyte* mElements; -}; - -int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { +int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath, jbyteArray signature) { const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); + env->ReleaseStringUTFChars(filePath, path); if (rfd.get() < 0) { return errno; } - if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) { + + fsverity_enable_arg arg = {}; + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + arg.salt_size = 0; + arg.salt_ptr = reinterpret_cast<uintptr_t>(nullptr); + arg.sig_size = env->GetArrayLength(signature); + arg.sig_ptr = reinterpret_cast<uintptr_t>(signature); + + if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, &arg) < 0) { return errno; } return 0; @@ -159,6 +103,7 @@ int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); + env->ReleaseStringUTFChars(filePath, path); if (rfd.get() < 0) { return errno; } @@ -168,71 +113,9 @@ int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { return 0; } -jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) { - auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes); - fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii.getRaw()); - - data->digest_algorithm = FS_VERITY_ALG_SHA256; - data->digest_size = kSha256Bytes; - if (env->GetArrayLength(digest) != kSha256Bytes) { - jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid hash size of %d", - env->GetArrayLength(digest)); - return 0; - } - const jbyte* src = env->GetByteArrayElements(digest, nullptr); - memcpy(data->digest, src, kSha256Bytes); - - return raii.release(); -} - - -jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { - auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); - fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii.getRaw()); - - memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic)); - desc->major_version = 1; - desc->minor_version = 0; - desc->log_data_blocksize = 12; - desc->log_tree_blocksize = 12; - desc->data_algorithm = FS_VERITY_ALG_SHA256; - desc->tree_algorithm = FS_VERITY_ALG_SHA256; - desc->flags = 0; - desc->orig_file_size = fileSize; - desc->auth_ext_count = 1; - - return raii.release(); -} - -jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, - jint extensionDataSize) { - auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); - fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii.getRaw()); - - ext->length = sizeof(fsverity_extension) + extensionDataSize; - ext->type = extensionId; - - return raii.release(); -} - -jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, - jint offsetToDescriptorHead) { - auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); - fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii.getRaw()); - - footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer); - memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); - - return raii.release(); -} - const JNINativeMethod sMethods[] = { - { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity }, + { "enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity }, { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity }, - { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData }, - { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, - { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension }, - { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter }, }; } // namespace diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp index 16c9c1bfcdaa..e4f54644df46 100644 --- a/services/coverage/Android.bp +++ b/services/coverage/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.coverage-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.coverage", - srcs: ["java/**/*.java"], + srcs: [":services.coverage-sources"], libs: ["jacocoagent"], } diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp index dbe0d811dbb6..2f6592bd33b0 100644 --- a/services/devicepolicy/Android.bp +++ b/services/devicepolicy/Android.bp @@ -1,6 +1,13 @@ +filegroup { + name: "services.devicepolicy-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.devicepolicy", - srcs: ["java/**/*.java"], + srcs: [":services.devicepolicy-sources"], libs: [ "services.core", diff --git a/services/midi/Android.bp b/services/midi/Android.bp index 3745e89e8034..20e00834d0ad 100644 --- a/services/midi/Android.bp +++ b/services/midi/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.midi-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.midi", - srcs: ["java/**/*.java"], + srcs: [":services.midi-sources"], libs: ["services.core"], } diff --git a/services/net/Android.bp b/services/net/Android.bp index 2dabdb7d47de..3babb0b0a133 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -1,8 +1,15 @@ +filegroup { + name: "services.net-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.net", srcs: [ ":net-module-utils-srcs", - "java/**/*.java", + ":services.net-sources", ":tethering-manager", ], static_libs: [ @@ -23,4 +30,5 @@ filegroup { "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", ], + visibility: ["//frameworks/base/packages/Tethering"], } diff --git a/services/print/Android.bp b/services/print/Android.bp index 80a8c7560de6..aad24d72345b 100644 --- a/services/print/Android.bp +++ b/services/print/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.print-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.print", - srcs: ["java/**/*.java"], + srcs: [":services.print-sources"], libs: ["services.core"], } diff --git a/services/restrictions/Android.bp b/services/restrictions/Android.bp index 979e891ada5f..805858f7f654 100644 --- a/services/restrictions/Android.bp +++ b/services/restrictions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.restrictions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.restrictions", - srcs: ["java/**/*.java"], + srcs: [":services.restrictions-sources"], libs: ["services.core"], } diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp index 4e190b639b2c..1ce3e665c665 100644 --- a/services/systemcaptions/Android.bp +++ b/services/systemcaptions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.systemcaptions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.systemcaptions", - srcs: ["java/**/*.java"], + srcs: [":services.systemcaptions-sources"], libs: ["services.core"], } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java deleted file mode 100644 index 7a0a28dfbd16..000000000000 --- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.timedetector; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.app.timedetector.ManualTimeSuggestion; -import android.app.timedetector.PhoneTimeSuggestion; -import android.content.Intent; -import android.icu.util.Calendar; -import android.icu.util.GregorianCalendar; -import android.icu.util.TimeZone; -import android.util.TimestampedValue; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.time.Duration; - -@RunWith(AndroidJUnit4.class) -public class SimpleTimeDetectorStrategyTest { - - private static final Scenario SCENARIO_1 = new Scenario.Builder() - .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0) - .setInitialDeviceRealtimeMillis(123456789L) - .setActualTimeUtc(2018, 1, 1, 12, 0, 0) - .build(); - - private static final int ARBITRARY_PHONE_ID = 123456; - - private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis(); - - private Script mScript; - - @Before - public void setUp() { - mScript = new Script(); - } - - @Test - public void testSuggestPhoneTime_autoTimeEnabled() { - Scenario scenario = SCENARIO_1; - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(true); - - PhoneTimeSuggestion timeSuggestion = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - final int clockIncrement = 1000; - long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement; - - mScript.simulateTimePassing(clockIncrement) - .simulatePhoneTimeSuggestion(timeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectSystemClockMillis, true /* expectNetworkBroadcast */); - } - - @Test - public void testSuggestPhoneTime_emptySuggestionIgnored() { - Scenario scenario = SCENARIO_1; - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(true); - - PhoneTimeSuggestion timeSuggestion = createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, null); - - mScript.simulatePhoneTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - @Test - public void testSuggestPhoneTime_systemClockThreshold() { - Scenario scenario = SCENARIO_1; - final int systemClockUpdateThresholdMillis = 1000; - mScript.pokeFakeClocks(scenario) - .pokeThresholds(systemClockUpdateThresholdMillis) - .pokeTimeDetectionEnabled(true); - - PhoneTimeSuggestion timeSuggestion1 = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); - - final int clockIncrement = 100; - // Increment the the device clocks to simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - - long expectSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); - - // Send the first time signal. It should be used. - mScript.simulatePhoneTimeSuggestion(timeSuggestion1) - .verifySystemClockWasSetAndResetCallTracking( - expectSystemClockMillis1, true /* expectNetworkBroadcast */); - - // Now send another time signal, but one that is too similar to the last one and should be - // ignored. - int underThresholdMillis = systemClockUpdateThresholdMillis - 1; - TimestampedValue<Long> utcTime2 = new TimestampedValue<>( - mScript.peekElapsedRealtimeMillis(), - mScript.peekSystemClockMillis() + underThresholdMillis); - PhoneTimeSuggestion timeSuggestion2 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2); - mScript.simulateTimePassing(clockIncrement) - .simulatePhoneTimeSuggestion(timeSuggestion2) - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Now send another time signal, but one that is on the threshold and so should be used. - TimestampedValue<Long> utcTime3 = new TimestampedValue<>( - mScript.peekElapsedRealtimeMillis(), - mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis); - - PhoneTimeSuggestion timeSuggestion3 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3); - mScript.simulateTimePassing(clockIncrement); - - long expectSystemClockMillis3 = - TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis()); - - mScript.simulatePhoneTimeSuggestion(timeSuggestion3) - .verifySystemClockWasSetAndResetCallTracking( - expectSystemClockMillis3, true /* expectNetworkBroadcast */); - } - - @Test - public void testSuggestPhoneTime_autoTimeDisabled() { - Scenario scenario = SCENARIO_1; - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(false); - - PhoneTimeSuggestion timeSuggestion = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - mScript.simulatePhoneTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - @Test - public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() { - Scenario scenario = SCENARIO_1; - final int systemClockUpdateThreshold = 2000; - mScript.pokeFakeClocks(scenario) - .pokeThresholds(systemClockUpdateThreshold) - .pokeTimeDetectionEnabled(true); - PhoneTimeSuggestion timeSuggestion1 = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); - - // Initialize the strategy / device with a time set from NITZ. - mScript.simulateTimePassing(100); - long expectedSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); - mScript.simulatePhoneTimeSuggestion(timeSuggestion1) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis1, true /* expectNetworkBroadcast */); - - // The UTC time increment should be larger than the system clock update threshold so we - // know it shouldn't be ignored for other reasons. - long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold); - - // Now supply a new signal that has an obviously bogus reference time : older than the last - // one. - long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1; - TimestampedValue<Long> utcTime2 = new TimestampedValue<>( - referenceTimeBeforeLastSignalMillis, validUtcTimeMillis); - PhoneTimeSuggestion timeSuggestion2 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2); - mScript.simulatePhoneTimeSuggestion(timeSuggestion2) - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Now supply a new signal that has an obviously bogus reference time : substantially in the - // future. - long referenceTimeInFutureMillis = - utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1; - TimestampedValue<Long> utcTime3 = new TimestampedValue<>( - referenceTimeInFutureMillis, validUtcTimeMillis); - PhoneTimeSuggestion timeSuggestion3 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3); - mScript.simulatePhoneTimeSuggestion(timeSuggestion3) - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Just to prove validUtcTimeMillis is valid. - long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100; - TimestampedValue<Long> utcTime4 = new TimestampedValue<>( - validReferenceTimeMillis, validUtcTimeMillis); - long expectedSystemClockMillis4 = - TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis()); - PhoneTimeSuggestion timeSuggestion4 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4); - mScript.simulatePhoneTimeSuggestion(timeSuggestion4) - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis4, true /* expectNetworkBroadcast */); - } - - @Test - public void testSuggestPhoneTime_timeDetectionToggled() { - Scenario scenario = SCENARIO_1; - final int clockIncrementMillis = 100; - final int systemClockUpdateThreshold = 2000; - mScript.pokeFakeClocks(scenario) - .pokeThresholds(systemClockUpdateThreshold) - .pokeTimeDetectionEnabled(false); - - PhoneTimeSuggestion timeSuggestion1 = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); - - // Simulate time passing. - mScript.simulateTimePassing(clockIncrementMillis); - - // Simulate the time signal being received. It should not be used because auto time - // detection is off but it should be recorded. - mScript.simulatePhoneTimeSuggestion(timeSuggestion1) - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Simulate more time passing. - mScript.simulateTimePassing(clockIncrementMillis); - - long expectedSystemClockMillis1 = - TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); - - // Turn on auto time detection. - mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis1, true /* expectNetworkBroadcast */); - - // Turn off auto time detection. - mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Receive another valid time signal. - // It should be on the threshold and accounting for the clock increments. - TimestampedValue<Long> utcTime2 = new TimestampedValue<>( - mScript.peekElapsedRealtimeMillis(), - mScript.peekSystemClockMillis() + systemClockUpdateThreshold); - PhoneTimeSuggestion timeSuggestion2 = - createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2); - - // Simulate more time passing. - mScript.simulateTimePassing(clockIncrementMillis); - - long expectedSystemClockMillis2 = - TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis()); - - // The new time, though valid, should not be set in the system clock because auto time is - // disabled. - mScript.simulatePhoneTimeSuggestion(timeSuggestion2) - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Turn on auto time detection. - mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasSetAndResetCallTracking( - expectedSystemClockMillis2, true /* expectNetworkBroadcast */); - } - - @Test - public void testSuggestManualTime_autoTimeDisabled() { - Scenario scenario = SCENARIO_1; - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(false); - - ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual(); - final int clockIncrement = 1000; - long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement; - - mScript.simulateTimePassing(clockIncrement) - .simulateManualTimeSuggestion(timeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectSystemClockMillis, false /* expectNetworkBroadcast */); - } - - @Test - public void testSuggestManualTime_retainsAutoSignal() { - Scenario scenario = SCENARIO_1; - - // Configure the start state. - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(true); - - // Simulate a phone suggestion. - PhoneTimeSuggestion phoneTimeSuggestion = - scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID); - long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue(); - final int clockIncrement = 1000; - - // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; - - mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedAutoClockMillis, true /* expectNetworkBroadcast */); - - // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; - - // Switch to manual. - mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasNotSetAndResetCallTracking(); - - // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; - - - // Simulate a manual suggestion 1 day different from the auto suggestion. - long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS; - long expectedManualClockMillis = manualTimeMillis; - ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis); - mScript.simulateManualTimeSuggestion(manualTimeSuggestion) - .verifySystemClockWasSetAndResetCallTracking( - expectedManualClockMillis, false /* expectNetworkBroadcast */); - - // Simulate the passage of time. - mScript.simulateTimePassing(clockIncrement); - expectedAutoClockMillis += clockIncrement; - - // Switch back to auto. - mScript.simulateAutoTimeDetectionToggle(); - - mScript.verifySystemClockWasSetAndResetCallTracking( - expectedAutoClockMillis, true /* expectNetworkBroadcast */); - - // Switch back to manual - nothing should happen to the clock. - mScript.simulateAutoTimeDetectionToggle() - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - /** - * Manual suggestions should be ignored if auto time is enabled. - */ - @Test - public void testSuggestManualTime_autoTimeEnabled() { - Scenario scenario = SCENARIO_1; - mScript.pokeFakeClocks(scenario) - .pokeTimeDetectionEnabled(true); - - ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual(); - final int clockIncrement = 1000; - - mScript.simulateTimePassing(clockIncrement) - .simulateManualTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - /** - * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving - * like the real thing should, it also asserts preconditions. - */ - private static class FakeCallback implements TimeDetectorStrategy.Callback { - private boolean mTimeDetectionEnabled; - private boolean mWakeLockAcquired; - private long mElapsedRealtimeMillis; - private long mSystemClockMillis; - private int mSystemClockUpdateThresholdMillis = 2000; - - // Tracking operations. - private boolean mSystemClockWasSet; - private Intent mBroadcastSent; - - @Override - public int systemClockUpdateThresholdMillis() { - return mSystemClockUpdateThresholdMillis; - } - - @Override - public boolean isAutoTimeDetectionEnabled() { - return mTimeDetectionEnabled; - } - - @Override - public void acquireWakeLock() { - if (mWakeLockAcquired) { - fail("Wake lock already acquired"); - } - mWakeLockAcquired = true; - } - - @Override - public long elapsedRealtimeMillis() { - assertWakeLockAcquired(); - return mElapsedRealtimeMillis; - } - - @Override - public long systemClockMillis() { - assertWakeLockAcquired(); - return mSystemClockMillis; - } - - @Override - public void setSystemClock(long newTimeMillis) { - assertWakeLockAcquired(); - mSystemClockWasSet = true; - mSystemClockMillis = newTimeMillis; - } - - @Override - public void releaseWakeLock() { - assertWakeLockAcquired(); - mWakeLockAcquired = false; - } - - @Override - public void sendStickyBroadcast(Intent intent) { - assertNotNull(intent); - mBroadcastSent = intent; - } - - // Methods below are for managing the fake's behavior. - - public void pokeSystemClockUpdateThreshold(int thresholdMillis) { - mSystemClockUpdateThresholdMillis = thresholdMillis; - } - - public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) { - mElapsedRealtimeMillis = elapsedRealtimeMillis; - } - - public void pokeSystemClockMillis(long systemClockMillis) { - mSystemClockMillis = systemClockMillis; - } - - public void pokeAutoTimeDetectionEnabled(boolean enabled) { - mTimeDetectionEnabled = enabled; - } - - public long peekElapsedRealtimeMillis() { - return mElapsedRealtimeMillis; - } - - public long peekSystemClockMillis() { - return mSystemClockMillis; - } - - public void simulateTimePassing(int incrementMillis) { - mElapsedRealtimeMillis += incrementMillis; - mSystemClockMillis += incrementMillis; - } - - public void simulateAutoTimeZoneDetectionToggle() { - mTimeDetectionEnabled = !mTimeDetectionEnabled; - } - - public void verifySystemClockNotSet() { - assertFalse(mSystemClockWasSet); - } - - public void verifySystemClockWasSet(long expectSystemClockMillis) { - assertTrue(mSystemClockWasSet); - assertEquals(expectSystemClockMillis, mSystemClockMillis); - } - - public void verifyIntentWasBroadcast() { - assertTrue(mBroadcastSent != null); - } - - public void verifyIntentWasNotBroadcast() { - assertNull(mBroadcastSent); - } - - public void resetCallTracking() { - mSystemClockWasSet = false; - mBroadcastSent = null; - } - - private void assertWakeLockAcquired() { - assertTrue("The operation must be performed only after acquiring the wakelock", - mWakeLockAcquired); - } - } - - /** - * A fluent helper class for tests. - */ - private class Script { - - private final FakeCallback mFakeCallback; - private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy; - - Script() { - mFakeCallback = new FakeCallback(); - mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy(); - mSimpleTimeDetectorStrategy.initialize(mFakeCallback); - - } - - Script pokeTimeDetectionEnabled(boolean enabled) { - mFakeCallback.pokeAutoTimeDetectionEnabled(enabled); - return this; - } - - Script pokeFakeClocks(Scenario scenario) { - mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis()); - mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis()); - return this; - } - - Script pokeThresholds(int systemClockUpdateThreshold) { - mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold); - return this; - } - - long peekElapsedRealtimeMillis() { - return mFakeCallback.peekElapsedRealtimeMillis(); - } - - long peekSystemClockMillis() { - return mFakeCallback.peekSystemClockMillis(); - } - - Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) { - mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion); - return this; - } - - Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) { - mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion); - return this; - } - - Script simulateAutoTimeDetectionToggle() { - mFakeCallback.simulateAutoTimeZoneDetectionToggle(); - mSimpleTimeDetectorStrategy.handleAutoTimeDetectionChanged(); - return this; - } - - Script simulateTimePassing(int clockIncrement) { - mFakeCallback.simulateTimePassing(clockIncrement); - return this; - } - - Script verifySystemClockWasNotSetAndResetCallTracking() { - mFakeCallback.verifySystemClockNotSet(); - mFakeCallback.verifyIntentWasNotBroadcast(); - mFakeCallback.resetCallTracking(); - return this; - } - - Script verifySystemClockWasSetAndResetCallTracking( - long expectSystemClockMillis, boolean expectNetworkBroadcast) { - mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis); - if (expectNetworkBroadcast) { - mFakeCallback.verifyIntentWasBroadcast(); - } - mFakeCallback.resetCallTracking(); - return this; - } - } - - /** - * A starting scenario used during tests. Describes a fictional "physical" reality. - */ - private static class Scenario { - - private final long mInitialDeviceSystemClockMillis; - private final long mInitialDeviceRealtimeMillis; - private final long mActualTimeMillis; - - Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) { - mInitialDeviceSystemClockMillis = initialDeviceSystemClock; - mActualTimeMillis = timeMillis; - mInitialDeviceRealtimeMillis = elapsedRealtime; - } - - long getInitialRealTimeMillis() { - return mInitialDeviceRealtimeMillis; - } - - long getInitialSystemClockMillis() { - return mInitialDeviceSystemClockMillis; - } - - long getActualTimeMillis() { - return mActualTimeMillis; - } - - PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) { - TimestampedValue<Long> time = new TimestampedValue<>( - mInitialDeviceRealtimeMillis, mActualTimeMillis); - return createPhoneTimeSuggestion(phoneId, time); - } - - ManualTimeSuggestion createManualTimeSuggestionForActual() { - TimestampedValue<Long> time = new TimestampedValue<>( - mInitialDeviceRealtimeMillis, mActualTimeMillis); - return new ManualTimeSuggestion(time); - } - - static class Builder { - - private long mInitialDeviceSystemClockMillis; - private long mInitialDeviceRealtimeMillis; - private long mActualTimeMillis; - - Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day, - int hourOfDay, int minute, int second) { - mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay, - minute, second); - return this; - } - - Builder setInitialDeviceRealtimeMillis(long realtimeMillis) { - mInitialDeviceRealtimeMillis = realtimeMillis; - return this; - } - - Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay, - int minute, int second) { - mActualTimeMillis = - createUtcTime(year, monthInYear, day, hourOfDay, minute, second); - return this; - } - - Scenario build() { - return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis, - mActualTimeMillis); - } - } - } - - private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId, - TimestampedValue<Long> utcTime) { - return new PhoneTimeSuggestion.Builder(phoneId) - .setUtcTime(utcTime) - .build(); - } - - private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) { - TimestampedValue<Long> utcTime = - new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis); - return new ManualTimeSuggestion(utcTime); - } - - private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute, - int second) { - Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC")); - cal.clear(); - cal.set(year, monthInYear - 1, day, hourOfDay, minute, second); - return cal.getTimeInMillis(); - } -} diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index 84b495f14c1f..72a7f508772b 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -38,8 +38,6 @@ import android.util.TimestampedValue; import androidx.test.runner.AndroidJUnit4; -import com.android.server.timedetector.TimeDetectorStrategy.Callback; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -52,7 +50,6 @@ public class TimeDetectorServiceTest { private Context mMockContext; private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy; - private Callback mMockCallback; private TimeDetectorService mTimeDetectorService; private HandlerThread mHandlerThread; @@ -68,12 +65,10 @@ public class TimeDetectorServiceTest { mHandlerThread.start(); mTestHandler = new TestHandler(mHandlerThread.getLooper()); - mMockCallback = mock(Callback.class); mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy(); mTimeDetectorService = new TimeDetectorService( - mMockContext, mTestHandler, mMockCallback, - mStubbedTimeDetectorStrategy); + mMockContext, mTestHandler, mStubbedTimeDetectorStrategy); } @After @@ -100,13 +95,13 @@ public class TimeDetectorServiceTest { @Test public void testSuggestManualTime() throws Exception { - doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); + doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any()); ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(); mTimeDetectorService.suggestManualTime(manualTimeSuggestion); mTestHandler.assertTotalMessagesEnqueued(1); - verify(mMockContext).enforceCallingPermission( + verify(mMockContext).enforceCallingOrSelfPermission( eq(android.Manifest.permission.SET_TIME), anyString()); diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java new file mode 100644 index 000000000000..1aa3d8fe654b --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timedetector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.timedetector.ManualTimeSuggestion; +import android.app.timedetector.PhoneTimeSuggestion; +import android.content.Intent; +import android.icu.util.Calendar; +import android.icu.util.GregorianCalendar; +import android.icu.util.TimeZone; +import android.util.TimestampedValue; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Duration; + +@RunWith(AndroidJUnit4.class) +public class TimeDetectorStrategyImplTest { + + private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO = + new TimestampedValue<>( + 123456789L /* realtimeClockMillis */, + createUtcTime(1977, 1, 1, 12, 0, 0)); + + private static final long ARBITRARY_TEST_TIME_MILLIS = createUtcTime(2018, 1, 1, 12, 0, 0); + + private static final int ARBITRARY_PHONE_ID = 123456; + + private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis(); + + private Script mScript; + + @Before + public void setUp() { + mScript = new Script(); + } + + @Test + public void testSuggestPhoneTime_autoTimeEnabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + int phoneId = ARBITRARY_PHONE_ID; + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion timeSuggestion = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + int clockIncrement = 1000; + long expectedSystemClockMillis = testTimeMillis + clockIncrement; + + mScript.simulateTimePassing(clockIncrement) + .simulatePhoneTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion); + } + + @Test + public void testSuggestPhoneTime_emptySuggestionIgnored() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + int phoneId = ARBITRARY_PHONE_ID; + PhoneTimeSuggestion timeSuggestion = + mScript.generatePhoneTimeSuggestion(phoneId, null); + mScript.simulatePhoneTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, null); + } + + @Test + public void testSuggestPhoneTime_systemClockThreshold() { + int systemClockUpdateThresholdMillis = 1000; + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeThresholds(systemClockUpdateThresholdMillis) + .pokeAutoTimeDetectionEnabled(true); + + final int clockIncrement = 100; + int phoneId = ARBITRARY_PHONE_ID; + + // Send the first time signal. It should be used. + { + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion timeSuggestion1 = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + + // Increment the the device clocks to simulate the passage of time. + mScript.simulateTimePassing(clockIncrement); + + long expectedSystemClockMillis1 = + TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + + mScript.simulatePhoneTimeSuggestion(timeSuggestion1) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + } + + // Now send another time signal, but one that is too similar to the last one and should be + // stored, but not used to set the system clock. + { + int underThresholdMillis = systemClockUpdateThresholdMillis - 1; + PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion( + phoneId, mScript.peekSystemClockMillis() + underThresholdMillis); + mScript.simulateTimePassing(clockIncrement) + .simulatePhoneTimeSuggestion(timeSuggestion2) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion2); + } + + // Now send another time signal, but one that is on the threshold and so should be used. + { + PhoneTimeSuggestion timeSuggestion3 = mScript.generatePhoneTimeSuggestion( + phoneId, + mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis); + mScript.simulateTimePassing(clockIncrement); + + long expectedSystemClockMillis3 = + TimeDetectorStrategy.getTimeAt(timeSuggestion3.getUtcTime(), + mScript.peekElapsedRealtimeMillis()); + + mScript.simulatePhoneTimeSuggestion(timeSuggestion3) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis3, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion3); + } + } + + @Test + public void testSuggestPhoneTime_multiplePhoneIdsAndBucketing() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + // There are 2 phones in this test. Phone 2 has a different idea of the current time. + // phone1Id < phone2Id (which is important because the strategy uses the lowest ID when + // multiple phone suggestions are available. + int phone1Id = ARBITRARY_PHONE_ID; + int phone2Id = ARBITRARY_PHONE_ID + 1; + long phone1TimeMillis = ARBITRARY_TEST_TIME_MILLIS; + long phone2TimeMillis = phone1TimeMillis + 60000; + + final int clockIncrement = 999; + + // Make a suggestion with phone2Id. + { + PhoneTimeSuggestion phone2TimeSuggestion = + mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); + mScript.simulateTimePassing(clockIncrement); + + long expectedSystemClockMillis = phone2TimeMillis + clockIncrement; + + mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phone1Id, null) + .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion); + } + + mScript.simulateTimePassing(clockIncrement); + + // Now make a different suggestion with phone1Id. + { + PhoneTimeSuggestion phone1TimeSuggestion = + mScript.generatePhoneTimeSuggestion(phone1Id, phone1TimeMillis); + mScript.simulateTimePassing(clockIncrement); + + long expectedSystemClockMillis = phone1TimeMillis + clockIncrement; + + mScript.simulatePhoneTimeSuggestion(phone1TimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phone1Id, phone1TimeSuggestion); + + } + + mScript.simulateTimePassing(clockIncrement); + + // Make another suggestion with phone2Id. It should be stored but not used because the + // phone1Id suggestion will still "win". + { + PhoneTimeSuggestion phone2TimeSuggestion = + mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); + mScript.simulateTimePassing(clockIncrement); + + mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion); + } + + // Let enough time pass that phone1Id's suggestion should now be too old. + mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_BUCKET_SIZE_MILLIS); + + // Make another suggestion with phone2Id. It should be used because the phoneId1 + // is in an older "bucket". + { + PhoneTimeSuggestion phone2TimeSuggestion = + mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis); + mScript.simulateTimePassing(clockIncrement); + + long expectedSystemClockMillis = phone2TimeMillis + clockIncrement; + + mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion); + } + } + + @Test + public void testSuggestPhoneTime_autoTimeDisabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(false); + + int phoneId = ARBITRARY_PHONE_ID; + PhoneTimeSuggestion timeSuggestion = + mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS); + mScript.simulateTimePassing(1000) + .simulatePhoneTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion); + } + + @Test + public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() { + final int systemClockUpdateThreshold = 2000; + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeThresholds(systemClockUpdateThreshold) + .pokeAutoTimeDetectionEnabled(true); + + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + int phoneId = ARBITRARY_PHONE_ID; + + PhoneTimeSuggestion timeSuggestion1 = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + + // Initialize the strategy / device with a time set from a phone suggestion. + mScript.simulateTimePassing(100); + long expectedSystemClockMillis1 = + TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + mScript.simulatePhoneTimeSuggestion(timeSuggestion1) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // The UTC time increment should be larger than the system clock update threshold so we + // know it shouldn't be ignored for other reasons. + long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold); + + // Now supply a new signal that has an obviously bogus reference time : older than the last + // one. + long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1; + TimestampedValue<Long> utcTime2 = new TimestampedValue<>( + referenceTimeBeforeLastSignalMillis, validUtcTimeMillis); + PhoneTimeSuggestion timeSuggestion2 = + createPhoneTimeSuggestion(phoneId, utcTime2); + mScript.simulatePhoneTimeSuggestion(timeSuggestion2) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // Now supply a new signal that has an obviously bogus reference time : substantially in the + // future. + long referenceTimeInFutureMillis = + utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1; + TimestampedValue<Long> utcTime3 = new TimestampedValue<>( + referenceTimeInFutureMillis, validUtcTimeMillis); + PhoneTimeSuggestion timeSuggestion3 = + createPhoneTimeSuggestion(phoneId, utcTime3); + mScript.simulatePhoneTimeSuggestion(timeSuggestion3) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // Just to prove validUtcTimeMillis is valid. + long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100; + TimestampedValue<Long> utcTime4 = new TimestampedValue<>( + validReferenceTimeMillis, validUtcTimeMillis); + long expectedSystemClockMillis4 = + TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis()); + PhoneTimeSuggestion timeSuggestion4 = + createPhoneTimeSuggestion(phoneId, utcTime4); + mScript.simulatePhoneTimeSuggestion(timeSuggestion4) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis4, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion4); + } + + @Test + public void testSuggestPhoneTime_timeDetectionToggled() { + final int clockIncrementMillis = 100; + final int systemClockUpdateThreshold = 2000; + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeThresholds(systemClockUpdateThreshold) + .pokeAutoTimeDetectionEnabled(false); + + int phoneId = ARBITRARY_PHONE_ID; + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion timeSuggestion1 = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime(); + + // Simulate time passing. + mScript.simulateTimePassing(clockIncrementMillis); + + // Simulate the time signal being received. It should not be used because auto time + // detection is off but it should be recorded. + mScript.simulatePhoneTimeSuggestion(timeSuggestion1) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // Simulate more time passing. + mScript.simulateTimePassing(clockIncrementMillis); + + long expectedSystemClockMillis1 = + TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); + + // Turn on auto time detection. + mScript.simulateAutoTimeDetectionToggle() + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis1, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // Turn off auto time detection. + mScript.simulateAutoTimeDetectionToggle() + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion1); + + // Receive another valid time signal. + // It should be on the threshold and accounting for the clock increments. + PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion( + phoneId, mScript.peekSystemClockMillis() + systemClockUpdateThreshold); + + // Simulate more time passing. + mScript.simulateTimePassing(clockIncrementMillis); + + long expectedSystemClockMillis2 = TimeDetectorStrategy.getTimeAt( + timeSuggestion2.getUtcTime(), mScript.peekElapsedRealtimeMillis()); + + // The new time, though valid, should not be set in the system clock because auto time is + // disabled. + mScript.simulatePhoneTimeSuggestion(timeSuggestion2) + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, timeSuggestion2); + + // Turn on auto time detection. + mScript.simulateAutoTimeDetectionToggle() + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis2, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, timeSuggestion2); + } + + @Test + public void testSuggestPhoneTime_maxSuggestionAge() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + int phoneId = ARBITRARY_PHONE_ID; + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion phoneSuggestion = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + int clockIncrementMillis = 1000; + + mScript.simulateTimePassing(clockIncrementMillis) + .simulatePhoneTimeSuggestion(phoneSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + testTimeMillis + clockIncrementMillis, true /* expectedNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, phoneSuggestion); + + // Look inside and check what the strategy considers the current best phone suggestion. + assertEquals(phoneSuggestion, mScript.peekBestPhoneSuggestion()); + + // Simulate time passing, long enough that phoneSuggestion is now too old. + mScript.simulateTimePassing(TimeDetectorStrategyImpl.PHONE_MAX_AGE_MILLIS); + + // Look inside and check what the strategy considers the current best phone suggestion. It + // should still be the, it's just no longer used. + assertNull(mScript.peekBestPhoneSuggestion()); + mScript.assertLatestPhoneSuggestion(phoneId, phoneSuggestion); + } + + @Test + public void testSuggestManualTime_autoTimeDisabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(false); + + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(testTimeMillis); + final int clockIncrement = 1000; + long expectedSystemClockMillis = testTimeMillis + clockIncrement; + + mScript.simulateTimePassing(clockIncrement) + .simulateManualTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedSystemClockMillis, false /* expectNetworkBroadcast */); + } + + @Test + public void testSuggestManualTime_retainsAutoSignal() { + // Configure the start state. + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + int phoneId = ARBITRARY_PHONE_ID; + + // Simulate a phone suggestion. + long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS; + PhoneTimeSuggestion phoneTimeSuggestion = + mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis); + long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue(); + final int clockIncrement = 1000; + + // Simulate the passage of time. + mScript.simulateTimePassing(clockIncrement); + expectedAutoClockMillis += clockIncrement; + + mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedAutoClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); + + // Simulate the passage of time. + mScript.simulateTimePassing(clockIncrement); + expectedAutoClockMillis += clockIncrement; + + // Switch to manual. + mScript.simulateAutoTimeDetectionToggle() + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); + + // Simulate the passage of time. + mScript.simulateTimePassing(clockIncrement); + expectedAutoClockMillis += clockIncrement; + + // Simulate a manual suggestion 1 day different from the auto suggestion. + long manualTimeMillis = testTimeMillis + ONE_DAY_MILLIS; + long expectedManualClockMillis = manualTimeMillis; + ManualTimeSuggestion manualTimeSuggestion = + mScript.generateManualTimeSuggestion(manualTimeMillis); + mScript.simulateManualTimeSuggestion(manualTimeSuggestion) + .verifySystemClockWasSetAndResetCallTracking( + expectedManualClockMillis, false /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); + + // Simulate the passage of time. + mScript.simulateTimePassing(clockIncrement); + expectedAutoClockMillis += clockIncrement; + + // Switch back to auto. + mScript.simulateAutoTimeDetectionToggle(); + + mScript.verifySystemClockWasSetAndResetCallTracking( + expectedAutoClockMillis, true /* expectNetworkBroadcast */) + .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); + + // Switch back to manual - nothing should happen to the clock. + mScript.simulateAutoTimeDetectionToggle() + .verifySystemClockWasNotSetAndResetCallTracking() + .assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion); + } + + /** + * Manual suggestions should be ignored if auto time is enabled. + */ + @Test + public void testSuggestManualTime_autoTimeEnabled() { + mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO) + .pokeAutoTimeDetectionEnabled(true); + + ManualTimeSuggestion timeSuggestion = + mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS); + final int clockIncrement = 1000; + + mScript.simulateTimePassing(clockIncrement) + .simulateManualTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + /** + * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving + * like the real thing should, it also asserts preconditions. + */ + private static class FakeCallback implements TimeDetectorStrategy.Callback { + private boolean mAutoTimeDetectionEnabled; + private boolean mWakeLockAcquired; + private long mElapsedRealtimeMillis; + private long mSystemClockMillis; + private int mSystemClockUpdateThresholdMillis = 2000; + + // Tracking operations. + private boolean mSystemClockWasSet; + private Intent mBroadcastSent; + + @Override + public int systemClockUpdateThresholdMillis() { + return mSystemClockUpdateThresholdMillis; + } + + @Override + public boolean isAutoTimeDetectionEnabled() { + return mAutoTimeDetectionEnabled; + } + + @Override + public void acquireWakeLock() { + if (mWakeLockAcquired) { + fail("Wake lock already acquired"); + } + mWakeLockAcquired = true; + } + + @Override + public long elapsedRealtimeMillis() { + return mElapsedRealtimeMillis; + } + + @Override + public long systemClockMillis() { + assertWakeLockAcquired(); + return mSystemClockMillis; + } + + @Override + public void setSystemClock(long newTimeMillis) { + assertWakeLockAcquired(); + mSystemClockWasSet = true; + mSystemClockMillis = newTimeMillis; + } + + @Override + public void releaseWakeLock() { + assertWakeLockAcquired(); + mWakeLockAcquired = false; + } + + @Override + public void sendStickyBroadcast(Intent intent) { + assertNotNull(intent); + mBroadcastSent = intent; + } + + // Methods below are for managing the fake's behavior. + + void pokeSystemClockUpdateThreshold(int thresholdMillis) { + mSystemClockUpdateThresholdMillis = thresholdMillis; + } + + void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) { + mElapsedRealtimeMillis = elapsedRealtimeMillis; + } + + void pokeSystemClockMillis(long systemClockMillis) { + mSystemClockMillis = systemClockMillis; + } + + void pokeAutoTimeDetectionEnabled(boolean enabled) { + mAutoTimeDetectionEnabled = enabled; + } + + long peekElapsedRealtimeMillis() { + return mElapsedRealtimeMillis; + } + + long peekSystemClockMillis() { + return mSystemClockMillis; + } + + void simulateTimePassing(long incrementMillis) { + mElapsedRealtimeMillis += incrementMillis; + mSystemClockMillis += incrementMillis; + } + + void simulateAutoTimeZoneDetectionToggle() { + mAutoTimeDetectionEnabled = !mAutoTimeDetectionEnabled; + } + + void verifySystemClockNotSet() { + assertFalse(mSystemClockWasSet); + } + + void verifySystemClockWasSet(long expectedSystemClockMillis) { + assertTrue(mSystemClockWasSet); + assertEquals(expectedSystemClockMillis, mSystemClockMillis); + } + + void verifyIntentWasBroadcast() { + assertTrue(mBroadcastSent != null); + } + + void verifyIntentWasNotBroadcast() { + assertNull(mBroadcastSent); + } + + void resetCallTracking() { + mSystemClockWasSet = false; + mBroadcastSent = null; + } + + private void assertWakeLockAcquired() { + assertTrue("The operation must be performed only after acquiring the wakelock", + mWakeLockAcquired); + } + } + + /** + * A fluent helper class for tests. + */ + private class Script { + + private final FakeCallback mFakeCallback; + private final TimeDetectorStrategyImpl mTimeDetectorStrategy; + + Script() { + mFakeCallback = new FakeCallback(); + mTimeDetectorStrategy = new TimeDetectorStrategyImpl(); + mTimeDetectorStrategy.initialize(mFakeCallback); + + } + + Script pokeAutoTimeDetectionEnabled(boolean enabled) { + mFakeCallback.pokeAutoTimeDetectionEnabled(enabled); + return this; + } + + Script pokeFakeClocks(TimestampedValue<Long> timeInfo) { + mFakeCallback.pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis()); + mFakeCallback.pokeSystemClockMillis(timeInfo.getValue()); + return this; + } + + Script pokeThresholds(int systemClockUpdateThreshold) { + mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold); + return this; + } + + long peekElapsedRealtimeMillis() { + return mFakeCallback.peekElapsedRealtimeMillis(); + } + + long peekSystemClockMillis() { + return mFakeCallback.peekSystemClockMillis(); + } + + Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) { + mTimeDetectorStrategy.suggestPhoneTime(timeSuggestion); + return this; + } + + Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) { + mTimeDetectorStrategy.suggestManualTime(timeSuggestion); + return this; + } + + Script simulateAutoTimeDetectionToggle() { + mFakeCallback.simulateAutoTimeZoneDetectionToggle(); + mTimeDetectorStrategy.handleAutoTimeDetectionChanged(); + return this; + } + + Script simulateTimePassing(long clockIncrementMillis) { + mFakeCallback.simulateTimePassing(clockIncrementMillis); + return this; + } + + Script verifySystemClockWasNotSetAndResetCallTracking() { + mFakeCallback.verifySystemClockNotSet(); + mFakeCallback.verifyIntentWasNotBroadcast(); + mFakeCallback.resetCallTracking(); + return this; + } + + Script verifySystemClockWasSetAndResetCallTracking( + long expectedSystemClockMillis, boolean expectNetworkBroadcast) { + mFakeCallback.verifySystemClockWasSet(expectedSystemClockMillis); + if (expectNetworkBroadcast) { + mFakeCallback.verifyIntentWasBroadcast(); + } + mFakeCallback.resetCallTracking(); + return this; + } + + /** + * White box test info: Asserts the latest suggestion for the phone ID is as expected. + */ + Script assertLatestPhoneSuggestion(int phoneId, PhoneTimeSuggestion expected) { + assertEquals(expected, mTimeDetectorStrategy.getLatestPhoneSuggestion(phoneId)); + return this; + } + + /** + * White box test info: Returns the phone suggestion that would be used, if any, given the + * current elapsed real time clock. + */ + PhoneTimeSuggestion peekBestPhoneSuggestion() { + return mTimeDetectorStrategy.findBestPhoneSuggestionForTests(); + } + + /** + * Generates a ManualTimeSuggestion using the current elapsed realtime clock for the + * reference time. + */ + ManualTimeSuggestion generateManualTimeSuggestion(long timeMillis) { + TimestampedValue<Long> utcTime = + new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis); + return new ManualTimeSuggestion(utcTime); + } + + /** + * Generates a PhoneTimeSuggestion using the current elapsed realtime clock for the + * reference time. + */ + PhoneTimeSuggestion generatePhoneTimeSuggestion(int phoneId, Long timeMillis) { + TimestampedValue<Long> time = null; + if (timeMillis != null) { + time = new TimestampedValue<>(peekElapsedRealtimeMillis(), timeMillis); + } + return createPhoneTimeSuggestion(phoneId, time); + } + } + + private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId, + TimestampedValue<Long> utcTime) { + return new PhoneTimeSuggestion.Builder(phoneId) + .setUtcTime(utcTime) + .build(); + } + + private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute, + int second) { + Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC")); + cal.clear(); + cal.set(year, monthInYear - 1, day, hourOfDay, minute, second); + return cal.getTimeInMillis(); + } +} diff --git a/services/usage/Android.bp b/services/usage/Android.bp index 1064b6ed802f..156bf330c128 100644 --- a/services/usage/Android.bp +++ b/services/usage/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.usage-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.usage", - srcs: ["java/**/*.java"], + srcs: [":services.usage-sources"], libs: ["services.core"], } diff --git a/services/usb/Android.bp b/services/usb/Android.bp index 20855b70cabc..d2c973abbc74 100644 --- a/services/usb/Android.bp +++ b/services/usb/Android.bp @@ -1,6 +1,13 @@ +filegroup { + name: "services.usb-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.usb", - srcs: ["java/**/*.java"], + srcs: [":services.usb-sources"], libs: [ "services.core", diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp index 390406f97264..85b96f34f4f6 100644 --- a/services/voiceinteraction/Android.bp +++ b/services/voiceinteraction/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.voiceinteraction-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.voiceinteraction", - srcs: ["java/**/*.java"], + srcs: [":services.voiceinteraction-sources"], libs: ["services.core"], } diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp index 59a80fbae792..993d1e1092b9 100644 --- a/startop/iorap/Android.bp +++ b/startop/iorap/Android.bp @@ -12,19 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -java_library_static { - name: "services.startop.iorap", - - aidl: { - include_dirs: [ - "system/iorap/binder", - ], - }, - - libs: ["services.core"], +filegroup { + name: "services.startop.iorap-javasources", + srcs: ["src/**/*.java"], + path: "src", + visibility: ["//visibility:private"], +} +filegroup { + name: "services.startop.iorap-sources", srcs: [ - ":iorap-aidl", - "**/*.java", + ":services.startop.iorap-javasources", + ":iorap-aidl", ], + visibility: ["//frameworks/base/services:__subpackages__"], +} + +java_library_static { + name: "services.startop.iorap", + srcs: [":services.startop.iorap-sources"], + libs: ["services.core"], } diff --git a/telephony/java/com/android/internal/telephony/EncodeException.java b/telephony/common/com/android/internal/telephony/EncodeException.java index cdc853e09895..cdc853e09895 100644 --- a/telephony/java/com/android/internal/telephony/EncodeException.java +++ b/telephony/common/com/android/internal/telephony/EncodeException.java diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index 7cf4eebabec9..df668ea2313d 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -305,7 +305,7 @@ public final class SmsApplication { Uri.fromParts(SCHEME_SMSTO, "", null)); List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.getUserHandleForUid(userId)); + UserHandle.of(userId)); for (ResolveInfo resolveInfo : respondServices) { final ServiceInfo serviceInfo = resolveInfo.serviceInfo; if (serviceInfo == null) { diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 73faf9f5f9f4..3940a3b0a1cf 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -116,7 +116,8 @@ public class Annotation { ApnSetting.TYPE_CBS, ApnSetting.TYPE_IA, ApnSetting.TYPE_EMERGENCY, - ApnSetting.TYPE_MCX + ApnSetting.TYPE_MCX, + ApnSetting.TYPE_XCAP, }) @Retention(RetentionPolicy.SOURCE) public @interface ApnType { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 261e8d008187..c04105b0599e 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -100,6 +100,16 @@ public class CarrierConfigManager { KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; /** + * Boolean indicating the Supplementary Services(SS) is disable when airplane mode on in the + * Call Settings menu. + * {@code true}: SS is disable when airplane mode on. + * {@code false}: SS is enable when airplane mode on. + * The default value for this key is {@code false} + */ + public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = + "disable_supplementary_services_in_airplane_mode_bool"; + + /** * Boolean indicating if the "Call forwarding" item is visible in the Call Settings menu. * true means visible. false means gone. * @hide @@ -3412,6 +3422,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true); sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true); + sDefaults.putBoolean(KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL, false); sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false); sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false); sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true); diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java index f4ce6e75769c..ce5e3f38e78b 100644 --- a/telephony/java/android/telephony/CbGeoUtils.java +++ b/telephony/java/android/telephony/CbGeoUtils.java @@ -18,6 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.os.Build; import android.text.TextUtils; import java.util.ArrayList; @@ -257,6 +258,15 @@ public class CbGeoUtils { return new Point(x - p.x, y - p.y); } } + + @Override + public String toString() { + String str = "Polygon: "; + if (Build.IS_DEBUGGABLE) { + str += mVertices; + } + return str; + } } /** @@ -284,6 +294,16 @@ public class CbGeoUtils { public boolean contains(LatLng p) { return mCenter.distance(p) <= mRadiusMeter; } + + @Override + public String toString() { + String str = "Circle: "; + if (Build.IS_DEBUGGABLE) { + str += mCenter + ", radius = " + mRadiusMeter; + } + + return str; + } } /** diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index f771a17755af..e1c4bef0dd65 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -15,17 +15,14 @@ */ package android.telephony; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.os.PersistableBundle; - import android.telephony.Annotation.DataFailureCause; -import com.android.internal.util.ArrayUtils; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import com.android.internal.telephony.util.ArrayUtils; + import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; diff --git a/telephony/java/android/telephony/IFinancialSmsCallback.aidl b/telephony/java/android/telephony/IFinancialSmsCallback.aidl deleted file mode 100644 index aa88615c15cf..000000000000 --- a/telephony/java/android/telephony/IFinancialSmsCallback.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/* -** Copyright 2019, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ -package android.telephony; - -import android.app.PendingIntent; -import android.database.CursorWindow; -import android.net.Uri; -import android.os.Bundle; -import com.android.internal.telephony.SmsRawData; - -/** Interface for returning back the financial sms messages asynchrously. - * @hide - */ -interface IFinancialSmsCallback { - /** - * Return sms messages back to calling financial app. - * - * @param messages the sms messages returned for cinancial app. - */ - oneway void onGetSmsMessagesForFinancialApp(in CursorWindow messages); -} diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index bbf746fcf3c4..fc717e7465b1 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -24,8 +24,8 @@ import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.AccessNetworkConstants.TransportType; - import android.telephony.Annotation.NetworkType; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -90,7 +90,7 @@ public final class NetworkRegistrationInfo implements Parcelable { * Dual Connectivity(EN-DC). * @hide */ - public static final int NR_STATE_NONE = -1; + public static final int NR_STATE_NONE = 0; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 1e601cf3de5f..d2c851789b96 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -102,7 +102,7 @@ public class ServiceState implements Parcelable { * Indicates frequency range is unknown. * @hide */ - public static final int FREQUENCY_RANGE_UNKNOWN = -1; + public static final int FREQUENCY_RANGE_UNKNOWN = 0; /** * Indicates the frequency range is below 1GHz. @@ -278,12 +278,9 @@ public class ServiceState implements Parcelable { */ public static final int UNKNOWN_ID = -1; - private String mVoiceOperatorAlphaLong; - private String mVoiceOperatorAlphaShort; - private String mVoiceOperatorNumeric; - private String mDataOperatorAlphaLong; - private String mDataOperatorAlphaShort; - private String mDataOperatorNumeric; + private String mOperatorAlphaLong; + private String mOperatorAlphaShort; + private String mOperatorNumeric; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private boolean mIsManualNetworkSelection; @@ -379,12 +376,9 @@ public class ServiceState implements Parcelable { protected void copyFrom(ServiceState s) { mVoiceRegState = s.mVoiceRegState; mDataRegState = s.mDataRegState; - mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong; - mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort; - mVoiceOperatorNumeric = s.mVoiceOperatorNumeric; - mDataOperatorAlphaLong = s.mDataOperatorAlphaLong; - mDataOperatorAlphaShort = s.mDataOperatorAlphaShort; - mDataOperatorNumeric = s.mDataOperatorNumeric; + mOperatorAlphaLong = s.mOperatorAlphaLong; + mOperatorAlphaShort = s.mOperatorAlphaShort; + mOperatorNumeric = s.mOperatorNumeric; mIsManualNetworkSelection = s.mIsManualNetworkSelection; mCssIndicator = s.mCssIndicator; mNetworkId = s.mNetworkId; @@ -418,12 +412,9 @@ public class ServiceState implements Parcelable { public ServiceState(Parcel in) { mVoiceRegState = in.readInt(); mDataRegState = in.readInt(); - mVoiceOperatorAlphaLong = in.readString(); - mVoiceOperatorAlphaShort = in.readString(); - mVoiceOperatorNumeric = in.readString(); - mDataOperatorAlphaLong = in.readString(); - mDataOperatorAlphaShort = in.readString(); - mDataOperatorNumeric = in.readString(); + mOperatorAlphaLong = in.readString(); + mOperatorAlphaShort = in.readString(); + mOperatorNumeric = in.readString(); mIsManualNetworkSelection = in.readInt() != 0; mCssIndicator = (in.readInt() != 0); mNetworkId = in.readInt(); @@ -448,12 +439,9 @@ public class ServiceState implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(mVoiceRegState); out.writeInt(mDataRegState); - out.writeString(mVoiceOperatorAlphaLong); - out.writeString(mVoiceOperatorAlphaShort); - out.writeString(mVoiceOperatorNumeric); - out.writeString(mDataOperatorAlphaLong); - out.writeString(mDataOperatorAlphaShort); - out.writeString(mDataOperatorNumeric); + out.writeString(mOperatorAlphaLong); + out.writeString(mOperatorAlphaShort); + out.writeString(mOperatorNumeric); out.writeInt(mIsManualNetworkSelection ? 1 : 0); out.writeInt(mCssIndicator ? 1 : 0); out.writeInt(mNetworkId); @@ -691,7 +679,7 @@ public class ServiceState implements Parcelable { * @return long name of operator, null if unregistered or unknown */ public String getOperatorAlphaLong() { - return mVoiceOperatorAlphaLong; + return mOperatorAlphaLong; } /** @@ -699,18 +687,10 @@ public class ServiceState implements Parcelable { * @return long name of operator * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@link #getOperatorAlphaLong} instead.") public String getVoiceOperatorAlphaLong() { - return mVoiceOperatorAlphaLong; - } - - /** - * Get current registered data network operator name in long alphanumeric format. - * @return long name of voice operator - * @hide - */ - public String getDataOperatorAlphaLong() { - return mDataOperatorAlphaLong; + return mOperatorAlphaLong; } /** @@ -721,7 +701,7 @@ public class ServiceState implements Parcelable { * @return short name of operator, null if unregistered or unknown */ public String getOperatorAlphaShort() { - return mVoiceOperatorAlphaShort; + return mOperatorAlphaShort; } /** @@ -729,9 +709,10 @@ public class ServiceState implements Parcelable { * @return short name of operator, null if unregistered or unknown * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.") public String getVoiceOperatorAlphaShort() { - return mVoiceOperatorAlphaShort; + return mOperatorAlphaShort; } /** @@ -739,9 +720,10 @@ public class ServiceState implements Parcelable { * @return short name of operator, null if unregistered or unknown * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.") public String getDataOperatorAlphaShort() { - return mDataOperatorAlphaShort; + return mOperatorAlphaShort; } /** @@ -755,11 +737,11 @@ public class ServiceState implements Parcelable { * @hide */ public String getOperatorAlpha() { - if (TextUtils.isEmpty(mVoiceOperatorAlphaLong)) { - return mVoiceOperatorAlphaShort; + if (TextUtils.isEmpty(mOperatorAlphaLong)) { + return mOperatorAlphaShort; } - return mVoiceOperatorAlphaLong; + return mOperatorAlphaLong; } /** @@ -775,7 +757,7 @@ public class ServiceState implements Parcelable { * {@link com.android.internal.telephony.MccTable#countryCodeForMcc(int)}. */ public String getOperatorNumeric() { - return mVoiceOperatorNumeric; + return mOperatorNumeric; } /** @@ -785,7 +767,7 @@ public class ServiceState implements Parcelable { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getVoiceOperatorNumeric() { - return mVoiceOperatorNumeric; + return mOperatorNumeric; } /** @@ -793,9 +775,10 @@ public class ServiceState implements Parcelable { * @return numeric format of operator, null if unregistered or unknown * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "Use {@link #getOperatorNumeric} instead.") public String getDataOperatorNumeric() { - return mDataOperatorNumeric; + return mOperatorNumeric; } /** @@ -815,12 +798,9 @@ public class ServiceState implements Parcelable { mDataRegState, mChannelNumber, Arrays.hashCode(mCellBandwidths), - mVoiceOperatorAlphaLong, - mVoiceOperatorAlphaShort, - mVoiceOperatorNumeric, - mDataOperatorAlphaLong, - mDataOperatorAlphaShort, - mDataOperatorNumeric, + mOperatorAlphaLong, + mOperatorAlphaShort, + mOperatorNumeric, mIsManualNetworkSelection, mCssIndicator, mNetworkId, @@ -850,12 +830,9 @@ public class ServiceState implements Parcelable { && mIsManualNetworkSelection == s.mIsManualNetworkSelection && mChannelNumber == s.mChannelNumber && Arrays.equals(mCellBandwidths, s.mCellBandwidths) - && equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong) - && equalsHandlesNulls(mVoiceOperatorAlphaShort, s.mVoiceOperatorAlphaShort) - && equalsHandlesNulls(mVoiceOperatorNumeric, s.mVoiceOperatorNumeric) - && equalsHandlesNulls(mDataOperatorAlphaLong, s.mDataOperatorAlphaLong) - && equalsHandlesNulls(mDataOperatorAlphaShort, s.mDataOperatorAlphaShort) - && equalsHandlesNulls(mDataOperatorNumeric, s.mDataOperatorNumeric) + && equalsHandlesNulls(mOperatorAlphaLong, s.mOperatorAlphaLong) + && equalsHandlesNulls(mOperatorAlphaShort, s.mOperatorAlphaShort) + && equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric) && equalsHandlesNulls(mCssIndicator, s.mCssIndicator) && equalsHandlesNulls(mNetworkId, s.mNetworkId) && equalsHandlesNulls(mSystemId, s.mSystemId) @@ -1007,10 +984,8 @@ public class ServiceState implements Parcelable { .append(", mChannelNumber=").append(mChannelNumber) .append(", duplexMode()=").append(getDuplexMode()) .append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths)) - .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong) - .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort) - .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong) - .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort) + .append(", mOperatorAlphaLong=").append(mOperatorAlphaLong) + .append(", mOperatorAlphaShort=").append(mOperatorAlphaShort) .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection) .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)") .append(", getRilVoiceRadioTechnology=").append(getRilVoiceRadioTechnology()) @@ -1040,12 +1015,9 @@ public class ServiceState implements Parcelable { mDataRegState = STATE_OUT_OF_SERVICE; mChannelNumber = -1; mCellBandwidths = new int[0]; - mVoiceOperatorAlphaLong = null; - mVoiceOperatorAlphaShort = null; - mVoiceOperatorNumeric = null; - mDataOperatorAlphaLong = null; - mDataOperatorAlphaShort = null; - mDataOperatorNumeric = null; + mOperatorAlphaLong = null; + mOperatorAlphaShort = null; + mOperatorNumeric = null; mIsManualNetworkSelection = false; mCssIndicator = false; mNetworkId = -1; @@ -1204,26 +1176,9 @@ public class ServiceState implements Parcelable { } public void setOperatorName(String longName, String shortName, String numeric) { - mVoiceOperatorAlphaLong = longName; - mVoiceOperatorAlphaShort = shortName; - mVoiceOperatorNumeric = numeric; - mDataOperatorAlphaLong = longName; - mDataOperatorAlphaShort = shortName; - mDataOperatorNumeric = numeric; - } - - /** @hide */ - public void setVoiceOperatorName(String longName, String shortName, String numeric) { - mVoiceOperatorAlphaLong = longName; - mVoiceOperatorAlphaShort = shortName; - mVoiceOperatorNumeric = numeric; - } - - /** @hide */ - public void setDataOperatorName(String longName, String shortName, String numeric) { - mDataOperatorAlphaLong = longName; - mDataOperatorAlphaShort = shortName; - mDataOperatorNumeric = numeric; + mOperatorAlphaLong = longName; + mOperatorAlphaShort = shortName; + mOperatorNumeric = numeric; } /** @@ -1233,19 +1188,8 @@ public class ServiceState implements Parcelable { * @hide */ @UnsupportedAppUsage - public void setOperatorAlphaLong(String longName) { - mVoiceOperatorAlphaLong = longName; - mDataOperatorAlphaLong = longName; - } - - /** @hide */ - public void setVoiceOperatorAlphaLong(String longName) { - mVoiceOperatorAlphaLong = longName; - } - - /** @hide */ - public void setDataOperatorAlphaLong(String longName) { - mDataOperatorAlphaLong = longName; + public void setOperatorAlphaLong(@Nullable String longName) { + mOperatorAlphaLong = longName; } public void setIsManualSelection(boolean isManual) { @@ -1293,12 +1237,12 @@ public class ServiceState implements Parcelable { m.putInt("dataRegState", mDataRegState); m.putInt("dataRoamingType", getDataRoamingType()); m.putInt("voiceRoamingType", getVoiceRoamingType()); - m.putString("operator-alpha-long", mVoiceOperatorAlphaLong); - m.putString("operator-alpha-short", mVoiceOperatorAlphaShort); - m.putString("operator-numeric", mVoiceOperatorNumeric); - m.putString("data-operator-alpha-long", mDataOperatorAlphaLong); - m.putString("data-operator-alpha-short", mDataOperatorAlphaShort); - m.putString("data-operator-numeric", mDataOperatorNumeric); + m.putString("operator-alpha-long", mOperatorAlphaLong); + m.putString("operator-alpha-short", mOperatorAlphaShort); + m.putString("operator-numeric", mOperatorNumeric); + m.putString("data-operator-alpha-long", mOperatorAlphaLong); + m.putString("data-operator-alpha-short", mOperatorAlphaShort); + m.putString("data-operator-numeric", mOperatorNumeric); m.putBoolean("manual", mIsManualNetworkSelection); m.putInt("radioTechnology", getRilVoiceRadioTechnology()); m.putInt("dataRadioTechnology", getRadioTechnology()); @@ -1933,12 +1877,9 @@ public class ServiceState implements Parcelable { } if (!removeCoarseLocation) return state; - state.mDataOperatorAlphaLong = null; - state.mDataOperatorAlphaShort = null; - state.mDataOperatorNumeric = null; - state.mVoiceOperatorAlphaLong = null; - state.mVoiceOperatorAlphaShort = null; - state.mVoiceOperatorNumeric = null; + state.mOperatorAlphaLong = null; + state.mOperatorAlphaShort = null; + state.mOperatorNumeric = null; return state; } diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java index c7f952954d5f..045d1ebb5640 100644 --- a/telephony/java/android/telephony/SmsCbMessage.java +++ b/telephony/java/android/telephony/SmsCbMessage.java @@ -533,7 +533,8 @@ public final class SmsCbMessage implements Parcelable { + ", priority=" + mPriority + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "") + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") - + ", maximumWaitingTime = " + mMaximumWaitTimeSec + + ", maximumWaitingTime=" + mMaximumWaitTimeSec + + ", received time=" + mReceivedTimeMillis + ", slotIndex = " + mSlotIndex + ", geo=" + (mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null") diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index daeacf8206b4..5b49117be532 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -32,6 +32,7 @@ import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; import android.os.Binder; +import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; @@ -79,11 +80,6 @@ public final class SmsManager { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); private static final Object sLockObject = new Object(); - /** @hide */ - public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0; - /** @hide */ - public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1; - /** SMS record length from TS 51.011 10.5.3 * @hide */ @@ -2457,7 +2453,9 @@ public final class SmsManager { } } - /** callback for providing asynchronous sms messages for financial app. */ + /** + * callback for providing asynchronous sms messages for financial app. + */ public abstract static class FinancialSmsCallback { /** * Callback to send sms messages back to financial app asynchronously. @@ -2483,24 +2481,14 @@ public final class SmsManager { * @param params the parameters to filter SMS messages returned. * @param executor the executor on which callback will be invoked. * @param callback a callback to receive CursorWindow with SMS messages. + * */ @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp( Bundle params, @NonNull @CallbackExecutor Executor executor, @NonNull FinancialSmsCallback callback) { - try { - ISms iccSms = getISmsServiceOrThrow(); - iccSms.getSmsMessagesForFinancialApp( - getSubscriptionId(), ActivityThread.currentPackageName(), params, - new IFinancialSmsCallback.Stub() { - public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) { - Binder.withCleanCallingIdentity(() -> executor.execute( - () -> callback.onFinancialSmsMessages(msgs))); - }}); - } catch (RemoteException ex) { - ex.rethrowFromSystemServer(); - } + // This API is not functional and thus removed to avoid future confusion. } /** diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 9eff809eaf5d..ebb517596b6c 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -89,8 +89,8 @@ public class SubscriptionInfo implements Parcelable { private int mCarrierId; /** - * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or - * NAME_SOURCE_USER_INPUT. + * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN, + * NAME_SOURCE_SIM_PNN, or NAME_SOURCE_USER_INPUT. */ private int mNameSource; @@ -334,7 +334,7 @@ public class SubscriptionInfo implements Parcelable { } /** - * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or + * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN or * NAME_SOURCE_USER_INPUT. * @hide */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index fbbc9518065d..4f908408506b 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -35,7 +35,6 @@ import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.BroadcastOptions; import android.app.PendingIntent; -import android.app.job.JobService; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; @@ -148,10 +147,11 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()} - * while your app is running. You can also use a {@link JobService} to ensure your app + * while your app is running. You can also use a {@link android.app.job.JobService} + * to ensure your app * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -168,10 +168,10 @@ public class SubscriptionManager { * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription advanced calling enabled * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running. - * You can also use a {@link JobService} to ensure your app is notified of changes to the - * {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * You can also use a {@link android.app.job.JobService} to ensure your app is notified of + * changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -187,10 +187,10 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()} - * while your app is running. You can also use a {@link JobService} to ensure your app - * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * while your app is running. You can also use a {@link android.app.job.JobService} to ensure + * your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -205,10 +205,10 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()} - * while your app is running. You can also use a {@link JobService} to ensure your app - * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * while your app is running. You can also use a {@link android.app.job.JobService} + * to ensure your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -225,10 +225,10 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()} - * while your app is running. You can also use a {@link JobService} to ensure your app - * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * while your app is running. You can also use a {@link android.app.job.JobService} to ensure + * your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -244,10 +244,10 @@ public class SubscriptionManager { * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()} - * while your app is running. You can also use a {@link JobService} to ensure your app - * is notified of changes to the {@link Uri} even when it is not running. - * Note, however, that using a {@link JobService} does not guarantee timely delivery of - * updates to the {@link Uri}. + * while your app is running. You can also use a {@link android.app.job.JobService} to ensure + * your app is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely + * delivery of updates to the {@link Uri}. * To be notified of changes to a specific subId, append subId to the URI * {@link Uri#withAppendedPath(Uri, String)}. * @hide @@ -400,19 +400,19 @@ public class SubscriptionManager { public static final String NAME_SOURCE = "name_source"; /** - * The name_source is the default + * The name_source is the default, which is from the carrier id. * @hide */ public static final int NAME_SOURCE_DEFAULT_SOURCE = 0; /** - * The name_source is from the SIM + * The name_source is from SIM EF_SPN. * @hide */ - public static final int NAME_SOURCE_SIM_SOURCE = 1; + public static final int NAME_SOURCE_SIM_SPN = 1; /** - * The name_source is from the user + * The name_source is from user input * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -425,6 +425,24 @@ public class SubscriptionManager { public static final int NAME_SOURCE_CARRIER = 3; /** + * The name_source is from SIM EF_PNN. + * @hide + */ + public static final int NAME_SOURCE_SIM_PNN = 4; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"NAME_SOURCE_"}, + value = { + NAME_SOURCE_DEFAULT_SOURCE, + NAME_SOURCE_SIM_SPN, + NAME_SOURCE_USER_INPUT, + NAME_SOURCE_CARRIER, + NAME_SOURCE_SIM_PNN + }) + public @interface SimDisplayNameSource {} + + /** * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ @@ -1660,13 +1678,12 @@ public class SubscriptionManager { * Set display name by simInfo index with name source * @param displayName the display name of SIM card * @param subId the unique SubscriptionInfo index in database - * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, - * 2: NAME_SOURCE_USER_INPUT + * @param nameSource SIM display name source * @return the number of records updated or < 0 if invalid subId * @hide */ @UnsupportedAppUsage - public int setDisplayName(String displayName, int subId, int nameSource) { + public int setDisplayName(String displayName, int subId, @SimDisplayNameSource int nameSource) { if (VDBG) { logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource); @@ -2897,8 +2914,7 @@ public class SubscriptionManager { * * @throws SecurityException if the caller doesn't meet the requirements * outlined above. - * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist, - * or the groupUuid doesn't exist. + * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist. * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that need adding into the group diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 4fb26fdf1d2c..7232ea714180 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -416,14 +416,14 @@ public class TelephonyManager { int modemCount = 1; switch (getMultiSimConfiguration()) { case UNKNOWN: - ConnectivityManager cm = mContext == null ? null : (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); + modemCount = MODEM_COUNT_SINGLE_MODEM; // check for voice and data support, 0 if not supported - if (!isVoiceCapable() && !isSmsCapable() && cm != null - && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { - modemCount = MODEM_COUNT_NO_MODEM; - } else { - modemCount = MODEM_COUNT_SINGLE_MODEM; + if (!isVoiceCapable() && !isSmsCapable() && mContext != null) { + ConnectivityManager cm = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm != null && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { + modemCount = MODEM_COUNT_NO_MODEM; + } } break; case DSDS: @@ -592,6 +592,7 @@ public class TelephonyManager { * * @hide */ + @SystemApi @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE"; @@ -2366,6 +2367,8 @@ public class TelephonyManager { * * @return the lowercase 2 character ISO-3166 country code, or empty string if not available. * + * @throws IllegalArgumentException when the slotIndex is invalid. + * * {@hide} */ @SystemApi @@ -2373,6 +2376,10 @@ public class TelephonyManager { @NonNull public String getNetworkCountryIso(int slotIndex) { try { + if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { + throw new IllegalArgumentException("invalid slot index " + slotIndex); + } + ITelephony telephony = getITelephony(); if (telephony == null) return ""; return telephony.getNetworkCountryIsoForPhone(slotIndex); diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 60774e7f1e7f..034fc220cbbe 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentValues; import android.database.Cursor; -import android.hardware.radio.V1_4.ApnTypes; +import android.hardware.radio.V1_5.ApnTypes; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -110,6 +110,8 @@ public class ApnSetting implements Parcelable { public static final int TYPE_EMERGENCY = ApnTypes.EMERGENCY; /** APN type for MCX (Mission Critical Service) where X can be PTT/Video/Data */ public static final int TYPE_MCX = ApnTypes.MCX; + /** APN type for XCAP. */ + public static final int TYPE_XCAP = ApnTypes.XCAP; // Possible values for authentication types. /** No authentication type. */ @@ -198,6 +200,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_STRING_MAP.put("ia", TYPE_IA); APN_TYPE_STRING_MAP.put("emergency", TYPE_EMERGENCY); APN_TYPE_STRING_MAP.put("mcx", TYPE_MCX); + APN_TYPE_STRING_MAP.put("xcap", TYPE_XCAP); APN_TYPE_INT_MAP = new ArrayMap<Integer, String>(); APN_TYPE_INT_MAP.put(TYPE_DEFAULT, "default"); APN_TYPE_INT_MAP.put(TYPE_MMS, "mms"); @@ -210,6 +213,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_INT_MAP.put(TYPE_IA, "ia"); APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, "emergency"); APN_TYPE_INT_MAP.put(TYPE_MCX, "mcx"); + APN_TYPE_INT_MAP.put(TYPE_XCAP, "xcap"); PROTOCOL_STRING_MAP = new ArrayMap<String, Integer>(); PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP); @@ -1944,8 +1948,9 @@ public class ApnSetting implements Parcelable { * {@link ApnSetting} built from this builder otherwise. */ public ApnSetting build() { - if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI | - TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX)) == 0 + if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI + | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX + | TYPE_XCAP)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { return null; } diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java index 76b214b71075..f4b2cef73a44 100644 --- a/telephony/java/android/telephony/ims/ImsReasonInfo.java +++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java @@ -889,6 +889,12 @@ public final class ImsReasonInfo implements Parcelable { */ public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623; + /** + * The dialed RTT call should be retried without RTT + * @hide + */ + public static final int CODE_RETRY_ON_IMS_WITHOUT_RTT = 3001; + /* * OEM specific error codes. To be used by OEMs when they don't want to reveal error code which * would be replaced by ERROR_UNSPECIFIED. @@ -1069,6 +1075,7 @@ public final class ImsReasonInfo implements Parcelable { CODE_REJECT_VT_AVPF_NOT_ALLOWED, CODE_REJECT_ONGOING_ENCRYPTED_CALL, CODE_REJECT_ONGOING_CS_CALL, + CODE_RETRY_ON_IMS_WITHOUT_RTT, CODE_OEM_CAUSE_1, CODE_OEM_CAUSE_2, CODE_OEM_CAUSE_3, diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java index d4ed9234569b..0630454cbf53 100644 --- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java @@ -31,7 +31,7 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; +import com.android.internal.telephony.util.ArrayUtils; import com.android.server.SystemConfig; import java.util.ArrayList; diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index c1d700a2d190..91aa3ce62cf2 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import com.android.internal.telephony.SmsRawData; /** @@ -570,17 +569,6 @@ interface ISms { int subId, String callingPkg, String prefixes, in PendingIntent intent); /** - * Get sms inbox messages for the calling financial app. - * - * @param subId the SIM id. - * @param callingPkg the package name of the calling app. - * @param params parameters to filter the sms messages. - * @param callback the callback interface to deliver the result. - */ - void getSmsMessagesForFinancialApp( - int subId, String callingPkg, in Bundle params, in IFinancialSmsCallback callback); - - /** * Check if the destination is a possible premium short code. * * @param destAddress the destination address to test for possible short code diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java index ff816f24667e..d9d4b6002206 100644 --- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java +++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import java.util.List; @@ -198,12 +197,6 @@ public class ISmsImplBase extends ISms.Stub { } @Override - public void getSmsMessagesForFinancialApp( - int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) { - throw new UnsupportedOperationException(); - } - - @Override public int checkSmsShortCodeDestination( int subid, String callingApk, String destAddress, String countryIso) { throw new UnsupportedOperationException(); diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 05e2ed9acb33..6e635143a8e5 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -161,6 +161,8 @@ public class PhoneConstants { public static final String APN_TYPE_EMERGENCY = "emergency"; /** APN type for Mission Critical Services */ public static final String APN_TYPE_MCX = "mcx"; + /** APN type for XCAP */ + public static final String APN_TYPE_XCAP = "xcap"; /** Array of all APN types */ public static final String[] APN_TYPES = {APN_TYPE_DEFAULT, APN_TYPE_MMS, @@ -172,7 +174,8 @@ public class PhoneConstants { APN_TYPE_CBS, APN_TYPE_IA, APN_TYPE_EMERGENCY, - APN_TYPE_MCX + APN_TYPE_MCX, + APN_TYPE_XCAP, }; public static final int RIL_CARD_MAX_APPS = 8; diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 03ea9208d064..4421c77dbbb1 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -485,6 +485,8 @@ public interface RILConstants { int RIL_REQUEST_EMERGENCY_DIAL = 205; int RIL_REQUEST_GET_PHONE_CAPABILITY = 206; int RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG = 207; + int RIL_REQUEST_ENABLE_UICC_APPLICATIONS = 208; + int RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT = 209; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; @@ -548,4 +550,5 @@ public interface RILConstants { int RIL_UNSOL_ICC_SLOT_STATUS = 1100; int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101; int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102; + int RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED = 1103; } diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java index 2cdf2f63e02f..dcea9bb72c01 100644 --- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java +++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java @@ -23,7 +23,7 @@ import android.telephony.Rlog; import android.util.SparseIntArray; import com.android.internal.telephony.cdma.sms.UserData; -import com.android.internal.util.XmlUtils; +import com.android.internal.telephony.util.XmlUtils; import dalvik.annotation.compat.UnsupportedAppUsage; diff --git a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java b/telephony/java/com/android/internal/telephony/util/ArrayUtils.java new file mode 100644 index 000000000000..2905125c69cc --- /dev/null +++ b/telephony/java/com/android/internal/telephony/util/ArrayUtils.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2019 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.internal.telephony.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +/** Utility methods for array operations. */ +public final class ArrayUtils { + private ArrayUtils() { /* cannot be instantiated */ } + + /** + * Adds value to given array if not already present, providing set-like behavior. + */ + @SuppressWarnings("unchecked") + public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { + return appendElement(kind, array, element, false); + } + + /** + * Adds value to given array. + */ + @SuppressWarnings("unchecked") + public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, + boolean allowDuplicates) { + final T[] result; + final int end; + if (array != null) { + if (!allowDuplicates && contains(array, element)) return array; + end = array.length; + result = (T[]) Array.newInstance(kind, end + 1); + System.arraycopy(array, 0, result, 0, end); + } else { + end = 0; + result = (T[]) Array.newInstance(kind, 1); + } + result[end] = element; + return result; + } + + /** + * Combine multiple arrays into a single array. + * + * @param kind The class of the array elements + * @param arrays The arrays to combine + * @param <T> The class of the array elements (inferred from kind). + * @return A single array containing all the elements of the parameter arrays. + */ + @SuppressWarnings("unchecked") + public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { + if (arrays == null || arrays.length == 0) { + return createEmptyArray(kind); + } + + int totalLength = 0; + for (T[] item : arrays) { + if (item == null) { + continue; + } + + totalLength += item.length; + } + + // Optimization for entirely empty arrays. + if (totalLength == 0) { + return createEmptyArray(kind); + } + + final T[] all = (T[]) Array.newInstance(kind, totalLength); + int pos = 0; + for (T[] item : arrays) { + if (item == null || item.length == 0) { + continue; + } + System.arraycopy(item, 0, all, pos, item.length); + pos += item.length; + } + return all; + } + + private static @NonNull <T> T[] createEmptyArray(Class<T> kind) { + if (kind == String.class) { + return (T[]) EmptyArray.STRING; + } else if (kind == Object.class) { + return (T[]) EmptyArray.OBJECT; + } + + return (T[]) Array.newInstance(kind, 0); + } + + private static final class EmptyArray { + private EmptyArray() {} + + public static final Object[] OBJECT = new Object[0]; + public static final String[] STRING = new String[0]; + } + + /** + * Checks if {@code value} is in {@code array}. + */ + public static boolean contains(@Nullable char[] array, char value) { + if (array == null) return false; + for (char element : array) { + if (element == value) { + return true; + } + } + return false; + } + + /** + * Checks if {@code value} is in {@code array}. + */ + public static <T> boolean contains(@Nullable Collection<T> cur, T val) { + return (cur != null) ? cur.contains(val) : false; + } + + /** + * Checks if {@code value} is in {@code array}. + */ + public static boolean contains(@Nullable int[] array, int value) { + if (array == null) return false; + for (int element : array) { + if (element == value) { + return true; + } + } + return false; + } + + /** + * Checks if {@code value} is in {@code array}. + */ + public static boolean contains(@Nullable long[] array, long value) { + if (array == null) return false; + for (long element : array) { + if (element == value) { + return true; + } + } + return false; + } + + /** + * Checks if {@code value} is in {@code array}. + */ + public static <T> boolean contains(@Nullable T[] array, T value) { + return indexOf(array, value) != -1; + } + + /** + * Return first index of {@code value} in {@code array}, or {@code -1} if + * not found. + */ + public static <T> int indexOf(@Nullable T[] array, T value) { + if (array == null) return -1; + for (int i = 0; i < array.length; i++) { + if (Objects.equals(array[i], value)) return i; + } + return -1; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(@Nullable Collection<?> array) { + return array == null || array.isEmpty(); + } + + /** + * Checks if given map is null or has zero elements. + */ + public static boolean isEmpty(@Nullable Map<?, ?> map) { + return map == null || map.isEmpty(); + } + + /** + * Checks if given array is null or has zero elements. + */ + public static <T> boolean isEmpty(@Nullable T[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(@Nullable int[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(@Nullable long[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(@Nullable byte[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(@Nullable boolean[] array) { + return array == null || array.length == 0; + } +} diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java new file mode 100644 index 000000000000..a28d65c9abb6 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 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.internal.telephony.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Binder; +import android.os.RemoteException; +import android.os.SystemProperties; + +import java.io.PrintWriter; + +/** + * This class provides various util functions + */ +public final class TelephonyUtils { + public static boolean IS_USER = "user".equals(android.os.Build.TYPE); + public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1; + + /** + * Verify that caller holds {@link android.Manifest.permission#DUMP}. + * + * @return true if access should be granted. + */ + public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { + if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump " + tag + " from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " due to missing android.permission.DUMP permission"); + return false; + } else { + return true; + } + } + + /** Returns an empty string if the input is {@code null}. */ + public static String emptyIfNull(@Nullable String str) { + return str == null ? "" : str; + } + + /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */ + public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) { + throw new RuntimeException(remoteException); + } + + /** + * Returns a {@link ComponentInfo} from the {@link ResolveInfo}, + * or throws an {@link IllegalStateException} if not available. + */ + public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) { + if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo; + if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo; + if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo; + throw new IllegalStateException("Missing ComponentInfo!"); + } +} diff --git a/telephony/java/com/android/internal/telephony/util/XmlUtils.java b/telephony/java/com/android/internal/telephony/util/XmlUtils.java new file mode 100644 index 000000000000..72c5d3a8e31b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/util/XmlUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 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.internal.telephony.util; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** Utility methods for XML operations. */ +public final class XmlUtils { + private XmlUtils() {} + + /** + * Moves parser to the first start tag, and expects the tag name being {@code firstElementName}. + */ + public static void beginDocument(XmlPullParser parser, String firstElementName) + throws XmlPullParserException, IOException { + int type; + while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) { + // no-op + } + + if (type != parser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + + if (!parser.getName().equals(firstElementName)) { + throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + + ", expected " + firstElementName); + } + } + + /** + * Moves parser to the next start tag. + */ + public static void nextElement(XmlPullParser parser) + throws XmlPullParserException, IOException { + int type; + while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) { + // no-op + } + } + + /** + * Moves parser to the next start tag within the {@code outerDepth}. + */ + public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) + throws IOException, XmlPullParserException { + for (;;) { + int type = parser.next(); + if (type == XmlPullParser.END_DOCUMENT + || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) { + return false; + } + if (type == XmlPullParser.START_TAG && parser.getDepth() == outerDepth + 1) { + return true; + } + } + } +} diff --git a/test-mock/Android.bp b/test-mock/Android.bp index aa4174ad40f4..616b6b005f89 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -30,6 +30,7 @@ java_sdk_library { libs: [ "framework-all", "app-compat-annotations", + "unsupportedappusage", ], api_packages: [ |