Merge "Resolve BluetoothHearingAid API usages by Settings"
diff --git a/Android.bp b/Android.bp
index e89aee0..5cb28f8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -366,7 +366,9 @@
sdk_version: "core_platform",
libs: [
+ "app-compat-annotations",
"ext",
+ "unsupportedappusage",
"updatable_media_stubs",
],
@@ -426,7 +428,6 @@
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 @@
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",
@@ -563,6 +566,7 @@
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
+ "core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
"core/java/com/android/internal/annotations/VisibleForTesting.java",
@@ -1622,15 +1626,16 @@
"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/DumpUtils.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/UserIcons.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"
],
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index ecd3078..1a6f104 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -23,6 +23,34 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
}
]
}
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
index 40f3c45..aaf25b1 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkext/Android.bp
@@ -19,7 +19,6 @@
java_libs: [ "framework-sdkext" ],
prebuilts: [
"com.android.sdkext.ldconfig",
- "cur_sdkinfo",
"derive_sdk.rc",
],
key: "com.android.sdkext.key",
@@ -43,28 +42,3 @@
filename: "ld.config.txt",
installable: false,
}
-
-python_binary_host {
- name: "gen_sdkinfo",
- srcs: [
- "derive_sdk/sdk.proto",
- "gen_sdkinfo.py",
- ],
- proto: {
- canonical_path_from_root: false,
- },
-}
-
-gensrcs {
- name: "cur_sdkinfo_src",
- srcs: [""],
- tools: [ "gen_sdkinfo" ],
- cmd: "$(location) -v 0 -o $(out)",
-}
-
-prebuilt_etc {
- name: "cur_sdkinfo",
- src: ":cur_sdkinfo_src",
- filename: "sdkinfo.binarypb",
- installable: false,
-}
diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING
index 8dc732d..91947f3 100644
--- a/apex/sdkext/TEST_MAPPING
+++ b/apex/sdkext/TEST_MAPPING
@@ -1,7 +1,7 @@
{
"presubmit": [
{
- "name": "framework-sdkext-tests"
+ "name": "CtsSdkExtTestCases"
}
]
}
diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkext/derive_sdk/derive_sdk.cpp
index 0aacebe..7536def 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.cpp
+++ b/apex/sdkext/derive_sdk/derive_sdk.cpp
@@ -68,7 +68,7 @@
auto itr = std::min_element(versions.begin(), versions.end());
std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr);
- if (!android::base::SetProperty("persist.com.android.sdkext.sdk_info", prop_value)) {
+ if (!android::base::SetProperty("ro.build.version.extensions.r", prop_value)) {
LOG(ERROR) << "failed to set sdk_info prop";
return EXIT_FAILURE;
}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
index c039a82..d3b9397 100644
--- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -17,25 +17,40 @@
package android.os.ext;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.os.Build.VERSION_CODES;
import android.os.SystemProperties;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-/** @hide */
+/**
+ * Methods for interacting with the extension SDK.
+ *
+ * This class provides information about the extension SDK version present
+ * on this device. Use the {@link #getExtensionVersion(int) getExtension} to
+ * query for the extension version for the given SDK version.
+
+ * @hide
+ */
+@SystemApi
public class SdkExtensions {
private static final int R_EXTENSION_INT;
static {
- R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+ R_EXTENSION_INT = SystemProperties.getInt("ro.build.version.extensions.r", 0);
}
- /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */
+ /**
+ * Values suitable as parameters for {@link #getExtensionVersion(int)}.
+ * @hide
+ */
@IntDef(value = { VERSION_CODES.R })
@Retention(RetentionPolicy.SOURCE)
public @interface SdkVersion {}
+ private SdkExtensions() { }
+
/**
* Return the version of the extension to the given SDK.
*
diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp
deleted file mode 100644
index ab63275..0000000
--- a/apex/sdkext/framework/tests/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_test {
- name: "framework-sdkext-tests",
- srcs: ["src/**/*.java"],
- libs: [
- "android.test.base",
- "android.test.runner",
- ],
- static_libs: [ "framework-sdkext" ],
- test_suites: [ "general-tests" ],
- platform_apis: true,
-}
diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml
deleted file mode 100644
index 831f132..0000000
--- a/apex/sdkext/framework/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.sdkext.tests">
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.sdkext.tests" />
-
-</manifest>
diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
deleted file mode 100644
index d7dca90..0000000
--- a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.os.ext;
-
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-public class SdkExtensionsTest extends TestCase {
-
- @SmallTest
- public void testBadArgument() throws Exception {
- try {
- SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q);
- fail("expected IllegalArgumentException");
- } catch (IllegalArgumentException expected) { }
- }
-
- @SmallTest
- public void testDefault() throws Exception {
- int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
- assertTrue(r >= 0);
- }
-
-}
diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkext/gen_sdkinfo.py
deleted file mode 100644
index 5af478b..0000000
--- a/apex/sdkext/gen_sdkinfo.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import sdk_pb2
-import sys
-
-if __name__ == '__main__':
- argv = sys.argv[1:]
- if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']:
- print('usage: gen_sdkinfo -v <version> -o <output-file>')
- sys.exit(1)
-
- for i in range(len(argv)):
- if sys.argv[i] == '-o':
- filename = sys.argv[i+1]
- if sys.argv[i] == '-v':
- version = int(sys.argv[i+1])
-
- proto = sdk_pb2.SdkVersion()
- proto.version = version
- with open(filename, 'wb') as f:
- f.write(proto.SerializeToString())
diff --git a/api/current.txt b/api/current.txt
index d2e1b5f..21ea6e6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28903,6 +28903,7 @@
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);
@@ -42386,6 +42387,7 @@
method public static String[] listxattr(String) throws android.system.ErrnoException;
method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
method public static android.system.StructStat lstat(String) throws android.system.ErrnoException;
+ method @NonNull public static java.io.FileDescriptor memfd_create(@NonNull String, int) throws android.system.ErrnoException;
method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
method public static void mkdir(String, int) throws android.system.ErrnoException;
method public static void mkfifo(String, int) throws android.system.ErrnoException;
@@ -42694,6 +42696,7 @@
field public static final int MCAST_UNBLOCK_SOURCE;
field public static final int MCL_CURRENT;
field public static final int MCL_FUTURE;
+ field public static final int MFD_CLOEXEC;
field public static final int MSG_CTRUNC;
field public static final int MSG_DONTROUTE;
field public static final int MSG_EOR;
@@ -44196,6 +44199,7 @@
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";
@@ -44264,7 +44268,6 @@
field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
- field public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT = "parameters_use_for_5g_nr_signal_bar_int";
field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool";
field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
@@ -45498,6 +45501,7 @@
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 {
@@ -46067,12 +46071,12 @@
package android.text {
- public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
- method public char charAt(int);
- method public void getChars(int, int, char[], int);
- method public int length();
- method public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
- method public CharSequence subSequence(int, int);
+ @Deprecated public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
+ method @Deprecated public char charAt(int);
+ method @Deprecated public void getChars(int, int, char[], int);
+ method @Deprecated public int length();
+ method @Deprecated public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
+ method @Deprecated public CharSequence subSequence(int, int);
}
@Deprecated public class AndroidCharacter {
@@ -46807,7 +46811,7 @@
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;
}
@@ -48244,6 +48248,13 @@
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
old mode 100644
new mode 100755
index 72e4e42..0e714d7
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1343,15 +1343,24 @@
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
@@ -1596,9 +1605,25 @@
field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+ field @Deprecated public static final String EXTRA_SIM_LOCKED_REASON = "reason";
+ field @Deprecated public static final String EXTRA_SIM_STATE = "ss";
field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
+ field @Deprecated public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+ field @Deprecated public static final String SIM_LOCKED_NETWORK = "NETWORK";
+ field @Deprecated public static final String SIM_LOCKED_ON_PIN = "PIN";
+ field @Deprecated public static final String SIM_LOCKED_ON_PUK = "PUK";
+ field @Deprecated public static final String SIM_STATE_ABSENT = "ABSENT";
+ field @Deprecated public static final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR";
+ field @Deprecated public static final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED";
+ field @Deprecated public static final String SIM_STATE_IMSI = "IMSI";
+ field @Deprecated public static final String SIM_STATE_LOADED = "LOADED";
+ field @Deprecated public static final String SIM_STATE_LOCKED = "LOCKED";
+ field @Deprecated public static final String SIM_STATE_NOT_READY = "NOT_READY";
+ field @Deprecated public static final String SIM_STATE_PRESENT = "PRESENT";
+ field @Deprecated public static final String SIM_STATE_READY = "READY";
+ field @Deprecated public static final String SIM_STATE_UNKNOWN = "UNKNOWN";
}
public class IntentFilter implements android.os.Parcelable {
@@ -4058,6 +4083,7 @@
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 {
@@ -4534,6 +4560,9 @@
}
public abstract class ChildSessionParams {
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
+ method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
}
public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
@@ -4601,6 +4630,13 @@
}
public final class IkeSessionParams {
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
+ method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
+ method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
+ method @NonNull public java.net.InetAddress getServerAddress();
+ method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
}
public static final class IkeSessionParams.Builder {
@@ -4617,6 +4653,27 @@
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
}
+ public abstract static class IkeSessionParams.IkeAuthConfig {
+ }
+
+ public static class IkeSessionParams.IkeAuthDigitalSignLocalConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public java.security.cert.X509Certificate getClientEndCertificate();
+ method @NonNull public java.util.List<java.security.cert.X509Certificate> getIntermediateCertificates();
+ method @NonNull public java.security.PrivateKey getPrivateKey();
+ }
+
+ public static class IkeSessionParams.IkeAuthDigitalSignRemoteConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public java.security.cert.X509Certificate getRemoteCaCert();
+ }
+
+ public static class IkeSessionParams.IkeAuthEapConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public android.net.eap.EapSessionConfig getEapConfig();
+ }
+
+ public static class IkeSessionParams.IkeAuthPskConfig extends android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig {
+ method @NonNull public byte[] getPsk();
+ }
+
public final class IkeTrafficSelector {
ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
field public final int endPort;
@@ -4663,6 +4720,7 @@
}
public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
+ method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest> getConfigurationRequests();
}
public static final class TunnelModeChildSessionParams.Builder {
@@ -4680,6 +4738,39 @@
method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
}
+ public static interface TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet6Address getAddress();
+ method public int getPrefixLength();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ method @Nullable public java.net.Inet6Address getAddress();
+ }
+
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Subnet extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ }
+
}
package android.net.ipsec.ike.exceptions {
@@ -6081,6 +6172,14 @@
}
+package android.os.ext {
+
+ public class SdkExtensions {
+ method public static int getExtensionVersion(int);
+ }
+
+}
+
package android.os.image {
public class DynamicSystemClient {
@@ -7825,6 +7924,10 @@
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);
@@ -8151,6 +8254,7 @@
field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
+ field public static final int UNACCEPTABLE_NETWORK_PARAMETER = 65538; // 0x10002
field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
field public static final int UNKNOWN = 65536; // 0x10000
field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index c64e3d8..432a5fd 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -144,6 +144,16 @@
ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+PublicTypedef: android.content.integrity.AtomicFormula.Key: Don't expose @IntDef: @Key must be hidden.
+
+PublicTypedef: android.content.integrity.AtomicFormula.Operator: Don't expose @IntDef: @Operator must be hidden.
+
+PublicTypedef: android.content.integrity.CompoundFormula.Connector: Don't expose @IntDef: @Connector must be hidden.
+
+PublicTypedef: android.content.integrity.Formula.Tag: Don't expose @IntDef: @Tag must be hidden.
+
+PublicTypedef: android.content.integrity.Rule.Effect: Don't expose @IntDef: @Effect must be hidden.
+
SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index bf21ce7..3af392c 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -2444,6 +2444,12 @@
ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
+PublicTypedef: android.os.HwParcel.Status: Don't expose @IntDef: @Status must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: Don't expose @IntDef: @MmTelCapability must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: Don't expose @IntDef: @ProcessCallResult must be hidden.
+
RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 1173d57..3a26063 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -22,6 +22,7 @@
"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 0000000..c8e5a4a
--- /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/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 471606da..55f92be 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -56,6 +56,7 @@
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 dd02af7..4a89a12 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -166,7 +166,12 @@
}
/** 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 49187dc..323c7d1 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.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 @@
@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 @@
/**
* 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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
/**
* 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 @@
}
/**
- * 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 @@
/**
* 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 @@
* @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/content/Intent.java b/core/java/android/content/Intent.java
index 2a17800..e9a4762 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3995,9 +3995,15 @@
* Broadcast Action: The sim card state has changed.
* For more details see TelephonyIntents.ACTION_SIM_STATE_CHANGED. This is here
* because TelephonyIntents is an internal class.
- * @hide
+ * The intent will have following extras.</p>
+ * <p>
+ * @see #EXTRA_SIM_STATE
+ * @see #EXTRA_SIM_LOCKED_REASON
+ *
* @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or
* {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ *
+ * @hide
*/
@Deprecated
@SystemApi
@@ -4005,6 +4011,170 @@
public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
/**
+ * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE.
+ * This will have one of the following intent values.
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_NOT_READY
+ * @see #SIM_STATE_ABSENT
+ * @see #SIM_STATE_PRESENT
+ * @see #SIM_STATE_CARD_IO_ERROR
+ * @see #SIM_STATE_CARD_RESTRICTED
+ * @see #SIM_STATE_LOCKED
+ * @see #SIM_STATE_READY
+ * @see #SIM_STATE_IMSI
+ * @see #SIM_STATE_LOADED
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String EXTRA_SIM_STATE = "ss";
+
+ /**
+ * The intent value UNKNOWN represents the SIM state unknown
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_UNKNOWN = "UNKNOWN";
+
+ /**
+ * The intent value NOT_READY means that the SIM is not ready eg. radio is off or powering on
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_NOT_READY = "NOT_READY";
+
+ /**
+ * The intent value ABSENT means the SIM card is missing
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_ABSENT = "ABSENT";
+
+ /**
+ * The intent value PRESENT means the device has a SIM card inserted
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_PRESENT = "PRESENT";
+
+ /**
+ * The intent value CARD_IO_ERROR means for three consecutive times there was SIM IO error
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ static public final String SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR";
+
+ /**
+ * The intent value CARD_RESTRICTED means card is present but not usable due to carrier
+ * restrictions
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ static public final String SIM_STATE_CARD_RESTRICTED = "CARD_RESTRICTED";
+
+ /**
+ * The intent value LOCKED means the SIM is locked by PIN or by network
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_LOCKED = "LOCKED";
+
+ /**
+ * The intent value READY means the SIM is ready to be accessed
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_READY = "READY";
+
+ /**
+ * The intent value IMSI means the SIM IMSI is ready in property
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_IMSI = "IMSI";
+
+ /**
+ * The intent value LOADED means all SIM records, including IMSI, are loaded
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_STATE_LOADED = "LOADED";
+
+ /**
+ * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for broadcasting SIM STATE.
+ * This extra will have one of the following intent values.
+ * <p>
+ * @see #SIM_LOCKED_ON_PIN
+ * @see #SIM_LOCKED_ON_PUK
+ * @see #SIM_LOCKED_NETWORK
+ * @see #SIM_ABSENT_ON_PERM_DISABLED
+ *
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String EXTRA_SIM_LOCKED_REASON = "reason";
+
+ /**
+ * The intent value PIN means the SIM is locked on PIN1
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_ON_PIN = "PIN";
+
+ /**
+ * The intent value PUK means the SIM is locked on PUK1
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ /* PUK means ICC is locked on PUK1 */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_ON_PUK = "PUK";
+
+ /**
+ * The intent value NETWORK means the SIM is locked on NETWORK PERSONALIZATION
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_LOCKED_NETWORK = "NETWORK";
+
+ /**
+ * The intent value PERM_DISABLED means SIM is permanently disabled due to puk fails
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+
+ /**
* Broadcast Action: indicate that the phone service state has changed.
* The intent will have the following extra values:</p>
* <p>
diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl
index c02cc6a..5031fba 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/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c9a999c..1ae44e1 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -20,8 +20,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.google.android.collect.Sets;
-
import java.util.HashSet;
/**
@@ -32,7 +30,7 @@
public class InterfaceConfiguration implements Parcelable {
private String mHwAddr;
private LinkAddress mAddr;
- private HashSet<String> mFlags = Sets.newHashSet();
+ private HashSet<String> mFlags = new HashSet<>();
// Must be kept in sync with constant in INetd.aidl
private static final String FLAG_UP = "up";
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 4270740..471b23e 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 @@
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 450bfae..1130f1d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -519,11 +519,12 @@
* @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 @@
@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 @@
@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/Trace.java b/core/java/android/os/Trace.java
index 1456a73..e132c11 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -21,6 +21,7 @@
import com.android.internal.os.Zygote;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
/**
@@ -107,12 +108,15 @@
private static final int MAX_SECTION_NAME_LEN = 127;
// Must be volatile to avoid word tearing.
+ // This is only kept in case any apps get this by reflection but do not
+ // check the return value for null.
@UnsupportedAppUsage
private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
private static int sZygoteDebugFlags = 0;
@UnsupportedAppUsage
+ @CriticalNative
private static native long nativeGetEnabledTags();
private static native void nativeSetAppTracingAllowed(boolean allowed);
private static native void nativeSetTracingEnabled(boolean allowed);
@@ -128,47 +132,10 @@
@FastNative
private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
- static {
- // We configure two separate change callbacks, one in Trace.cpp and one here. The
- // native callback reads the tags from the system property, and this callback
- // reads the value that the native code retrieved. It's essential that the native
- // callback executes first.
- //
- // The system provides ordering through a priority level. Callbacks made through
- // SystemProperties.addChangeCallback currently have a negative priority, while
- // our native code is using a priority of zero.
- SystemProperties.addChangeCallback(() -> {
- cacheEnabledTags();
- if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
- traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1);
- }
- });
- }
-
private Trace() {
}
/**
- * Caches a copy of the enabled-tag bits. The "master" copy is held by the native code,
- * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property.
- * <p>
- * If the native code hasn't yet read the property, we will cause it to do one-time
- * initialization. We don't want to do this during class init, because this class is
- * preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote
- * doesn't see the system-property update broadcasts.)
- * <p>
- * We want to defer initialization until the first use by an app, post-zygote.
- * <p>
- * We're okay if multiple threads call here simultaneously -- the native state is
- * synchronized, and sEnabledTags is volatile (prevents word tearing).
- */
- private static long cacheEnabledTags() {
- long tags = nativeGetEnabledTags();
- sEnabledTags = tags;
- return tags;
- }
-
- /**
* Returns true if a trace tag is enabled.
*
* @param traceTag The trace tag to check.
@@ -178,10 +145,7 @@
*/
@UnsupportedAppUsage
public static boolean isTagEnabled(long traceTag) {
- long tags = sEnabledTags;
- if (tags == TRACE_TAG_NOT_READY) {
- tags = cacheEnabledTags();
- }
+ long tags = nativeGetEnabledTags();
return (tags & traceTag) != 0;
}
@@ -210,10 +174,6 @@
@UnsupportedAppUsage
public static void setAppTracingAllowed(boolean allowed) {
nativeSetAppTracingAllowed(allowed);
-
- // Setting whether app tracing is allowed may change the tags, so we update the cached
- // tags here.
- cacheEnabledTags();
}
/**
@@ -227,10 +187,6 @@
public static void setTracingEnabled(boolean enabled, int debugFlags) {
nativeSetTracingEnabled(enabled);
sZygoteDebugFlags = debugFlags;
-
- // Setting whether tracing is enabled may change the tags, so we update the cached tags
- // here.
- cacheEnabledTags();
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 3a55aff..c2d3ecc 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -306,6 +306,8 @@
* @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 @@
@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 @@
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 @@
* @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 @@
boolean startChildZygote,
@Nullable String packageName,
boolean useUsapPool,
+ @Nullable long[] disabledCompatChanges,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
@@ -623,6 +628,21 @@
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 @@
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/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
new file mode 100644
index 0000000..8446253
--- /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/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 308c8b3..f87a7c5 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -25,8 +25,6 @@
import android.net.NetworkCapabilities;
import android.os.Binder;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Annotation.ApnType;
diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java
index 4cc71fd..971a47d 100644
--- a/core/java/android/text/AlteredCharSequence.java
+++ b/core/java/android/text/AlteredCharSequence.java
@@ -16,12 +16,14 @@
package android.text;
-// XXX should this really be in the public API at all?
/**
* An AlteredCharSequence is a CharSequence that is largely mirrored from
* another CharSequence, except that a specified range of characters are
* mirrored from a different char array instead.
+ *
+ * @deprecated The functionality this class offers is easily implemented outside the framework.
*/
+@Deprecated
public class AlteredCharSequence
implements CharSequence, GetChars
{
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index e94b800..90625183 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -56,8 +56,12 @@
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 0000000..c39a6c9
--- /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/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 8b5659b..0203430 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -17,9 +17,11 @@
package android.util;
import android.annotation.UnsupportedAppUsage;
+import android.os.SystemClock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -33,10 +35,22 @@
private final Deque<String> mLog;
private final int mMaxLines;
+ /**
+ * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log
+ * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is
+ * useful when logging behavior that modifies device time zone or system clock.
+ */
+ private final boolean mUseLocalTimestamps;
+
@UnsupportedAppUsage
public LocalLog(int maxLines) {
+ this(maxLines, true /* useLocalTimestamps */);
+ }
+
+ public LocalLog(int maxLines, boolean useLocalTimestamps) {
mMaxLines = Math.max(0, maxLines);
mLog = new ArrayDeque<>(mMaxLines);
+ mUseLocalTimestamps = useLocalTimestamps;
}
@UnsupportedAppUsage
@@ -44,7 +58,14 @@
if (mMaxLines <= 0) {
return;
}
- append(String.format("%s - %s", LocalDateTime.now(), msg));
+ final String logLine;
+ if (mUseLocalTimestamps) {
+ logLine = String.format("%s - %s", LocalDateTime.now(), msg);
+ } else {
+ logLine = String.format(
+ "%s / %s - %s", SystemClock.elapsedRealtime(), Instant.now(), msg);
+ }
+ append(logLine);
}
private synchronized void append(String logLine) {
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index a211871..fa823c4 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -367,8 +367,8 @@
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 @@
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 f0e7796..790d7f7 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.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 @@
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 00ab45e..33adec1 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -642,6 +642,7 @@
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 fc55ccf..3915ba2 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -210,6 +210,12 @@
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 @@
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 b15e1ef..4c37591 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -502,6 +502,7 @@
} 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 93e6102..7b77a92 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -547,6 +547,7 @@
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+ parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
@@ -972,14 +973,16 @@
*
* 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 @@
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
- return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+ return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
+ classLoader);
}
/**
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 731b93c..3fff5c2 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -102,6 +102,24 @@
}
/**
+ * Ensures that an string reference passed as a parameter to the calling method is not empty.
+ *
+ * @param string an string reference
+ * @param messageTemplate a printf-style message template to use if the check fails; will be
+ * converted to a string using {@link String#format(String, Object...)}
+ * @param messageArgs arguments for {@code messageTemplate}
+ * @return the string reference that was validated
+ * @throws IllegalArgumentException if {@code string} is empty
+ */
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(
+ final T string, final String messageTemplate, final Object... messageArgs) {
+ if (TextUtils.isEmpty(string)) {
+ throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
+ }
+ return string;
+ }
+
+ /**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index bd82bd9..0f7611a 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -50,10 +50,6 @@
callback(buffer.data());
}
-static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv*, jclass) {
- return atrace_get_enabled_tags();
-}
-
static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass,
jlong tag, jstring nameStr, jlong value) {
withString(env, nameStr, [tag, value](char* str) {
@@ -96,9 +92,6 @@
static const JNINativeMethod gTraceMethods[] = {
/* name, signature, funcPtr */
- { "nativeGetEnabledTags",
- "()J",
- (void*)android_os_Trace_nativeGetEnabledTags },
{ "nativeSetAppTracingAllowed",
"(Z)V",
(void*)android_os_Trace_nativeSetAppTracingAllowed },
@@ -123,6 +116,11 @@
{ "nativeAsyncTraceEnd",
"(JLjava/lang/String;I)V",
(void*)android_os_Trace_nativeAsyncTraceEnd },
+
+ // ----------- @CriticalNative ----------------
+ { "nativeGetEnabledTags",
+ "()J",
+ (void*)atrace_get_enabled_tags },
};
int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index fd6984b..0c21076 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -37,6 +37,8 @@
"/apex/com.android.ipsec/javalib/ike.jar",
"/apex/com.android.media/javalib/updatable-media.jar",
"/apex/com.android.sdkext/javalib/framework-sdkext.jar",
+ "/apex/com.android.telephony/javalib/telephony-common.jar",
+ "/apex/com.android.telephony/javalib/ims-common.jar",
"/dev/null",
"/dev/socket/zygote",
"/dev/socket/zygote_secondary",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 68f3c2e..a35c4db 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -633,10 +633,9 @@
<protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
- <!-- NETWORK_SET_TIME / NETWORK_SET_TIMEZONE moved from com.android.phone to system server.
- They should ultimately be removed. -->
+ <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be
+ removed. -->
<protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
- <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" />
<!-- For tether entitlement recheck-->
<protected-broadcast
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index b906d84..ed613c3 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -176,14 +176,12 @@
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 1670d49..4d4f447 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -24,6 +24,7 @@
],
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 0000000..d86c7b7
--- /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/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 6cdcb5e..d4861cd 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -29,14 +29,24 @@
@LargeTest
public class LocalLogTest extends TestCase {
- public void testA() {
+ public void testA_localTimestamps() {
+ boolean localTimestamps = true;
+ doTestA(localTimestamps);
+ }
+
+ public void testA_nonLocalTimestamps() {
+ boolean localTimestamps = false;
+ doTestA(localTimestamps);
+ }
+
+ private void doTestA(boolean localTimestamps) {
String[] lines = {
- "foo",
- "bar",
- "baz"
+ "foo",
+ "bar",
+ "baz"
};
String[] want = lines;
- testcase(new LocalLog(10), lines, want);
+ testcase(new LocalLog(10, localTimestamps), lines, want);
}
public void testB() {
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
old mode 100644
new mode 100755
index bd05184..f90c504
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -38,4 +38,5 @@
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
old mode 100644
new mode 100755
index ff69779..5c11ed9b
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -173,6 +173,12 @@
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 @@
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 @@
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 @@
}
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 96aee51..a2bd210 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 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 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 55765dd..9c896c8 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 @@
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 @@
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 @@
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 0d972c5..2f34b2b 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 @@
}
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 56be3bb..abfee1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -164,9 +164,7 @@
public void disconnect() {
synchronized (mProfileLock) {
- for (LocalBluetoothProfile profile : mProfiles) {
- disconnect(profile);
- }
+ mLocalAdapter.disconnectAllEnabledProfiles(mDevice);
}
// Disconnect PBAP server in case its connected
// This is to ensure all the profiles are disconnected as some CK/Hs do not
@@ -645,12 +643,8 @@
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 9f7b718..560cb3b 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 @@
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 @@
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 @@
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 ebaeb74..58655a2 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 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 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 860b77d..a372e23 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 @@
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 @@
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 @@
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 6d874ab..975a1e6 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 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 d4dda32..95139a1 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 @@
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 @@
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 @@
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 b2a9a6a..31a0eea 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 @@
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 @@
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 @@
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 7162121..387bae1 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 e1e5dbe..8e3f3ed 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 @@
}
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 a2da4fb..4ea0df6 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 @@
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 @@
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 9b733f2..0ca4d61 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 @@
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 @@
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 @@
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/Tethering/Android.bp b/packages/Tethering/Android.bp
index 7e8721d..3c953b3 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -31,6 +31,7 @@
"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 eb0d443..7fb286b 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 @@
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 @@
*/
@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 @@
*/
@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 @@
*/
@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 @@
// 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 @@
* {@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 @@
// 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 ef40a35..3b56607 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 @@
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 f991d7b..284a2f2 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 a7be587..e14e1df 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 aad2ad19..54cf6ce 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 2768c18..539eb1a 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 ef03d83..f945d0f 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 d2dac35..9677a7d 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 57e859e..96e2072 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 fc09d2e..d17f06f 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 4e75e00..725303d 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 753c117..87b1bdf 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5573,7 +5573,7 @@
* @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.
@@ -5596,7 +5596,7 @@
ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
mDnsResolver, mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
- nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
+ nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSSID() : extraInfo;
@@ -5864,6 +5864,19 @@
return INetd.PERMISSION_NONE;
}
+ private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities newNc) {
+ final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+ final int newPermission = getNetworkPermission(newNc);
+ if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
+ try {
+ mNMS.setNetworkPermission(nai.network.netId, newPermission);
+ } catch (RemoteException e) {
+ loge("Exception in setNetworkPermission: " + e);
+ }
+ }
+ }
+
/**
* Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
@@ -5935,26 +5948,12 @@
* @param nai the network having its capabilities updated.
* @param nc the new network capabilities.
*/
- private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) {
+ private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities nc) {
NetworkCapabilities newNc = mixInCapabilities(nai, nc);
-
if (Objects.equals(nai.networkCapabilities, newNc)) return;
-
- final int oldPermission = getNetworkPermission(nai.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
- try {
- mNMS.setNetworkPermission(nai.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
- final NetworkCapabilities prevNc;
- synchronized (nai) {
- prevNc = nai.networkCapabilities;
- nai.setNetworkCapabilities(newNc);
- }
+ updateNetworkPermissions(nai, nc);
+ final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
updateUids(nai, prevNc, newNc);
@@ -5963,7 +5962,7 @@
// the change we're processing can't affect any requests, it can only affect the listens
// on this network. We might have been called by rematchNetworkAndRequests when a
// network changed foreground state.
- processListenRequests(nai, true);
+ processListenRequests(nai);
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
@@ -6271,8 +6270,14 @@
updateAllVpnsCapabilities();
}
- private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
+ private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
// For consistency with previous behaviour, send onLost callbacks before onAvailable.
+ processNewlyLostListenRequests(nai);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ processNewlySatisfiedListenRequests(nai);
+ }
+
+ private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
@@ -6281,11 +6286,9 @@
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
}
}
+ }
- if (capabilitiesChanged) {
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
+ private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
@@ -6296,6 +6299,52 @@
}
}
+ // An accumulator class to gather the list of changes that result from a rematch.
+ // TODO : enrich to represent an entire set of changes to apply.
+ private static class NetworkReassignment {
+ static class NetworkBgStatePair {
+ @NonNull final NetworkAgentInfo mNetwork;
+ final boolean mOldBackground;
+ NetworkBgStatePair(@NonNull final NetworkAgentInfo network,
+ final boolean oldBackground) {
+ mNetwork = network;
+ mOldBackground = oldBackground;
+ }
+ }
+
+ static class RequestReassignment {
+ @NonNull public final NetworkRequestInfo mRequest;
+ @Nullable public final NetworkAgentInfo mOldNetwork;
+ @Nullable public final NetworkAgentInfo mNewNetwork;
+ RequestReassignment(@NonNull final NetworkRequestInfo request,
+ @Nullable final NetworkAgentInfo oldNetwork,
+ @Nullable final NetworkAgentInfo newNetwork) {
+ mRequest = request;
+ mOldNetwork = oldNetwork;
+ mNewNetwork = newNetwork;
+ }
+ }
+
+ @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>();
+ @NonNull private final List<RequestReassignment> mReassignments = new ArrayList<>();
+
+ @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() {
+ return mRematchedNetworks;
+ }
+
+ @NonNull Iterable<RequestReassignment> getRequestReassignments() {
+ return mReassignments;
+ }
+
+ void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
+ mReassignments.add(reassignment);
+ }
+
+ void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
+ mRematchedNetworks.add(network);
+ }
+ }
+
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@NonNull final NetworkAgentInfo newNetwork) {
final int score = newNetwork.getCurrentScore();
@@ -6341,8 +6390,8 @@
// needed. A network is needed if it is the best network for
// one or more NetworkRequests, or if it is a VPN.
//
- // - Tears down newNetwork if it just became validated
- // but turns out to be unneeded.
+ // - Writes into the passed reassignment object all changes that should be done for
+ // rematching this network with all requests, to be applied later.
//
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
@@ -6350,29 +6399,29 @@
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// as it performs better by a factor of the number of Networks.
//
+ // TODO : stop writing to the passed reassignment. This is temporarily more useful, but
+ // it's unidiomatic Java and it's hard to read.
+ //
+ // @param changes a currently-building list of changes to write to
// @param newNetwork is the network to be matched against NetworkRequests.
// @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+ private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes,
+ @NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
- final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
- final int score = newNetwork.getCurrentScore();
+ changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
+ newNetwork.isBackgroundNetwork()));
if (VDBG || DDBG) log("rematching " + newNetwork.name());
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
computeRequestReassignmentForNetwork(newNetwork);
- NetworkCapabilities nc = newNetwork.networkCapabilities;
- if (VDBG) log(" network has: " + nc);
-
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
- final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
- final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
reassignedRequests.entrySet()) {
final NetworkRequestInfo nri = entry.getKey();
@@ -6386,7 +6435,6 @@
}
previousSatisfier.removeRequest(nri.request.requestId);
previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
- removedRequests.add(previousSatisfier);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
@@ -6395,7 +6443,8 @@
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- addedRequests.add(nri);
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
// Tell NetworkFactories about the new score, so they can stop
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have a lot of requests for this
@@ -6452,89 +6501,6 @@
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
}
-
- if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed requestable capabilities during rematch: %s -> %s",
- newNetwork.name(), nc, newNetwork.networkCapabilities));
- }
- if (newNetwork.getCurrentScore() != score) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed score during rematch: %d -> %d",
- newNetwork.name(), score, newNetwork.getCurrentScore()));
- }
-
- // Notify requested networks are available after the default net is switched, but
- // before LegacyTypeTracker sends legacy broadcasts
- for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
- // Second pass: process all listens.
- if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
- // TODO : most of the following is useless because the only thing that changed
- // here is whether the network is a background network. Clean this up.
-
- NetworkCapabilities newNc = mixInCapabilities(newNetwork,
- newNetwork.networkCapabilities);
-
- if (Objects.equals(newNetwork.networkCapabilities, newNc)) return;
-
- final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && newNetwork.created && !newNetwork.isVPN()) {
- try {
- mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
- final NetworkCapabilities prevNc;
- synchronized (newNetwork) {
- prevNc = newNetwork.networkCapabilities;
- newNetwork.setNetworkCapabilities(newNc);
- }
-
- updateUids(newNetwork, prevNc, newNc);
-
- if (newNetwork.getCurrentScore() == score
- && newNc.equalRequestableCapabilities(prevNc)) {
- // If the requestable capabilities haven't changed, and the score hasn't changed,
- // then the change we're processing can't affect any requests, it can only affect
- // the listens on this network.
- processListenRequests(newNetwork, true);
- } else {
- rematchAllNetworksAndRequests();
- notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
- if (prevNc != null) {
- final boolean oldMetered = prevNc.isMetered();
- final boolean newMetered = newNc.isMetered();
- final boolean meteredChanged = oldMetered != newMetered;
-
- if (meteredChanged) {
- maybeNotifyNetworkBlocked(newNetwork, oldMetered, newMetered,
- mRestrictBackground, mRestrictBackground);
- }
-
- final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
- != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-
- // Report changes that are interesting for network statistics tracking.
- if (meteredChanged || roamingChanged) {
- notifyIfacesChangedForNetworkStats();
- }
- }
-
- if (!newNc.hasTransport(TRANSPORT_VPN)) {
- // Tell VPNs about updated capabilities, since they may need to
- // bubble those changes through.
- updateAllVpnsCapabilities();
- }
-
- } else {
- processListenRequests(newNetwork, false);
- }
}
/**
@@ -6556,12 +6522,33 @@
// scoring network and then a higher scoring network, which could produce multiple
// callbacks.
Arrays.sort(nais);
+ final NetworkReassignment changes = new NetworkReassignment();
for (final NetworkAgentInfo nai : nais) {
- rematchNetworkAndRequests(nai, now);
+ rematchNetworkAndRequests(changes, nai, now);
}
final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ // Notify requested networks are available after the default net is switched, but
+ // before LegacyTypeTracker sends legacy broadcasts
+ for (final NetworkReassignment.RequestReassignment event :
+ changes.getRequestReassignments()) {
+ if (null != event.mNewNetwork) {
+ notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ }
+ }
+
+ for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) {
+ // Process listen requests and update capabilities if the background state has
+ // changed for this network. For consistency with previous behavior, send onLost
+ // callbacks before onAvailable.
+ processNewlyLostListenRequests(event.mNetwork);
+ if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) {
+ applyBackgroundChangeForRematch(event.mNetwork);
+ }
+ processNewlySatisfiedListenRequests(event.mNetwork);
+ }
+
for (final NetworkAgentInfo nai : nais) {
// Rematching may have altered the linger state of some networks, so update all linger
// timers. updateLingerState reads the state from the network agent and does nothing
@@ -6593,6 +6580,24 @@
}
}
+ /**
+ * Apply a change in background state resulting from rematching networks with requests.
+ *
+ * During rematch, a network may change background states by starting to satisfy or stopping
+ * to satisfy a foreground request. Listens don't count for this. When a network changes
+ * background states, its capabilities need to be updated and callbacks fired for the
+ * capability change.
+ *
+ * @param nai The network that changed background states
+ */
+ private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) {
+ final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities);
+ if (Objects.equals(nai.networkCapabilities, newNc)) return;
+ updateNetworkPermissions(nai, newNc);
+ nai.getAndSetNetworkCapabilities(newNc);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ }
+
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
@Nullable final NetworkAgentInfo oldDefaultNetwork,
@Nullable final NetworkAgentInfo newDefaultNetwork,
@@ -6719,9 +6724,8 @@
// NetworkCapabilities need to be set before sending the private DNS config to
// NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
- synchronized (networkAgent) {
- networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities);
- }
+ networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
+
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
null);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 840b7af..0d496b6 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,6 +58,7 @@
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.TetherConfigParcel;
import android.net.TetherStatsParcel;
import android.net.UidRange;
import android.net.UidRangeParcel;
@@ -1023,7 +1024,10 @@
NetworkStack.checkNetworkStackPermission(mContext);
// an odd number of addrs will fail
try {
- mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange);
+ final TetherConfigParcel config = new TetherConfigParcel();
+ config.usingLegacyDnsProxy = usingLegacyDnsProxy;
+ config.dhcpRanges = dhcpRange;
+ mNetdService.tetherStartWithConfiguration(config);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8436e38..be95456 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -72,7 +72,6 @@
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.PhoneConstantConversions;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyPermissions;
@@ -359,7 +358,7 @@
SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.getDefaultSubscriptionId());
int newDefaultPhoneId = intent.getIntExtra(
- PhoneConstants.PHONE_KEY,
+ SubscriptionManager.EXTRA_SLOT_INDEX,
SubscriptionManager.getPhoneId(newDefaultSubId));
if (DBG) {
log("onReceive:current mDefaultSubId=" + mDefaultSubId
@@ -450,9 +449,9 @@
mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
- mCallQuality[i] = new CallQuality();
+ mCallQuality[i] = createCallQuality();
mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = new PreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -547,9 +546,9 @@
mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
- mCallQuality[i] = new CallQuality();
+ mCallQuality[i] = createCallQuality();
mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = new PreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -1611,8 +1610,6 @@
}
broadcastDataConnectionStateChanged(state, isDataAllowed, apn, apnType, linkProperties,
networkCapabilities, roaming, subId);
- broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn,
- linkProperties, DataFailCause.NONE);
}
public void notifyDataConnectionFailed(String apnType) {
@@ -1652,9 +1649,6 @@
handleRemoveListLocked();
}
broadcastDataConnectionFailed(apnType, subId);
- broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, null, null,
- DataFailCause.NONE);
}
public void notifyCellLocation(Bundle cellLocation) {
@@ -1744,7 +1738,7 @@
if (mPreciseCallState[phoneId].getForegroundCallState()
!= PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- mCallQuality[phoneId] = new CallQuality();
+ mCallQuality[phoneId] = createCallQuality();
}
mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
mCallNetworkType[phoneId], mCallQuality[phoneId]);
@@ -1772,8 +1766,6 @@
}
handleRemoveListLocked();
}
- broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState,
- backgroundCallState);
}
public void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
@@ -1855,8 +1847,6 @@
handleRemoveListLocked();
}
- broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, null, failCause);
}
@Override
@@ -2186,6 +2176,16 @@
// the legacy intent broadcasting
//
+ // Legacy intent action.
+ /** Fired when a subscription's phone state changes. */
+ private static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED =
+ "android.intent.action.SUBSCRIPTION_PHONE_STATE";
+
+ // Legacy intent extra keys, copied from PhoneConstants.
+ // Used in legacy intents sent here, for backward compatibility.
+ private static final String PHONE_CONSTANTS_SLOT_KEY = "slot";
+ private static final String PHONE_CONSTANTS_SUBSCRIPTION_KEY = "subscription";
+
private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) {
long ident = Binder.clearCallingIdentity();
try {
@@ -2202,9 +2202,10 @@
state.fillInNotifierBundle(data);
intent.putExtras(data);
// Pass the subscription along with the intent.
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -2223,8 +2224,8 @@
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -2254,19 +2255,19 @@
}
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- intent.putExtra(PhoneConstants.STATE_KEY,
- PhoneConstantConversions.convertCallState(state).toString());
+ intent.putExtra(TelephonyManager.EXTRA_STATE, callStateToString(state));
// If a valid subId was specified, we should fire off a subId-specific state
// change intent and include the subId.
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.setAction(ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
}
// If the phoneId is invalid, the broadcast is for overall call state.
if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
- intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
+ intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
}
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
@@ -2288,6 +2289,18 @@
android.Manifest.permission.READ_CALL_LOG});
}
+ /** Converts TelephonyManager#CALL_STATE_* to TelephonyManager#EXTRA_STATE_*. */
+ private static String callStateToString(int callState) {
+ switch (callState) {
+ case TelephonyManager.CALL_STATE_RINGING:
+ return TelephonyManager.EXTRA_STATE_RINGING;
+ case TelephonyManager.CALL_STATE_OFFHOOK:
+ return TelephonyManager.EXTRA_STATE_OFFHOOK;
+ default:
+ return TelephonyManager.EXTRA_STATE_IDLE;
+ }
+ }
+
private void broadcastDataConnectionStateChanged(int state, boolean isDataAllowed, String apn,
String apnType, LinkProperties linkProperties,
NetworkCapabilities networkCapabilities,
@@ -2296,8 +2309,7 @@
// status bar takes care of that after taking into account all of the
// required info.
Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- intent.putExtra(PhoneConstants.STATE_KEY,
- PhoneConstantConversions.convertDataState(state).toString());
+ intent.putExtra(TelephonyManager.EXTRA_STATE, dataStateToString(state));
if (!isDataAllowed) {
intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
}
@@ -2315,44 +2327,17 @@
intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
private void broadcastDataConnectionFailed(String apnType, int subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
- int backgroundCallState) {
- Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
- intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
- intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
- intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_PRECISE_PHONE_STATE);
- }
-
- private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
- String apnType, String apn, LinkProperties linkProperties,
- @DataFailureCause int failCause) {
- Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
- intent.putExtra(PhoneConstants.STATE_KEY, state);
- intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
- if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
- if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
- if (linkProperties != null) {
- intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
- }
- intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
-
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_PRECISE_PHONE_STATE);
- }
-
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
if (checkNotifyPermission()) {
return;
@@ -2681,11 +2666,11 @@
}
/**
- * Convert data state to string
+ * Convert TelephonyManager.DATA_* to string.
*
* @return The data state in string format.
*/
- private String dataStateToString(@TelephonyManager.DataState int state) {
+ private static String dataStateToString(int state) {
switch (state) {
case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED";
case TelephonyManager.DATA_CONNECTING: return "CONNECTING";
@@ -2748,4 +2733,9 @@
return "UNKNOWN";
}
}
+
+ /** Returns a new CallQuality object with default values. */
+ private static CallQuality createCallQuality() {
+ return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5ffdf02..35774ed 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59070c7..b406ce6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2875,6 +2875,12 @@
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
+ if (toggleValue.equals("reset-all")) {
+ final String packageName = getNextArgRequired();
+ pw.println("Reset all changes for " + packageName + " to default value.");
+ platformCompat.clearOverrides(packageName);
+ return 0;
+ }
long changeId;
String changeIdString = getNextArgRequired();
try {
@@ -3233,9 +3239,14 @@
pw.println(" without restarting any processes.");
pw.println(" write");
pw.println(" Write all pending state to storage.");
- pw.println(" compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
- pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
- pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" compat [COMMAND] [...]: sub-commands for toggling app-compat changes.");
+ pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+ pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" reset-all <PACKAGE_NAME>");
+ pw.println(" Removes all existing overrides for all changes for ");
+ pw.println(" <PACKAGE_NAME> (back to default behaviour).");
+ pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
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 0000000..cacf676
--- /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 a2670d8..3b8d39b 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.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.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 @@
/**
* 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 @@
// 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 @@
private boolean mHaveDisplaySize;
- private static Object sLmkdSocketLock = new Object();
+ private static LmkdConnection sLmkdConnection = null;
- @GuardedBy("sLmkdSocketLock")
- private static LocalSocket sLmkdSocket;
-
- @GuardedBy("sLmkdSocketLock")
- private static OutputStream sLmkdOutputStream;
-
- @GuardedBy("sLmkdSocketLock")
- private static InputStream sLmkdInputStream;
+ private boolean mOomLevelsSet = false;
/**
* Temporary to avoid allocations. Protected by main lock.
@@ -369,6 +358,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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());
- } 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;
+ // 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 reading from lowmemorykiller socket");
+ return false;
}
-
- IoUtils.closeQuietly(sLmkdSocket);
- sLmkdSocket = null;
- return false;
+ return true;
}
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 @@
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 @@
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 @@
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 @@
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 ea30842..8c1a0d3 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 @@
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 37add3d..135f199d 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 @@
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 @@
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 @@
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 @@
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/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9f1a6bd..36332c0 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -295,6 +295,7 @@
&& mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
+ broadcast = false;
break;
default:
// do not broadcast CONNECTING or invalid state
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index 27f11ff..1b1c546 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -31,8 +31,6 @@
import android.util.Log;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.server.am.BatteryStatsService;
public class DataConnectionStats extends BroadcastReceiver {
@@ -44,7 +42,7 @@
private final Handler mListenerHandler;
private final PhoneStateListener mPhoneStateListener;
- private IccCardConstants.State mSimState = IccCardConstants.State.READY;
+ private int mSimState = TelephonyManager.SIM_STATE_READY;
private SignalStrength mSignalStrength;
private ServiceState mServiceState;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
@@ -66,7 +64,7 @@
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
IntentFilter filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
@@ -75,7 +73,7 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+ if (action.equals(Intent.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
notePhoneDataConnectionState();
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
@@ -88,8 +86,8 @@
if (mServiceState == null) {
return;
}
- boolean simReadyOrUnknown = mSimState == IccCardConstants.State.READY
- || mSimState == IccCardConstants.State.UNKNOWN;
+ boolean simReadyOrUnknown = mSimState == TelephonyManager.SIM_STATE_READY
+ || mSimState == TelephonyManager.SIM_STATE_UNKNOWN;
boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM
&& hasService()
&& mDataState == TelephonyManager.DATA_CONNECTED;
@@ -105,23 +103,23 @@
}
private final void updateSimState(Intent intent) {
- String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
- if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
- mSimState = IccCardConstants.State.ABSENT;
- } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- mSimState = IccCardConstants.State.READY;
- } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+ String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
+ if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
+ mSimState = TelephonyManager.SIM_STATE_ABSENT;
+ } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
+ mSimState = TelephonyManager.SIM_STATE_READY;
+ } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
final String lockedReason =
- intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
- if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PIN_REQUIRED;
- } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PUK_REQUIRED;
+ intent.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
+ if (Intent.SIM_LOCKED_ON_PIN.equals(lockedReason)) {
+ mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED;
+ } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
+ mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED;
} else {
- mSimState = IccCardConstants.State.NETWORK_LOCKED;
+ mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
}
} else {
- mSimState = IccCardConstants.State.UNKNOWN;
+ mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bb7f862..5e085ca 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -291,13 +291,18 @@
*
* <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails,
* the exception is logged but not reported to callers.
+ *
+ * @return the old capabilities of this network.
*/
- public void setNetworkCapabilities(NetworkCapabilities nc) {
+ public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+ @NonNull final NetworkCapabilities nc) {
+ final NetworkCapabilities oldNc = networkCapabilities;
networkCapabilities = nc;
final NetworkMonitorManager nm = mNetworkMonitor;
if (nm != null) {
nm.notifyNetworkCapabilitiesChanged(nc);
}
+ return oldNc;
}
public ConnectivityService connService() {
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
index a91fe77..1cf27ff 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 @@
// 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 52cede2..23b5c14 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 @@
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/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 181a435..3fc8438 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -508,8 +508,10 @@
CarrierConfigManager configManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
- String mccMnc = SubscriptionManager.isValidSubscriptionId(ddSubId)
- ? phone.getSimOperator(ddSubId) : phone.getSimOperator();
+ if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+ phone = phone.createForSubscriptionId(ddSubId);
+ }
+ String mccMnc = phone.getSimOperator();
boolean isKeepLppProfile = false;
if (!TextUtils.isEmpty(mccMnc)) {
if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
@@ -1903,24 +1905,17 @@
String setId = null;
int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+ phone = phone.createForSubscriptionId(ddSubId);
+ }
if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
- if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
- setId = phone.getSubscriberId(ddSubId);
- }
- if (setId == null) {
- setId = phone.getSubscriberId();
- }
+ setId = phone.getSubscriberId();
if (setId != null) {
// This means the framework has the SIM card.
type = AGPS_SETID_TYPE_IMSI;
}
} else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
- if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
- setId = phone.getLine1Number(ddSubId);
- }
- if (setId == null) {
- setId = phone.getLine1Number();
- }
+ setId = phone.getLine1Number();
if (setId != null) {
// This means the framework has the SIM card.
type = AGPS_SETID_TYPE_MSISDN;
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 9b9f4de..f295ed3 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.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 @@
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/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index adcd19e..b3b0029 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -85,6 +85,9 @@
public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
+ public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES =
+ IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
+
private final boolean mIsolated;
private volatile IInstalld mInstalld;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cec5c6d..9791ff3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3136,7 +3136,8 @@
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
- | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
+ | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
}
}
ver.fingerprint = Build.FINGERPRINT;
@@ -10222,7 +10223,9 @@
clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+ if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
+ clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+ }
}
private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -22047,7 +22050,8 @@
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
- | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
+ | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
}
}
}
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 340fe3d..0000000
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ /dev/null
@@ -1,304 +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);
-
- // @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 34400ff..172367a 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.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 @@
@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 @@
@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 0000000..1b1ac6d
--- /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/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index e034ad4..adf6d7e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -20,13 +20,9 @@
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.provider.Settings;
-import com.android.internal.telephony.TelephonyIntents;
-
/**
* The real implementation of {@link TimeZoneDetectorStrategy.Callback}.
*/
@@ -66,16 +62,8 @@
}
@Override
- public void setDeviceTimeZone(String zoneId, boolean sendNetworkBroadcast) {
+ public void setDeviceTimeZone(String zoneId) {
AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
alarmManager.setTimeZone(zoneId);
-
- if (sendNetworkBroadcast) {
- // TODO Nothing in the platform appears to listen for this. Remove it.
- Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra("time-zone", zoneId);
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 5db12c7..b4d8053 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -86,7 +86,7 @@
/**
* Sets the device's time zone.
*/
- void setDeviceTimeZone(@NonNull String zoneId, boolean sendNetworkBroadcast);
+ void setDeviceTimeZone(@NonNull String zoneId);
}
private static final String LOG_TAG = "TimeZoneDetectorStrategy";
@@ -172,7 +172,7 @@
* (for use during debugging).
*/
@NonNull
- private final LocalLog mTimeZoneChangesLog = new LocalLog(30);
+ private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
/**
* A mapping from phoneId to a linked list of phone time zone suggestions (the head being the
@@ -333,7 +333,6 @@
Objects.requireNonNull(newZoneId);
Objects.requireNonNull(cause);
- boolean sendNetworkBroadcast = (origin == ORIGIN_PHONE);
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
if (!mCallback.isAutoTimeZoneDetectionEnabled()) {
@@ -373,12 +372,11 @@
return;
}
- mCallback.setDeviceTimeZone(newZoneId, sendNetworkBroadcast);
+ mCallback.setDeviceTimeZone(newZoneId);
String msg = "Set device time zone."
+ " origin=" + origin
+ ", currentZoneId=" + currentZoneId
+ ", newZoneId=" + newZoneId
- + ", sendNetworkBroadcast" + sendNetworkBroadcast
+ ", cause=" + cause;
if (DBG) {
Slog.d(LOG_TAG, msg);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
old mode 100644
new mode 100755
index 8e66b14..18ed51a
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2943,6 +2943,16 @@
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/coverage/Android.bp b/services/coverage/Android.bp
index 16c9c1b..e4f5464 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 dbe0d81..2f6592b 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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2e4f1e3..2528063 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -40,12 +40,12 @@
import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
-import android.net.Network;
import android.net.NetworkStackClient;
import android.net.TetheringManager;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
+import android.os.Debug;
import android.os.Environment;
import android.os.FactoryTest;
import android.os.FileUtils;
@@ -497,6 +497,24 @@
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
+ // Attach JVMTI agent if this is a debuggable build and the system property is set.
+ if (Build.IS_DEBUGGABLE) {
+ // Property is of the form "library_path=parameters".
+ String jvmtiAgent = SystemProperties.get("persist.sys.dalvik.jvmtiagent");
+ if (!jvmtiAgent.isEmpty()) {
+ int equalIndex = jvmtiAgent.indexOf('=');
+ String libraryPath = jvmtiAgent.substring(0, equalIndex);
+ String parameterList =
+ jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length());
+ // Attach the agent.
+ try {
+ Debug.attachJvmtiAgent(libraryPath, parameterList, null);
+ } catch (Exception e) {
+ Slog.e("System", "*************************************************");
+ Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent);
+ }
+ }
+ }
} finally {
traceEnd(); // InitBeforeStartServices
}
diff --git a/services/midi/Android.bp b/services/midi/Android.bp
index 3745e89..20e0083 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 2dabdb7..3babb0b 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 @@
"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 80a8c75..aad24d7 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 979e891..805858f 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 4e190b6..1ce3e66 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 7a0a28d..0000000
--- 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 84b495f..72a7f50 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 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 @@
private Context mMockContext;
private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
- private Callback mMockCallback;
private TimeDetectorService mTimeDetectorService;
private HandlerThread mHandlerThread;
@@ -68,12 +65,10 @@
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 @@
@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 0000000..1aa3d8f
--- /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/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
index 270436d..cb49fef 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
@@ -50,7 +50,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
-import java.util.Objects;
/**
* White-box unit tests for {@link TimeZoneDetectorStrategy}.
@@ -445,8 +444,7 @@
static class FakeTimeZoneDetectorStrategyCallback implements TimeZoneDetectorStrategy.Callback {
private boolean mAutoTimeZoneDetectionEnabled;
- private TestState<TimeZoneChange> mTimeZoneChanges = new TestState<>();
- private String mTimeZoneId;
+ private TestState<String> mTimeZoneId = new TestState<>();
@Override
public boolean isAutoTimeZoneDetectionEnabled() {
@@ -460,13 +458,12 @@
@Override
public String getDeviceTimeZone() {
- return mTimeZoneId;
+ return mTimeZoneId.getLatest();
}
@Override
- public void setDeviceTimeZone(String zoneId, boolean withNetworkBroadcast) {
- mTimeZoneId = zoneId;
- mTimeZoneChanges.set(new TimeZoneChange(zoneId, withNetworkBroadcast));
+ public void setDeviceTimeZone(String zoneId) {
+ mTimeZoneId.set(zoneId);
}
void initializeAutoTimeZoneDetection(boolean enabled) {
@@ -474,7 +471,7 @@
}
void initializeTimeZone(String zoneId) {
- mTimeZoneId = zoneId;
+ mTimeZoneId.init(zoneId);
}
void setAutoTimeZoneDetectionEnabled(boolean enabled) {
@@ -482,46 +479,17 @@
}
void assertTimeZoneNotSet() {
- mTimeZoneChanges.assertHasNotBeenSet();
+ mTimeZoneId.assertHasNotBeenSet();
}
- void assertTimeZoneSet(String timeZoneId, boolean withNetworkBroadcast) {
- mTimeZoneChanges.assertHasBeenSet();
- mTimeZoneChanges.assertChangeCount(1);
- TimeZoneChange expectedChange = new TimeZoneChange(timeZoneId, withNetworkBroadcast);
- mTimeZoneChanges.assertLatestEquals(expectedChange);
+ void assertTimeZoneSet(String timeZoneId) {
+ mTimeZoneId.assertHasBeenSet();
+ mTimeZoneId.assertChangeCount(1);
+ mTimeZoneId.assertLatestEquals(timeZoneId);
}
void commitAllChanges() {
- mTimeZoneChanges.commitLatest();
- }
- }
-
- private static class TimeZoneChange {
- private final String mTimeZoneId;
- private final boolean mWithNetworkBroadcast;
-
- private TimeZoneChange(String timeZoneId, boolean withNetworkBroadcast) {
- mTimeZoneId = timeZoneId;
- mWithNetworkBroadcast = withNetworkBroadcast;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TimeZoneChange that = (TimeZoneChange) o;
- return mWithNetworkBroadcast == that.mWithNetworkBroadcast
- && mTimeZoneId.equals(that.mTimeZoneId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mTimeZoneId, mWithNetworkBroadcast);
+ mTimeZoneId.commitLatest();
}
}
@@ -614,21 +582,13 @@
}
Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion suggestion) {
- // Phone suggestions should cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE
- // broadcast.
- boolean withNetworkBroadcast = true;
- mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(
- suggestion.getZoneId(), withNetworkBroadcast);
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
return this;
}
Script verifyTimeZoneSetAndReset(ManualTimeZoneSuggestion suggestion) {
- // Manual suggestions should not cause a TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE
- // broadcast.
- boolean withNetworkBroadcast = false;
- mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(
- suggestion.getZoneId(), withNetworkBroadcast);
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
return this;
}
diff --git a/services/usage/Android.bp b/services/usage/Android.bp
index 1064b6e..156bf33 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 20855b7..d2c973a 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 390406f..85b96f34 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 59a80fb..993d1e1 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.
+filegroup {
+ name: "services.startop.iorap-javasources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "services.startop.iorap-sources",
+ srcs: [
+ ":services.startop.iorap-javasources",
+ ":iorap-aidl",
+ ],
+ visibility: ["//frameworks/base/services:__subpackages__"],
+}
+
java_library_static {
name: "services.startop.iorap",
-
- aidl: {
- include_dirs: [
- "system/iorap/binder",
- ],
- },
-
+ srcs: [":services.startop.iorap-sources"],
libs: ["services.core"],
-
- srcs: [
- ":iorap-aidl",
- "**/*.java",
- ],
}
diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
new file mode 100644
index 0000000..922af12
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
@@ -0,0 +1,167 @@
+/*
+ * 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+
+import com.android.internal.os.BackgroundThread;
+
+/**
+ * Helper class for monitoring the state of packages: adding, removing,
+ * updating, and disappearing and reappearing on the SD card.
+ */
+public abstract class PackageChangeReceiver extends BroadcastReceiver {
+ static final IntentFilter sPackageIntentFilter = new IntentFilter();
+ static {
+ sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ sPackageIntentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ sPackageIntentFilter.addDataScheme("package");
+ }
+ Context mRegisteredContext;
+
+ /**
+ * To register the intents that needed for monitoring the state of packages
+ */
+ public void register(@NonNull Context context, @Nullable Looper thread,
+ @Nullable UserHandle user) {
+ if (mRegisteredContext != null) {
+ throw new IllegalStateException("Already registered");
+ }
+ Handler handler = (thread == null) ? BackgroundThread.getHandler() : new Handler(thread);
+ mRegisteredContext = context;
+ if (handler != null) {
+ if (user != null) {
+ context.registerReceiverAsUser(this, user, sPackageIntentFilter, null, handler);
+ } else {
+ context.registerReceiver(this, sPackageIntentFilter,
+ null, handler);
+ }
+ } else {
+ throw new NullPointerException();
+ }
+ }
+
+ /**
+ * To unregister the intents for monitoring the state of packages
+ */
+ public void unregister() {
+ if (mRegisteredContext == null) {
+ throw new IllegalStateException("Not registered");
+ }
+ mRegisteredContext.unregisterReceiver(this);
+ mRegisteredContext = null;
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED
+ */
+ public void onPackageAdded(@Nullable String packageName) {
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_PACKAGE_REMOVED
+ */
+ public void onPackageRemoved(@Nullable String packageName) {
+ }
+
+ /**
+ * This method is invoked when Intent.EXTRA_REPLACING as extra field is true
+ */
+ public void onPackageUpdateFinished(@Nullable String packageName) {
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_PACKAGE_CHANGED or
+ * Intent.EXTRA_REPLACING as extra field is true
+ */
+ public void onPackageModified(@Nullable String packageName) {
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_QUERY_PACKAGE_RESTART and
+ * Intent.ACTION_PACKAGE_RESTARTED
+ */
+ public void onHandleForceStop(@Nullable String[] packages, boolean doit) {
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_PACKAGE_REMOVED
+ */
+ public void onPackageDisappeared() {
+ }
+
+ /**
+ * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED
+ */
+ public void onPackageAppeared() {
+ }
+
+ @Override
+ public void onReceive(@Nullable Context context, @Nullable Intent intent) {
+ String action = intent.getAction();
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ String pkg = getPackageName(intent);
+ if (pkg != null) {
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ onPackageUpdateFinished(pkg);
+ onPackageModified(pkg);
+ } else {
+ onPackageAdded(pkg);
+ }
+ onPackageAppeared();
+ }
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ String pkg = getPackageName(intent);
+ if (pkg != null) {
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ onPackageRemoved(pkg);
+ }
+ onPackageDisappeared();
+ }
+ } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ String pkg = getPackageName(intent);
+ if (pkg != null) {
+ onPackageModified(pkg);
+ }
+ } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
+ String[] disappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ onHandleForceStop(disappearingPackages, false);
+ } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+ String[] disappearingPackages = new String[] {getPackageName(intent)};
+ onHandleForceStop(disappearingPackages, true);
+ }
+ }
+
+ String getPackageName(Intent intent) {
+ Uri uri = intent.getData();
+ String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+ return pkg;
+ }
+}
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 9da45da..7cf4eeb 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -39,11 +39,11 @@
import android.os.UserHandle;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
+import android.telephony.PackageChangeReceiver;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.util.Log;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -782,7 +782,7 @@
* Tracks package changes and ensures that the default SMS app is always configured to be the
* preferred activity for SENDTO sms/mms intents.
*/
- private static final class SmsPackageMonitor extends PackageMonitor {
+ private static final class SmsPackageMonitor extends PackageChangeReceiver {
final Context mContext;
public SmsPackageMonitor(Context context) {
@@ -791,12 +791,12 @@
}
@Override
- public void onPackageDisappeared(String packageName, int reason) {
+ public void onPackageDisappeared() {
onPackageChanged();
}
@Override
- public void onPackageAppeared(String packageName, int reason) {
+ public void onPackageAppeared() {
onPackageChanged();
}
@@ -829,7 +829,7 @@
public static void initSmsPackageMonitor(Context context) {
sSmsPackageMonitor = new SmsPackageMonitor(context);
- sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
+ sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL);
}
@UnsupportedAppUsage
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index f89bbc7..3940a3b 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -116,7 +116,8 @@
ApnSetting.TYPE_CBS,
ApnSetting.TYPE_IA,
ApnSetting.TYPE_EMERGENCY,
- ApnSetting.TYPE_MCX
+ ApnSetting.TYPE_MCX,
+ ApnSetting.TYPE_XCAP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {
@@ -463,9 +464,7 @@
DataFailCause.UNKNOWN,
DataFailCause.RADIO_NOT_AVAILABLE,
DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
- DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN,
DataFailCause.LOST_CONNECTION,
- DataFailCause.RESET_BY_FRAMEWORK
})
@Retention(RetentionPolicy.SOURCE)
public @interface DataFailureCause {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 92c6e93..c04105b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -100,6 +100,16 @@
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
@@ -2323,7 +2333,7 @@
* Reference: 3GPP TS 38.215
*
* 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
- * "NONE: [-23, threshold1]"
+ * "NONE: [-20, threshold1]"
* "POOR: (threshold1, threshold2]"
* "MODERATE: (threshold2, threshold3]"
* "GOOD: (threshold3, threshold4]"
@@ -2357,15 +2367,26 @@
/**
* Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
* SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
- * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
- * parameter whose value is smallest is used to indicate the signal bar.
+ * ratio (SSSINR) for the number of 5G NR signal bars and signal criteria reporting enabling.
+ *
+ * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
+ * not be used for calculating signal level. If multiple measures are set bit, the parameter
+ * whose value is smallest is used to indicate the signal level.
*
* SSRSRP = 1 << 0,
* SSRSRQ = 1 << 1,
* SSSINR = 1 << 2,
*
+ * The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP},
+ * {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}.
+ *
+ * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+ * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+ *
* Reference: 3GPP TS 38.215,
* 3GPP TS 38.133 10.1.16.1
+ *
+ * @hide
*/
public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT =
"parameters_use_for_5g_nr_signal_bar_int";
@@ -2978,7 +2999,6 @@
/**
* Location information during (and after) an emergency call is only provided over control
* plane signaling from the network.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_CP_ONLY = 0;
@@ -2986,7 +3006,6 @@
* Location information during (and after) an emergency call is provided over the data
* plane and serviced by the framework GNSS service, but if it fails, the carrier also
* supports control plane backup signaling.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK = 1;
@@ -2994,7 +3013,6 @@
* Location information during (and after) an emergency call is provided over the data plane
* and serviced by the framework GNSS service only. There is no backup signalling over the
* control plane if it fails.
- * @hide
*/
public static final int SUPL_EMERGENCY_MODE_TYPE_DP_ONLY = 2;
@@ -3102,11 +3120,21 @@
* {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
* <p>
* The default value for this configuration is {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}.
- * @hide
*/
public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = KEY_PREFIX
+ "es_supl_control_plane_support_int";
+ /**
+ * A list of roaming PLMNs where SUPL ES mode does not support a control-plane mechanism to
+ * get a user's location in the event that data plane SUPL fails or is otherwise
+ * unavailable.
+ * <p>
+ * A string array of PLMNs that do not support a control-plane mechanism for getting a
+ * user's location for SUPL ES.
+ */
+ public static final String KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY =
+ KEY_PREFIX + "es_supl_data_plane_only_roaming_plmn_string_array";
+
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
@@ -3123,6 +3151,7 @@
defaults.putString(KEY_NFW_PROXY_APPS_STRING, "");
defaults.putInt(KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
SUPL_EMERGENCY_MODE_TYPE_CP_ONLY);
+ defaults.putStringArray(KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, null);
return defaults;
}
}
@@ -3393,6 +3422,7 @@
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);
@@ -3692,6 +3722,32 @@
-95, /* SIGNAL_STRENGTH_GOOD */
-85 /* SIGNAL_STRENGTH_GREAT */
});
+ sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-140 dB, -44 dB]
+ new int[] {
+ -125, /* SIGNAL_STRENGTH_POOR */
+ -115, /* SIGNAL_STRENGTH_MODERATE */
+ -105, /* SIGNAL_STRENGTH_GOOD */
+ -95, /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-20 dB, -3 dB]
+ new int[] {
+ -14, /* SIGNAL_STRENGTH_POOR */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
+ -10, /* SIGNAL_STRENGTH_GOOD */
+ -8 /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
+ // Boundaries: [-23 dB, 40 dB]
+ new int[] {
+ -8, /* SIGNAL_STRENGTH_POOR */
+ 0, /* SIGNAL_STRENGTH_MODERATE */
+ 8, /* SIGNAL_STRENGTH_GOOD */
+ 16 /* SIGNAL_STRENGTH_GREAT */
+ });
+ sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+ CellSignalStrengthNr.USE_SSRSRP);
sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
@@ -3810,6 +3866,34 @@
@SystemApi
@TestApi
public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues) {
+ overrideConfig(subscriptionId, overrideValues, false);
+ }
+
+ /**
+ * Overrides the carrier config of the provided subscription ID with the provided values.
+ *
+ * Any further queries to carrier config from any process will return the overridden values
+ * after this method returns. The overrides are effective until the user passes in {@code null}
+ * for {@code overrideValues}. This removes all previous overrides and sets the carrier config
+ * back to production values.
+ *
+ * The overrides is stored persistently and will survive a reboot if {@code persistent} is true.
+ *
+ * May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid
+ * values for the specified config keys.
+ *
+ * NOTE: This API is meant for testing purposes only.
+ *
+ * @param subscriptionId The subscription ID for which the override should be done.
+ * @param overrideValues Key-value pairs of the values that are to be overridden. If set to
+ * {@code null}, this will remove all previous overrides and set the
+ * carrier configuration back to production values.
+ * @param persistent Determines whether the override should be persistent.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues,
+ boolean persistent) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
if (loader == null) {
@@ -3817,7 +3901,7 @@
+ " ICarrierConfigLoader is null");
return;
}
- loader.overrideConfig(subscriptionId, overrideValues);
+ loader.overrideConfig(subscriptionId, overrideValues, persistent);
} catch (RemoteException ex) {
Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": "
+ ex.toString());
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f9b7f6d..f31fafe 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,11 +16,15 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -36,13 +40,67 @@
private static final String TAG = "CellSignalStrengthNr";
+ // Lifted from Default carrier configs and max range of SSRSRP
+ // Boundaries: [-140 dB, -44 dB]
+ private int[] mSsRsrpThresholds = new int[] {
+ -125, /* SIGNAL_STRENGTH_POOR */
+ -115, /* SIGNAL_STRENGTH_MODERATE */
+ -105, /* SIGNAL_STRENGTH_GOOD */
+ -95, /* SIGNAL_STRENGTH_GREAT */
+ };
+
+ // Lifted from Default carrier configs and max range of SSRSRQ
+ // Boundaries: [-20 dB, -3 dB]
+ private int[] mSsRsrqThresholds = new int[] {
+ -14, /* SIGNAL_STRENGTH_POOR */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
+ -10, /* SIGNAL_STRENGTH_GOOD */
+ -8 /* SIGNAL_STRENGTH_GREAT */
+ };
+
+ // Lifted from Default carrier configs and max range of SSSINR
+ // Boundaries: [-23 dB, 40 dB]
+ private int[] mSsSinrThresholds = new int[] {
+ -8, /* SIGNAL_STRENGTH_POOR */
+ 0, /* SIGNAL_STRENGTH_MODERATE */
+ 8, /* SIGNAL_STRENGTH_GOOD */
+ 16 /* SIGNAL_STRENGTH_GREAT */
+ };
+
/**
- * These threshold values are copied from LTE.
- * TODO: make it configurable via CarrierConfig.
+ * Indicates SSRSRP is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
*/
- private static final int SIGNAL_GREAT_THRESHOLD = -95;
- private static final int SIGNAL_GOOD_THRESHOLD = -105;
- private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+ public static final int USE_SSRSRP = 1 << 0;
+ /**
+ * Indicates SSRSRQ is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
+ */
+ public static final int USE_SSRSRQ = 1 << 1;
+ /**
+ * Indicates SSSINR is considered for {@link #getLevel()} and reporting from modem.
+ *
+ * @hide
+ */
+ public static final int USE_SSSINR = 1 << 2;
+
+ /**
+ * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+ * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+ * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+ * parameter whose value is smallest is used to indicate the signal bar.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "USE_" }, value = {
+ USE_SSRSRP,
+ USE_SSRSRQ,
+ USE_SSSINR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SignalLevelAndReportCriteriaSource {}
private int mCsiRsrp;
private int mCsiRsrq;
@@ -52,6 +110,21 @@
private int mSsSinr;
private int mLevel;
+ /**
+ * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+ * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+ * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+ * parameter whose value is smallest is used to indicate the signal bar.
+ *
+ * SSRSRP = 1 << 0,
+ * SSRSRQ = 1 << 1,
+ * SSSINR = 1 << 2,
+ *
+ * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+ * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+ */
+ private int mParametersUseForLevel;
+
/** @hide */
public CellSignalStrengthNr() {
setDefaultValues();
@@ -182,6 +255,7 @@
mSsRsrq = CellInfo.UNAVAILABLE;
mSsSinr = CellInfo.UNAVAILABLE;
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ mParametersUseForLevel = USE_SSRSRP;
}
/** {@inheritDoc} */
@@ -191,20 +265,83 @@
return mLevel;
}
+ /**
+ * Checks if the given parameter type is considered to use for {@link #getLevel()}.
+ *
+ * Note: if multiple parameter types are considered, the smaller level for one of the
+ * parameters would be returned by {@link #getLevel()}
+ *
+ * @param parameterType bitwise OR of {@link #USE_SSRSRP}, {@link #USE_SSRSRQ},
+ * {@link #USE_SSSINR}
+ * @return {@code true} if the level is calculated based on the given parameter type;
+ * {@code false} otherwise.
+ *
+ */
+ private boolean isLevelForParameter(@SignalLevelAndReportCriteriaSource int parameterType) {
+ return (parameterType & mParametersUseForLevel) == parameterType;
+ }
+
/** @hide */
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
- if (mSsRsrp == CellInfo.UNAVAILABLE) {
- mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_GREAT;
- } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_GOOD;
- } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
- mLevel = SIGNAL_STRENGTH_MODERATE;
+ if (cc == null) {
+ mParametersUseForLevel = USE_SSRSRP;
} else {
- mLevel = SIGNAL_STRENGTH_POOR;
+ mParametersUseForLevel = cc.getInt(
+ CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, USE_SSRSRP);
+ Rlog.i(TAG, "Using SSRSRP for Level.");
+ mSsRsrpThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: " + Arrays.toString(mSsRsrpThresholds));
+ mSsRsrqThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: " + Arrays.toString(mSsRsrqThresholds));
+ mSsSinrThresholds = cc.getIntArray(
+ CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY);
+ Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: " + Arrays.toString(mSsSinrThresholds));
}
+ int ssRsrpLevel = SignalStrength.INVALID;
+ int ssRsrqLevel = SignalStrength.INVALID;
+ int ssSinrLevel = SignalStrength.INVALID;
+ if (isLevelForParameter(USE_SSRSRP)) {
+ ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
+ }
+ if (isLevelForParameter(USE_SSRSRQ)) {
+ ssRsrqLevel = updateLevelWithMeasure(mSsRsrq, mSsRsrqThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel);
+ }
+ if (isLevelForParameter(USE_SSSINR)) {
+ ssSinrLevel = updateLevelWithMeasure(mSsSinr, mSsSinrThresholds);
+ Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel);
+ }
+ // Apply the smaller value among three levels of three measures.
+ mLevel = Math.min(Math.min(ssRsrpLevel, ssRsrqLevel), ssSinrLevel);
+ }
+
+ /**
+ * Update level with corresponding measure and thresholds.
+ *
+ * @param measure corresponding signal measure
+ * @param thresholds corresponding signal thresholds
+ * @return level of the signal strength
+ */
+ private int updateLevelWithMeasure(int measure, int[] thresholds) {
+ int level;
+ if (measure == CellInfo.UNAVAILABLE) {
+ level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ } else if (measure > thresholds[3]) {
+ level = SIGNAL_STRENGTH_GREAT;
+ } else if (measure > thresholds[2]) {
+ level = SIGNAL_STRENGTH_GOOD;
+ } else if (measure > thresholds[1]) {
+ level = SIGNAL_STRENGTH_MODERATE;
+ } else if (measure > thresholds[0]) {
+ level = SIGNAL_STRENGTH_POOR;
+ } else {
+ level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ }
+ return level;
}
/**
@@ -247,6 +384,7 @@
mSsRsrq = s.mSsRsrq;
mSsSinr = s.mSsSinr;
mLevel = s.mLevel;
+ mParametersUseForLevel = s.mParametersUseForLevel;
}
/** @hide */
@@ -290,6 +428,7 @@
.append(" ssRsrq = " + mSsRsrq)
.append(" ssSinr = " + mSsSinr)
.append(" level = " + mLevel)
+ .append(" parametersUseForLevel = " + mParametersUseForLevel)
.append(" }")
.toString();
}
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 246bec7..e1c4bef 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;
@@ -953,14 +950,10 @@
public static final int UNKNOWN = 0x10000;
/** Data fail due to radio not unavailable. */
public static final int RADIO_NOT_AVAILABLE = 0x10001; /* no retry */
- /** @hide */
+ /** Data fail due to unacceptable network parameter. */
public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002; /* no retry */
- /** @hide */
- public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003;
/** Data connection was lost. */
public static final int LOST_CONNECTION = 0x10004;
- /** @hide */
- public static final int RESET_BY_FRAMEWORK = 0x10005;
/**
* Data handover failed.
@@ -1364,10 +1357,7 @@
sFailCauseMap.put(RADIO_NOT_AVAILABLE, "RADIO_NOT_AVAILABLE");
sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER,
"UNACCEPTABLE_NETWORK_PARAMETER");
- sFailCauseMap.put(CONNECTION_TO_DATACONNECTIONAC_BROKEN,
- "CONNECTION_TO_DATACONNECTIONAC_BROKEN");
sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION");
- sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK");
}
private DataFailCause() {
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index bbf746fc..fc717e7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -24,8 +24,8 @@
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 @@
* 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 1e601cf..9ace86c 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -102,7 +102,7 @@
* 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.
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
new file mode 100644
index 0000000..f6f6d75
--- /dev/null
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -0,0 +1,256 @@
+/*
+ * 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.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Defines the threshold value of the signal strength.
+ * @hide
+ */
+public class SignalThresholdInfo implements Parcelable {
+ /**
+ * Received Signal Strength Indication.
+ * Range: -113 dBm and -51 dBm
+ * Used RAN: GERAN, CDMA2000
+ * Reference: 3GPP TS 27.007 section 8.5.
+ */
+ public static final int SIGNAL_RSSI = 1;
+
+ /**
+ * Received Signal Code Power.
+ * Range: -120 dBm to -25 dBm;
+ * Used RAN: UTRAN
+ * Reference: 3GPP TS 25.123, section 9.1.1.1
+ */
+ public static final int SIGNAL_RSCP = 2;
+
+ /**
+ * Reference Signal Received Power.
+ * Range: -140 dBm to -44 dBm;
+ * Used RAN: EUTRAN
+ * Reference: 3GPP TS 36.133 9.1.4
+ */
+ public static final int SIGNAL_RSRP = 3;
+
+ /**
+ * Reference Signal Received Quality
+ * Range: -20 dB to -3 dB;
+ * Used RAN: EUTRAN
+ * Reference: 3GPP TS 36.133 9.1.7
+ */
+ public static final int SIGNAL_RSRQ = 4;
+
+ /**
+ * Reference Signal Signal to Noise Ratio
+ * Range: -20 dB to 30 dB;
+ * Used RAN: EUTRAN
+ */
+ public static final int SIGNAL_RSSNR = 5;
+
+ /**
+ * 5G SS reference signal received power.
+ * Range: -140 dBm to -44 dBm.
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215.
+ */
+ public static final int SIGNAL_SSRSRP = 6;
+
+ /**
+ * 5G SS reference signal received quality.
+ * Range: -20 dB to -3 dB.
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215.
+ */
+ public static final int SIGNAL_SSRSRQ = 7;
+
+ /**
+ * 5G SS signal-to-noise and interference ratio.
+ * Range: -23 dB to 40 dB
+ * Used RAN: NGRAN
+ * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+ */
+ public static final int SIGNAL_SSSINR = 8;
+
+ /** @hide */
+ @IntDef(prefix = { "SIGNAL_" }, value = {
+ SIGNAL_RSSI,
+ SIGNAL_RSCP,
+ SIGNAL_RSRP,
+ SIGNAL_RSRQ,
+ SIGNAL_RSSNR,
+ SIGNAL_SSRSRP,
+ SIGNAL_SSRSRQ,
+ SIGNAL_SSSINR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SignalMeasurementType {}
+
+ @SignalMeasurementType
+ private int mSignalMeasurement;
+
+ /**
+ * A hysteresis time in milliseconds to prevent flapping.
+ * A value of 0 disables hysteresis
+ */
+ private int mHysteresisMs;
+
+ /**
+ * An interval in dB defining the required magnitude change between reports.
+ * hysteresisDb must be smaller than the smallest threshold delta.
+ * An interval value of 0 disables hysteresis.
+ */
+ private int mHysteresisDb;
+
+ /**
+ * List of threshold values.
+ * Range and unit must reference specific SignalMeasurementType
+ * The threshold values for which to apply criteria.
+ * A vector size of 0 disables the use of thresholds for reporting.
+ */
+ private int[] mThresholds = null;
+
+ /**
+ * {@code true} means modem must trigger the report based on the criteria;
+ * {@code false} means modem must not trigger the report based on the criteria.
+ */
+ private boolean mIsEnabled = true;
+
+ /**
+ * Indicates the hysteresisMs is disabled.
+ */
+ public static final int HYSTERESIS_MS_DISABLED = 0;
+
+ /**
+ * Indicates the hysteresisDb is disabled.
+ */
+ public static final int HYSTERESIS_DB_DISABLED = 0;
+
+ /**
+ * Constructor
+ *
+ * @param signalMeasurement Signal Measurement Type
+ * @param hysteresisMs hysteresisMs
+ * @param hysteresisDb hysteresisDb
+ * @param thresholds threshold value
+ * @param isEnabled isEnabled
+ */
+ public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement,
+ int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) {
+ mSignalMeasurement = signalMeasurement;
+ mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs;
+ mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb;
+ mThresholds = thresholds == null ? null : thresholds.clone();
+ mIsEnabled = isEnabled;
+ }
+
+ public @SignalMeasurementType int getSignalMeasurement() {
+ return mSignalMeasurement;
+ }
+
+ public int getHysteresisMs() {
+ return mHysteresisMs;
+ }
+
+ public int getHysteresisDb() {
+ return mHysteresisDb;
+ }
+
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ public int[] getThresholds() {
+ return mThresholds == null ? null : mThresholds.clone();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSignalMeasurement);
+ out.writeInt(mHysteresisMs);
+ out.writeInt(mHysteresisDb);
+ out.writeIntArray(mThresholds);
+ out.writeBoolean(mIsEnabled);
+ }
+
+ private SignalThresholdInfo(Parcel in) {
+ mSignalMeasurement = in.readInt();
+ mHysteresisMs = in.readInt();
+ mHysteresisDb = in.readInt();
+ mThresholds = in.createIntArray();
+ mIsEnabled = in.readBoolean();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (!(o instanceof SignalThresholdInfo)) {
+ return false;
+ }
+
+ SignalThresholdInfo other = (SignalThresholdInfo) o;
+ return mSignalMeasurement == other.mSignalMeasurement
+ && mHysteresisMs == other.mHysteresisMs
+ && mHysteresisDb == other.mHysteresisDb
+ && Arrays.equals(mThresholds, other.mThresholds)
+ && mIsEnabled == other.mIsEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled);
+ }
+
+ public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
+ new Parcelable.Creator<SignalThresholdInfo>() {
+ @Override
+ public SignalThresholdInfo createFromParcel(Parcel in) {
+ return new SignalThresholdInfo(in);
+ }
+
+ @Override
+ public SignalThresholdInfo[] newArray(int size) {
+ return new SignalThresholdInfo[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new StringBuilder("SignalThresholdInfo{")
+ .append("mSignalMeasurement=").append(mSignalMeasurement)
+ .append("mHysteresisMs=").append(mSignalMeasurement)
+ .append("mHysteresisDb=").append(mHysteresisDb)
+ .append("mThresholds=").append(Arrays.toString(mThresholds))
+ .append("mIsEnabled=").append(mIsEnabled)
+ .append("}").toString();
+ }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f1abe04..4fb26fd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -703,31 +703,6 @@
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
/**
- * Broadcast intent action indicating that a precise call state
- * (cellular) on the device has changed.
- *
- * <p>
- * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state.
- * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state.
- * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state.
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- *
- * @see #EXTRA_RINGING_CALL_STATE
- * @see #EXTRA_FOREGROUND_CALL_STATE
- * @see #EXTRA_BACKGROUND_CALL_STATE
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- * @deprecated use {@link PhoneStateListener#LISTEN_PRECISE_CALL_STATE} instead
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PRECISE_CALL_STATE_CHANGED =
- "android.intent.action.PRECISE_CALL_STATE";
-
- /**
* Broadcast intent action indicating that call disconnect cause has changed.
*
* <p>
@@ -749,78 +724,6 @@
/**
* The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
* {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current ringing call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_RINGING_CALL_STATE = "ringing_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current foreground call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
- * containing the state of the current background call.
- *
- * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
- * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
- * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
- * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
- * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
- * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
- * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
- * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
- * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
- * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
* containing the disconnect cause.
*
* @see DisconnectCause
@@ -849,88 +752,6 @@
public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
/**
- * Broadcast intent action indicating a data connection has changed,
- * providing precise information about the connection.
- *
- * <p>
- * The {@link #EXTRA_DATA_STATE} extra indicates the connection state.
- * The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
- * The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
- * The {@link #EXTRA_DATA_APN} extra indicates the APN.
- * The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
- * The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
- *
- * <p class="note">
- * Requires the READ_PRECISE_PHONE_STATE permission.
- *
- * @see #EXTRA_DATA_STATE
- * @see #EXTRA_DATA_NETWORK_TYPE
- * @see #EXTRA_DATA_APN_TYPE
- * @see #EXTRA_DATA_APN
- * @see #EXTRA_DATA_IFACE
- * @see #EXTRA_DATA_FAILURE_CAUSE
- * @hide
- *
- * @deprecated If the app is running in the background, it won't be able to receive this
- * broadcast. Apps should use ConnectivityManager {@link #registerNetworkCallback(
- * android.net.NetworkRequest, ConnectivityManager.NetworkCallback)} to listen for network
- * changes.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @Deprecated
- @UnsupportedAppUsage
- public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
- "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an integer containing the state of the current data connection.
- *
- * @see TelephonyManager#DATA_UNKNOWN
- * @see TelephonyManager#DATA_DISCONNECTED
- * @see TelephonyManager#DATA_CONNECTING
- * @see TelephonyManager#DATA_CONNECTED
- * @see TelephonyManager#DATA_SUSPENDED
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_STATE = PhoneConstants.STATE_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an integer containing the network type.
- *
- * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
- * @see TelephonyManager#NETWORK_TYPE_GPRS
- * @see TelephonyManager#NETWORK_TYPE_EDGE
- * @see TelephonyManager#NETWORK_TYPE_UMTS
- * @see TelephonyManager#NETWORK_TYPE_CDMA
- * @see TelephonyManager#NETWORK_TYPE_EVDO_0
- * @see TelephonyManager#NETWORK_TYPE_EVDO_A
- * @see TelephonyManager#NETWORK_TYPE_1xRTT
- * @see TelephonyManager#NETWORK_TYPE_HSDPA
- * @see TelephonyManager#NETWORK_TYPE_HSUPA
- * @see TelephonyManager#NETWORK_TYPE_HSPA
- * @see TelephonyManager#NETWORK_TYPE_IDEN
- * @see TelephonyManager#NETWORK_TYPE_EVDO_B
- * @see TelephonyManager#NETWORK_TYPE_LTE
- * @see TelephonyManager#NETWORK_TYPE_EHRPD
- * @see TelephonyManager#NETWORK_TYPE_HSPAP
- * @see TelephonyManager#NETWORK_TYPE_NR
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_NETWORK_TYPE = PhoneConstants.DATA_NETWORK_TYPE_KEY;
-
- /**
* The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
* for an String containing the data APN type.
*
@@ -967,18 +788,6 @@
public static final String EXTRA_DATA_LINK_PROPERTIES_KEY = PhoneConstants.DATA_LINK_PROPERTIES_KEY;
/**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for the data connection fail cause.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
-
- /**
* Broadcast intent action for letting the default dialer to know to show voicemail
* notification.
*
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 60774e7..034fc22 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -20,7 +20,7 @@
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 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 @@
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 @@
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 @@
* {@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/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 47c4681..5adc99e 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -1173,18 +1173,8 @@
public void callSessionMergeComplete(IImsCallSession newSession) {
if (mListener != null) {
if (newSession != null) {
- // Check if the active session is the same session that was
- // active before the merge request was sent.
- ImsCallSession validActiveSession = ImsCallSession.this;
- try {
- if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
- // New session created after conference
- validActiveSession = new ImsCallSession(newSession);
- }
- } catch (RemoteException rex) {
- Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
- }
- mListener.callSessionMergeComplete(validActiveSession);
+ // New session created after conference
+ mListener.callSessionMergeComplete(new ImsCallSession(newSession));
} else {
// Session already exists. Hence no need to pass
mListener.callSessionMergeComplete(null);
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 76b214b..f4b2cef 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -889,6 +889,12 @@
*/
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 @@
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 d4ed923..0630454 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -31,7 +31,7 @@
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/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
index 8e50a8f..4e79660 100644
--- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
+++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
@@ -26,7 +26,7 @@
@UnsupportedAppUsage
PersistableBundle getConfigForSubId(int subId, String callingPackage);
- void overrideConfig(int subId, in PersistableBundle overrides);
+ void overrideConfig(int subId, in PersistableBundle overrides, boolean persistent);
void notifyConfigChangedForSubId(int subId);
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 6ff27b1..25f03c2 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -15,6 +15,7 @@
*/
package com.android.internal.telephony;
+import android.content.Intent;
import android.telephony.TelephonyManager;
import dalvik.annotation.compat.UnsupportedAppUsage;
@@ -25,37 +26,38 @@
public class IccCardConstants {
/* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */
- public static final String INTENT_KEY_ICC_STATE = "ss";
+ public static final String INTENT_KEY_ICC_STATE = Intent.EXTRA_SIM_STATE;
/* UNKNOWN means the ICC state is unknown */
- public static final String INTENT_VALUE_ICC_UNKNOWN = "UNKNOWN";
+ public static final String INTENT_VALUE_ICC_UNKNOWN = Intent.SIM_STATE_UNKNOWN;
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
- public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
+ public static final String INTENT_VALUE_ICC_NOT_READY = Intent.SIM_STATE_NOT_READY;
/* ABSENT means ICC is missing */
- public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
+ public static final String INTENT_VALUE_ICC_ABSENT = Intent.SIM_STATE_ABSENT;
/* PRESENT means ICC is present */
- public static final String INTENT_VALUE_ICC_PRESENT = "PRESENT";
+ public static final String INTENT_VALUE_ICC_PRESENT = Intent.SIM_STATE_PRESENT;
/* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
- static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
+ static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = Intent.SIM_STATE_CARD_IO_ERROR;
/* CARD_RESTRICTED means card is present but not usable due to carrier restrictions */
- static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = "CARD_RESTRICTED";
+ static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = Intent.SIM_STATE_CARD_RESTRICTED;
/* LOCKED means ICC is locked by pin or by network */
- public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
+ public static final String INTENT_VALUE_ICC_LOCKED = Intent.SIM_STATE_LOCKED;
/* READY means ICC is ready to access */
- public static final String INTENT_VALUE_ICC_READY = "READY";
+ public static final String INTENT_VALUE_ICC_READY = Intent.SIM_STATE_READY;
/* IMSI means ICC IMSI is ready in property */
- public static final String INTENT_VALUE_ICC_IMSI = "IMSI";
+ public static final String INTENT_VALUE_ICC_IMSI = Intent.SIM_STATE_IMSI;
/* LOADED means all ICC records, including IMSI, are loaded */
- public static final String INTENT_VALUE_ICC_LOADED = "LOADED";
+ public static final String INTENT_VALUE_ICC_LOADED = Intent.SIM_STATE_LOADED;
/* The extra data for broadcasting intent INTENT_ICC_STATE_CHANGE */
- public static final String INTENT_KEY_LOCKED_REASON = "reason";
+ public static final String INTENT_KEY_LOCKED_REASON = Intent.EXTRA_SIM_LOCKED_REASON;
/* PIN means ICC is locked on PIN1 */
- public static final String INTENT_VALUE_LOCKED_ON_PIN = "PIN";
+ public static final String INTENT_VALUE_LOCKED_ON_PIN = Intent.SIM_LOCKED_ON_PIN;
/* PUK means ICC is locked on PUK1 */
- public static final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
+ public static final String INTENT_VALUE_LOCKED_ON_PUK = Intent.SIM_LOCKED_ON_PUK;
/* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
- public static final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
+ public static final String INTENT_VALUE_LOCKED_NETWORK = Intent.SIM_LOCKED_NETWORK;
/* PERM_DISABLED means ICC is permanently disabled due to puk fails */
- public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+ public static final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED =
+ Intent.SIM_ABSENT_ON_PERM_DISABLED;
/**
* This is combination of IccCardStatus.CardState and IccCardApplicationStatus.AppState
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index e4397cd..6e63514 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -161,6 +161,8 @@
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 @@
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;
@@ -189,10 +192,6 @@
public static final String SLOT_KEY = "slot";
- /** Fired when a subscriptions phone state changes. */
- public static final String ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED =
- "android.intent.action.SUBSCRIPTION_PHONE_STATE";
-
// FIXME: This is used to pass a subId via intents, we need to look at its usage, which is
// FIXME: extensive, and see if this should be an array of all active subId's or ...?
/**
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 8b62872..b2c3fc7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -240,25 +240,6 @@
*/
public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME";
-
- /**
- * Broadcast Action: The timezone was set by the carrier (typically by the NITZ string).
- * This is a sticky broadcast.
- * The intent will have the following extra values:</p>
- * <ul>
- * <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time
- * zone.</li>
- * </ul>
- *
- * <p class="note">
- * Requires the READ_PHONE_STATE permission.
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
- */
- public static final String ACTION_NETWORK_SET_TIMEZONE
- = "android.intent.action.NETWORK_SET_TIMEZONE";
-
/**
* <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
* <p class="note">.
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 0000000..2905125
--- /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/test-mock/Android.bp b/test-mock/Android.bp
index aa4174a..616b6b0 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,6 +30,7 @@
libs: [
"framework-all",
"app-compat-annotations",
+ "unsupportedappusage",
],
api_packages: [